From d66debaf1b8f7ca9c59c4e367a93f0e07f8def0e Mon Sep 17 00:00:00 2001 From: Chris Nojima Date: Tue, 6 Jan 2026 09:31:33 -0500 Subject: [PATCH 01/20] move simple stores out of registry --- .gitignore | 1 + shared/common-adapters/avatar/store.tsx | 1 + shared/constants/archive/index.tsx | 3 +- shared/constants/chat2/convostate.tsx | 35 +++++----- shared/constants/chat2/index.tsx | 12 ++-- shared/constants/chat2/meta.tsx | 5 +- shared/constants/config/index.tsx | 25 +++++--- shared/constants/crypto/index.tsx | 7 +- shared/constants/current-user/index.tsx | 1 + shared/constants/daemon/index.tsx | 6 +- shared/constants/darkmode/index.tsx | 1 + shared/constants/followers/index.tsx | 1 + shared/constants/fs/index.tsx | 7 +- shared/constants/logout/index.tsx | 1 + shared/constants/notifications/index.tsx | 3 +- shared/constants/people/index.tsx | 3 +- shared/constants/pinentry/index.tsx | 1 + shared/constants/pinentry/util.tsx | 3 +- .../platform-specific/index.native.tsx | 8 ++- .../platform-specific/kbfs-notifications.tsx | 3 +- .../platform-specific/push.native.tsx | 3 +- shared/constants/profile/index.tsx | 15 +++-- shared/constants/provision/index.tsx | 7 +- shared/constants/push.native.tsx | 15 +++-- shared/constants/settings-contacts.native.tsx | 8 ++- shared/constants/settings-password/index.tsx | 3 +- shared/constants/settings/index.tsx | 8 ++- shared/constants/store-registry.tsx | 64 ------------------- shared/constants/teams/index.tsx | 7 +- shared/constants/tracker2/index.tsx | 5 +- shared/constants/waiting/index.tsx | 1 + shared/constants/whats-new/index.tsx | 1 + 32 files changed, 121 insertions(+), 143 deletions(-) diff --git a/.gitignore b/.gitignore index 1b909c12e951..c19c467dfabb 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,4 @@ go/keybase_freebsd go/keybase_netbsd go/keybase_openbsd +.cursor diff --git a/shared/common-adapters/avatar/store.tsx b/shared/common-adapters/avatar/store.tsx index da6964f9fc9a..c73d64efeff5 100644 --- a/shared/common-adapters/avatar/store.tsx +++ b/shared/common-adapters/avatar/store.tsx @@ -1,6 +1,7 @@ import type * as T from '@/constants/types' import * as Z from '@/util/zustand' +// This store has no dependencies on other stores and is safe to import directly from other stores. type Store = T.Immutable<{ counts: Map }> diff --git a/shared/constants/archive/index.tsx b/shared/constants/archive/index.tsx index 772f60224ffc..e9a894ee24c8 100644 --- a/shared/constants/archive/index.tsx +++ b/shared/constants/archive/index.tsx @@ -7,6 +7,7 @@ import {formatTimeForPopup} from '@/util/timestamp' import {uint8ArrayToHex} from 'uint8array-extras' import {storeRegistry} from '../store-registry' import {isMobile} from '../platform' +import {useCurrentUserState} from '../current-user' type ChatJob = { id: string @@ -448,7 +449,7 @@ export const useArchiveState = Z.createZustand((set, get) => { return { ...initialStore, chatIDToDisplayname: (conversationIDKey: string) => { - const you = storeRegistry.getState('current-user').username + const you = useCurrentUserState.getState().username const cs = storeRegistry.getConvoState(conversationIDKey) const m = cs.meta if (m.teamname) { diff --git a/shared/constants/chat2/convostate.tsx b/shared/constants/chat2/convostate.tsx index 8339874c3e6b..883633df60a8 100644 --- a/shared/constants/chat2/convostate.tsx +++ b/shared/constants/chat2/convostate.tsx @@ -47,6 +47,7 @@ import {enumKeys, ignorePromise, shallowEqual} from '../utils' import * as Strings from '@/constants/strings' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' const {darwinCopyToChatTempUploadFile} = KB2.functions @@ -648,7 +649,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const refreshMutualTeamsInConv = () => { const f = async () => { const {id: conversationIDKey} = get() - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username const otherParticipants = Meta.getRowParticipants(get().participants, username || '') const results = await T.RPCChat.localGetMutualTeamsLocalRpcPromise( {usernames: otherParticipants}, @@ -834,7 +835,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { } const onInboxFailed = (convID: Uint8Array, error: T.RPCChat.InboxUIItemError) => { - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username const conversationIDKey = T.Chat.conversationIDToKey(convID) switch (error.typ) { case T.RPCChat.ConversationErrorType.transient: @@ -1419,8 +1420,8 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { hit: T.RPCChat.MessageTypes['chat.1.chatUi.chatLoadGalleryHit']['inParam'] ) => { const getLastOrdinal = () => get().messageOrdinals?.at(-1) ?? T.Chat.numberToOrdinal(0) - const username = storeRegistry.getState('current-user').username - const devicename = storeRegistry.getState('current-user').deviceName + const username = useCurrentUserState.getState().username + const devicename = useCurrentUserState.getState().deviceName const m = Message.uiMessageToMessage( conversationIDKey, hit.message, @@ -1564,8 +1565,8 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { s.loaded = true }) - const username = storeRegistry.getState('current-user').username - const devicename = storeRegistry.getState('current-user').deviceName + const username = useCurrentUserState.getState().username + const devicename = useCurrentUserState.getState().deviceName const getLastOrdinal = () => get().messageOrdinals?.at(-1) ?? T.Chat.numberToOrdinal(0) const uiMessages = JSON.parse(thread) as T.RPCChat.UIMessages @@ -1703,8 +1704,8 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { }) if (result.message) { - const devicename = storeRegistry.getState('current-user').deviceName - const username = storeRegistry.getState('current-user').username + const devicename = useCurrentUserState.getState().deviceName + const username = useCurrentUserState.getState().username const getLastOrdinal = () => get().messageOrdinals?.at(-1) ?? T.Chat.numberToOrdinal(0) const goodMessage = Message.uiMessageToMessage( get().id, @@ -1956,7 +1957,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { logger.warn("messageReplyPrivately: can't find message to reply to", ordinal) return } - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username if (!username) { throw new Error('messageReplyPrivately: making a convo while logged out?') } @@ -2248,7 +2249,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { }, onIncomingMessage: incoming => { const {message: cMsg} = incoming - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username // check for a reaction outbox notification before doing anything if ( cMsg.state === T.RPCChat.MessageUnboxedState.outbox && @@ -2274,7 +2275,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { } const conversationIDKey = get().id - const devicename = storeRegistry.getState('current-user').deviceName + const devicename = useCurrentUserState.getState().deviceName const getLastOrdinal = () => get().messageOrdinals?.at(-1) ?? T.Chat.numberToOrdinal(0) // special case mutations @@ -2330,8 +2331,8 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { }, onMessagesUpdated: messagesUpdated => { if (!messagesUpdated.updates) return - const username = storeRegistry.getState('current-user').username - const devicename = storeRegistry.getState('current-user').deviceName + const username = useCurrentUserState.getState().username + const devicename = useCurrentUserState.getState().deviceName const getLastOrdinal = () => get().messageOrdinals?.at(-1) ?? T.Chat.numberToOrdinal(0) const toAdd = new Array() messagesUpdated.updates.forEach(uimsg => { @@ -2492,7 +2493,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const fetchConversationBio = () => { const participantInfo = get().participants - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username const otherParticipants = Meta.getRowParticipants(participantInfo, username || '') if (otherParticipants.length === 1) { // we're in a one-on-one convo @@ -2607,7 +2608,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { let ordinal = T.Chat.numberToOrdinal(0) // Editing last message if (e === 'last') { - const editLastUser = storeRegistry.getState('current-user').username + const editLastUser = useCurrentUserState.getState().username // Editing your last message const ordinals = get().messageOrdinals const found = @@ -2875,8 +2876,8 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const f = async () => { const conversationIDKey = get().id const getLastOrdinal = () => get().messageOrdinals?.at(-1) ?? T.Chat.numberToOrdinal(0) - const username = storeRegistry.getState('current-user').username - const devicename = storeRegistry.getState('current-user').deviceName + const username = useCurrentUserState.getState().username + const devicename = useCurrentUserState.getState().deviceName const onDone = () => { set(s => { s.threadSearchInfo.status = 'done' diff --git a/shared/constants/chat2/index.tsx b/shared/constants/chat2/index.tsx index 818915ca1b15..b0991b30975f 100644 --- a/shared/constants/chat2/index.tsx +++ b/shared/constants/chat2/index.tsx @@ -18,6 +18,8 @@ import isEqual from 'lodash/isEqual' import {bodyToJSON} from '../rpc-utils' import {navigateAppend, navUpToScreen, switchTab} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' +import {useWaitingState} from '../waiting' import * as S from '../strings' const defaultTopReacjis = [ @@ -406,7 +408,7 @@ export const useChatState = Z.createZustand((set, get) => { // only one pending conversation state. // The fix involves being able to make multiple pending conversations const f = async () => { - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username if (!username) { logger.error('Making a convo while logged out?') return @@ -524,7 +526,7 @@ export const useChatState = Z.createZustand((set, get) => { }, inboxRefresh: reason => { const f = async () => { - const {username} = storeRegistry.getState('current-user') + const {username} = useCurrentUserState.getState() const {loggedIn} = storeRegistry.getState('config') if (!loggedIn || !username) { return @@ -897,7 +899,7 @@ export const useChatState = Z.createZustand((set, get) => { }, messageSendByUsername: (username, text, waitingKey) => { const f = async () => { - const tlfName = `${storeRegistry.getState('current-user').username},${username}` + const tlfName = `${useCurrentUserState.getState().username},${username}` try { const result = await T.RPCChat.localNewConversationLocalRpcPromise( { @@ -953,7 +955,7 @@ export const useChatState = Z.createZustand((set, get) => { }, onChatInboxSynced: action => { const {syncRes} = action.payload.params - const {clear} = storeRegistry.getState('waiting').dispatch + const {clear} = useWaitingState.getState().dispatch const {inboxRefresh} = get().dispatch clear(S.waitingKeyChatInboxSyncStarted) @@ -1118,7 +1120,7 @@ export const useChatState = Z.createZustand((set, get) => { get().dispatch.onGetInboxUnverifiedConvs(action) break case EngineGen.chat1NotifyChatChatInboxSyncStarted: - storeRegistry.getState('waiting').dispatch.increment(S.waitingKeyChatInboxSyncStarted) + useWaitingState.getState().dispatch.increment(S.waitingKeyChatInboxSyncStarted) break case EngineGen.chat1NotifyChatChatInboxSynced: diff --git a/shared/constants/chat2/meta.tsx b/shared/constants/chat2/meta.tsx index 9adc5eda010f..243060f08637 100644 --- a/shared/constants/chat2/meta.tsx +++ b/shared/constants/chat2/meta.tsx @@ -5,6 +5,7 @@ import * as Teams from '../teams/util' import * as Message from './message' import {base64ToUint8Array, uint8ArrayToHex} from 'uint8array-extras' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' const conversationMemberStatusToMembershipType = (m: T.RPCChat.ConversationMemberStatus) => { switch (m) { @@ -263,8 +264,8 @@ export const inboxUIItemToConversationMeta = ( const conversationIDKey = T.Chat.stringToConversationIDKey(i.convID) let pinnedMsg: T.Chat.PinnedMessageInfo | undefined if (i.pinnedMsg) { - const username = storeRegistry.getState('current-user').username - const devicename = storeRegistry.getState('current-user').deviceName + const username = useCurrentUserState.getState().username + const devicename = useCurrentUserState.getState().deviceName const getLastOrdinal = () => storeRegistry.getConvoState(conversationIDKey).messageOrdinals?.at(-1) ?? T.Chat.numberToOrdinal(0) const message = Message.uiMessageToMessage( diff --git a/shared/constants/config/index.tsx b/shared/constants/config/index.tsx index 3786390fdaa8..2ca66cf343cc 100644 --- a/shared/constants/config/index.tsx +++ b/shared/constants/config/index.tsx @@ -16,6 +16,11 @@ import {type CommonResponseHandler} from '@/engine/types' import {invalidPasswordErrorString} from './util' import {navigateAppend, switchTab} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useAvatarState} from '@/common-adapters/avatar/store' +import {useCurrentUserState} from '../current-user' +import {useFollowerState} from '../followers' +import {usePinentryState} from '../pinentry' +import {useWhatsNewState} from '../whats-new' import {getSelectedConversation} from '@/constants/chat2/common' type Store = T.Immutable<{ @@ -278,7 +283,7 @@ export const useConfigState = Z.createZustand((set, get) => { }) const lastSeenItem = goodState.find(i => i.item.category === 'whatsNewLastSeenVersion') - storeRegistry.getState('whats-new').dispatch.updateLastSeen(lastSeenItem) + useWhatsNewState.getState().dispatch.updateLastSeen(lastSeenItem) } const updateApp = () => { @@ -397,11 +402,11 @@ export const useConfigState = Z.createZustand((set, get) => { break } case RemoteGen.pinentryOnCancel: { - storeRegistry.getState('pinentry').dispatch.dynamic.onCancel?.() + usePinentryState.getState().dispatch.dynamic.onCancel?.() break } case RemoteGen.pinentryOnSubmit: { - storeRegistry.getState('pinentry').dispatch.dynamic.onSubmit?.(action.payload.password) + usePinentryState.getState().dispatch.dynamic.onSubmit?.(action.payload.password) break } case RemoteGen.openPathInSystemFileManager: { @@ -595,7 +600,7 @@ export const useConfigState = Z.createZustand((set, get) => { if (phase === 'startupOrReloginButNotInARush') { const getFollowerInfo = () => { - const {uid} = storeRegistry.getState('current-user') + const {uid} = useCurrentUserState.getState() logger.info(`getFollowerInfo: init; uid=${uid}`) if (uid) { // request follower info in the background @@ -626,7 +631,7 @@ export const useConfigState = Z.createZustand((set, get) => { const updateChat = async () => { // On login lets load the untrusted inbox. This helps make some flows easier - if (storeRegistry.getState('current-user').username) { + if (useCurrentUserState.getState().username) { const {inboxRefresh} = storeRegistry.getState('chat').dispatch inboxRefresh('bootstrap') } @@ -800,17 +805,17 @@ export const useConfigState = Z.createZustand((set, get) => { } case EngineGen.keybase1NotifyTeamAvatarUpdated: { const {name} = action.payload.params - storeRegistry.getState('avatar').dispatch.updated(name) + useAvatarState.getState().dispatch.updated(name) break } case EngineGen.keybase1NotifyTrackingTrackingChanged: { const {isTracking, username} = action.payload.params - storeRegistry.getState('followers').dispatch.updateFollowing(username, isTracking) + useFollowerState.getState().dispatch.updateFollowing(username, isTracking) break } case EngineGen.keybase1NotifyTrackingTrackingInfo: { const {uid, followers: _newFollowers, followees: _newFollowing} = action.payload.params - if (storeRegistry.getState('current-user').uid !== uid) { + if (useCurrentUserState.getState().uid !== uid) { return } const newFollowers = new Set(_newFollowers) @@ -819,7 +824,7 @@ export const useConfigState = Z.createZustand((set, get) => { following: oldFollowing, followers: oldFollowers, dispatch, - } = storeRegistry.getState('followers') + } = useFollowerState.getState() const following = isEqual(newFollowing, oldFollowing) ? oldFollowing : newFollowing const followers = isEqual(newFollowers, oldFollowers) ? oldFollowers : newFollowers dispatch.replace(followers, following) @@ -910,7 +915,7 @@ export const useConfigState = Z.createZustand((set, get) => { })) }, revoke: name => { - const wasCurrentDevice = storeRegistry.getState('current-user').deviceName === name + const wasCurrentDevice = useCurrentUserState.getState().deviceName === name if (wasCurrentDevice) { const {configuredAccounts, defaultUsername} = get() const acc = configuredAccounts.find(n => n.username !== defaultUsername) diff --git a/shared/constants/crypto/index.tsx b/shared/constants/crypto/index.tsx index c4ee70dcfe73..dbf1f6c551bf 100644 --- a/shared/constants/crypto/index.tsx +++ b/shared/constants/crypto/index.tsx @@ -8,6 +8,7 @@ import * as T from '../types' import {RPCError} from '@/util/errors' import {navigateAppend} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' import {Operations} from './util' export * from './util' @@ -214,7 +215,7 @@ export const useCryptoState = Z.createZustand((set, get) => { const encrypt = (destinationDir: string = '') => { const f = async () => { const start = get().encrypt - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username const signed = start.options.sign const inputType = start.inputType const input = start.input.stringValue() @@ -349,7 +350,7 @@ export const useCryptoState = Z.createZustand((set, get) => { const output = await (inputType === 'text' ? callText() : callFile()) - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username set(s => { onSuccess(s.sign, s.sign.input.stringValue() === input, '', output, inputType, true, username, '') }) @@ -530,7 +531,7 @@ export const useCryptoState = Z.createZustand((set, get) => { // User set themselves as a recipient, so don't show 'includeSelf' option // However we don't want to set hideIncludeSelf if we are also encrypting to an SBS user (since we must force includeSelf) - const currentUser = storeRegistry.getState('current-user').username + const currentUser = useCurrentUserState.getState().username const {options} = get().encrypt if (usernames.includes(currentUser) && !hasSBS) { get().dispatch.setEncryptOptions(options, true) diff --git a/shared/constants/current-user/index.tsx b/shared/constants/current-user/index.tsx index 8219dbc286f9..76b8a2caa8be 100644 --- a/shared/constants/current-user/index.tsx +++ b/shared/constants/current-user/index.tsx @@ -1,6 +1,7 @@ import type * as T from '../types' import * as Z from '@/util/zustand' +// This store has no dependencies on other stores and is safe to import directly from other stores. type Store = T.Immutable<{ deviceID: T.RPCGen.DeviceID deviceName: string diff --git a/shared/constants/daemon/index.tsx b/shared/constants/daemon/index.tsx index 15d3f95b7f9c..b08dff8bedc6 100644 --- a/shared/constants/daemon/index.tsx +++ b/shared/constants/daemon/index.tsx @@ -3,6 +3,8 @@ import {ignorePromise} from '../utils' import * as T from '../types' import * as Z from '@/util/zustand' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' +import {useDarkModeState} from '../darkmode' import {maxHandshakeTries} from '../values' // Load accounts, this call can be slow so we attempt to continue w/o waiting if we determine we're logged in @@ -109,7 +111,7 @@ export const useDaemonState = Z.createZustand((set, get) => { wait(name, version, true) try { await get().dispatch.loadDaemonBootstrapStatus() - storeRegistry.getState('dark-mode').dispatch.loadDarkPrefs() + useDarkModeState.getState().dispatch.loadDarkPrefs() storeRegistry.getState('chat').dispatch.loadStaticConfig() } finally { wait(name, version, false) @@ -170,7 +172,7 @@ export const useDaemonState = Z.createZustand((set, get) => { const {wait} = get().dispatch const f = async () => { - const {setBootstrap} = storeRegistry.getState('current-user').dispatch + const {setBootstrap} = useCurrentUserState.getState().dispatch const {setDefaultUsername} = storeRegistry.getState('config').dispatch const s = await T.RPCGen.configGetBootstrapStatusRpcPromise() const {userReacjis, deviceName, deviceID, uid, loggedIn, username} = s diff --git a/shared/constants/darkmode/index.tsx b/shared/constants/darkmode/index.tsx index f5e240e3a4d3..fa4d7a445ed1 100644 --- a/shared/constants/darkmode/index.tsx +++ b/shared/constants/darkmode/index.tsx @@ -5,6 +5,7 @@ import {isMobile} from '../platform' export type DarkModePreference = 'system' | 'alwaysDark' | 'alwaysLight' +// This store has no dependencies on other stores and is safe to import directly from other stores. type Store = T.Immutable<{ darkModePreference: DarkModePreference systemDarkMode: boolean diff --git a/shared/constants/followers/index.tsx b/shared/constants/followers/index.tsx index f7f550f23102..f276f03786e9 100644 --- a/shared/constants/followers/index.tsx +++ b/shared/constants/followers/index.tsx @@ -1,6 +1,7 @@ import * as T from '@/constants/types' import * as Z from '@/util/zustand' +// This store has no dependencies on other stores and is safe to import directly from other stores. type Store = T.Immutable<{ followers: Set following: Set diff --git a/shared/constants/fs/index.tsx b/shared/constants/fs/index.tsx index b5f112cfcbe5..16e08313c52b 100644 --- a/shared/constants/fs/index.tsx +++ b/shared/constants/fs/index.tsx @@ -15,6 +15,7 @@ import isEqual from 'lodash/isEqual' import {settingsFsTab} from '../settings/util' import {navigateAppend, navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' export {makeActionForOpenPathInFilesTab} from './util' @@ -565,7 +566,7 @@ export const resetBannerType = (s: State, path: T.FS.Path): T.FS.ResetBannerType return T.FS.ResetBannerNoOthersType.None } - const you = storeRegistry.getState('current-user').username + const you = useCurrentUserState.getState().username if (resetParticipants.findIndex(username => username === you) >= 0) { return T.FS.ResetBannerNoOthersType.Self } @@ -1606,7 +1607,7 @@ export const useFSState = Z.createZustand((set, get) => { const tlfType = rpcFolderTypeToTlfType(folder.folderType) const tlfName = tlfType === T.FS.TlfType.Private || tlfType === T.FS.TlfType.Public - ? tlfToPreferredOrder(folder.name, storeRegistry.getState('current-user').username) + ? tlfToPreferredOrder(folder.name, useCurrentUserState.getState().username) : folder.name tlfType && payload[tlfType].set( @@ -1903,7 +1904,7 @@ export const useFSState = Z.createZustand((set, get) => { const tlfType = rpcFolderTypeToTlfType(folder.folderType) const tlfName = tlfType === T.FS.TlfType.Private || tlfType === T.FS.TlfType.Public - ? tlfToPreferredOrder(folder.name, storeRegistry.getState('current-user').username) + ? tlfToPreferredOrder(folder.name, useCurrentUserState.getState().username) : folder.name if (tlfType) { diff --git a/shared/constants/logout/index.tsx b/shared/constants/logout/index.tsx index c1e85a767cad..82a3c99c749f 100644 --- a/shared/constants/logout/index.tsx +++ b/shared/constants/logout/index.tsx @@ -8,6 +8,7 @@ import {navigateAppend} from '../router2/util' import {isMobile} from '../platform' import * as Tabs from '../tabs' +// This store has no dependencies on other stores and is safe to import directly from other stores. type Store = T.Immutable<{ waiters: Map // if we ever restart handshake up this so we can ignore any waiters for old things diff --git a/shared/constants/notifications/index.tsx b/shared/constants/notifications/index.tsx index 6d9881b80fa1..c619e197f9c4 100644 --- a/shared/constants/notifications/index.tsx +++ b/shared/constants/notifications/index.tsx @@ -5,6 +5,7 @@ import {isMobile} from '../platform' import isEqual from 'lodash/isEqual' import * as Tabs from '../tabs' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' export type BadgeType = 'regular' | 'update' | 'error' | 'uploading' export type NotificationKeys = 'kbfsUploading' | 'outOfSpace' @@ -67,7 +68,7 @@ const badgeStateToBadgeCounts = (bs: T.RPCGen.BadgeState) => { revokedDevices.forEach(d => allDeviceChanges.add(d)) // don't see badges related to this device - const deviceID = storeRegistry.getState('current-user').deviceID + const deviceID = useCurrentUserState.getState().deviceID counts.set(Tabs.devicesTab, allDeviceChanges.size - (allDeviceChanges.has(deviceID) ? 1 : 0)) counts.set(Tabs.chatTab, bs.smallTeamBadgeCount + bs.bigTeamBadgeCount) counts.set(Tabs.gitTab, newGitRepoGlobalUniqueIDs.length) diff --git a/shared/constants/people/index.tsx b/shared/constants/people/index.tsx index 10cfde7db8af..ec922f5dea71 100644 --- a/shared/constants/people/index.tsx +++ b/shared/constants/people/index.tsx @@ -10,6 +10,7 @@ import {isMobile} from '../platform' import type {e164ToDisplay as e164ToDisplayType} from '@/util/phone-numbers' import debounce from 'lodash/debounce' import {storeRegistry} from '../store-registry' +import {useFollowerState} from '../followers' import {RPCError, isNetworkErr} from '../utils' // set this to true to have all todo items + a contact joined notification show up all the time @@ -398,7 +399,7 @@ export const usePeopleState = Z.createZustand((set, get) => { {markViewed, numFollowSuggestionsWanted}, getPeopleDataWaitingKey ) - const {following, followers} = storeRegistry.getState('followers') + const {following, followers} = useFollowerState.getState() const oldItems: Array = (data.items ?? []) .filter(item => !item.badged && item.data.t !== T.RPCGen.HomeScreenItemType.todo) .reduce(reduceRPCItemToPeopleItem, []) diff --git a/shared/constants/pinentry/index.tsx b/shared/constants/pinentry/index.tsx index 1dae7f694344..45caef2e55d3 100644 --- a/shared/constants/pinentry/index.tsx +++ b/shared/constants/pinentry/index.tsx @@ -5,6 +5,7 @@ import logger from '@/logger' import {invalidPasswordErrorString} from '@/constants/config/util' import {wrapErrors} from '../utils' +// This store has no dependencies on other stores and is safe to import directly from other stores. export type Store = T.Immutable<{ cancelLabel?: string prompt: string diff --git a/shared/constants/pinentry/util.tsx b/shared/constants/pinentry/util.tsx index 5ec547f0d1cf..6bc86e3001f6 100644 --- a/shared/constants/pinentry/util.tsx +++ b/shared/constants/pinentry/util.tsx @@ -2,6 +2,7 @@ import * as T from '../types' import {ignorePromise} from '../utils' import * as EngineGen from '@/actions/engine-gen-gen' import {storeRegistry} from '../store-registry' +import {usePinentryState} from '../pinentry' import logger from '@/logger' export const onEngineConnected = () => { @@ -20,7 +21,7 @@ export const onEngineIncoming = (action: EngineGen.Actions) => { switch (action.type) { case EngineGen.keybase1SecretUiGetPassphrase: { - storeRegistry.getState('pinentry').dispatch.onEngineIncomingImpl(action) + usePinentryState.getState().dispatch.onEngineIncomingImpl(action) } break default: diff --git a/shared/constants/platform-specific/index.native.tsx b/shared/constants/platform-specific/index.native.tsx index 844634a4e82f..595195b7fe7f 100644 --- a/shared/constants/platform-specific/index.native.tsx +++ b/shared/constants/platform-specific/index.native.tsx @@ -1,5 +1,7 @@ import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from '../utils' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' +import {useDarkModeState} from '../darkmode' import * as T from '../types' import * as Clipboard from 'expo-clipboard' import * as EngineGen from '@/actions/engine-gen-gen' @@ -526,9 +528,9 @@ export const initPlatformListener = () => { // Location if (isAndroid) { - storeRegistry.getStore('dark-mode').subscribe((s, old) => { + useDarkModeState.subscribe((s, old) => { if (s.darkModePreference === old.darkModePreference) return - const {darkModePreference} = storeRegistry.getState('dark-mode') + const {darkModePreference} = useDarkModeState.getState() androidAppColorSchemeChanged(darkModePreference) }) } @@ -622,7 +624,7 @@ export const initPlatformListener = () => { s.dispatch.dynamic.tabLongPress = wrapErrors((tab: string) => { if (tab !== Tabs.peopleTab) return const accountRows = storeRegistry.getState('config').configuredAccounts - const current = storeRegistry.getState('current-user').username + const current = useCurrentUserState.getState().username const row = accountRows.find(a => a.username !== current && a.hasStoredSecret) if (row) { storeRegistry.getState('config').dispatch.setUserSwitching(true) diff --git a/shared/constants/platform-specific/kbfs-notifications.tsx b/shared/constants/platform-specific/kbfs-notifications.tsx index f06fd2b4c629..f23791bd2d4e 100644 --- a/shared/constants/platform-specific/kbfs-notifications.tsx +++ b/shared/constants/platform-specific/kbfs-notifications.tsx @@ -1,5 +1,6 @@ import {pathSep} from '@/constants/platform' import {storeRegistry} from '@/constants/store-registry' +import {useCurrentUserState} from '@/constants/current-user' import capitalize from 'lodash/capitalize' import * as T from '@/constants/types' import {parseFolderNameToUsers} from '@/util/kbfs' @@ -200,7 +201,7 @@ export function kbfsNotification( let title = `KBFS: ${action}` let body = `Chat or files with ${usernames} ${notification.status}` - const user = storeRegistry.getState('current-user').username + const user = useCurrentUserState.getState().username let rateLimitKey: string const isError = notification.statusCode === T.RPCGen.FSStatusCode.error diff --git a/shared/constants/platform-specific/push.native.tsx b/shared/constants/platform-specific/push.native.tsx index 3f2114a603bc..87936d03820d 100644 --- a/shared/constants/platform-specific/push.native.tsx +++ b/shared/constants/platform-specific/push.native.tsx @@ -10,6 +10,7 @@ import { removeAllPendingNotificationRequests, } from 'react-native-kb' import {storeRegistry} from '../store-registry' +import {useLogoutState} from '../logout' type DataCommon = { userInteraction: boolean @@ -177,7 +178,7 @@ export const initPushListener = () => { }) // Token handling - storeRegistry.getStore('logout').subscribe((s, old) => { + useLogoutState.subscribe((s, old) => { if (s.version === old.version) return storeRegistry.getState('push').dispatch.deleteToken(s.version) }) diff --git a/shared/constants/profile/index.tsx b/shared/constants/profile/index.tsx index 0d01f9582e9c..5e8eaa1d4cf1 100644 --- a/shared/constants/profile/index.tsx +++ b/shared/constants/profile/index.tsx @@ -9,6 +9,7 @@ import {RPCError} from '@/util/errors' import {fixCrop} from '@/util/crop' import {clearModals, navigateAppend, navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' import {navToProfile} from '../router2' type ProveGenericParams = { @@ -266,7 +267,7 @@ export const useProfileState = Z.createZustand((set, get) => { const loadAfter = () => storeRegistry.getState('tracker2').dispatch.load({ - assertion: storeRegistry.getState('current-user').username, + assertion: useCurrentUserState.getState().username, guiID: generateGUIID(), inTracker: false, reason: '', @@ -435,7 +436,7 @@ export const useProfileState = Z.createZustand((set, get) => { backToProfile: () => { clearModals() setTimeout(() => { - get().dispatch.showUserProfile(storeRegistry.getState('current-user').username) + get().dispatch.showUserProfile(useCurrentUserState.getState().username) }, 100) }, checkProof: () => { @@ -494,15 +495,15 @@ export const useProfileState = Z.createZustand((set, get) => { editProfile: (bio, fullName, location) => { const f = async () => { await T.RPCGen.userProfileEditRpcPromise({bio, fullName, location}, S.waitingKeyTracker) - get().dispatch.showUserProfile(storeRegistry.getState('current-user').username) + get().dispatch.showUserProfile(useCurrentUserState.getState().username) } ignorePromise(f()) }, finishRevoking: () => { - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username get().dispatch.showUserProfile(username) storeRegistry.getState('tracker2').dispatch.load({ - assertion: storeRegistry.getState('current-user').username, + assertion: useCurrentUserState.getState().username, guiID: generateGUIID(), inTracker: false, reason: '', @@ -599,7 +600,7 @@ export const useProfileState = Z.createZustand((set, get) => { await T.RPCGen.proveCheckProofRpcPromise({sigID}, S.waitingKeyProfile) storeRegistry .getState('tracker2') - .dispatch.showUser(storeRegistry.getState('current-user').username, false) + .dispatch.showUser(useCurrentUserState.getState().username, false) } ignorePromise(f()) }, @@ -649,7 +650,7 @@ export const useProfileState = Z.createZustand((set, get) => { const f = async () => { const you = storeRegistry .getState('tracker2') - .getDetails(storeRegistry.getState('current-user').username) + .getDetails(useCurrentUserState.getState().username) if (!you.assertions) return const proof = [...you.assertions.values()].find(a => a.sigID === proofId) if (!proof) return diff --git a/shared/constants/provision/index.tsx b/shared/constants/provision/index.tsx index c49fcbf3c1d7..f5d82672bde0 100644 --- a/shared/constants/provision/index.tsx +++ b/shared/constants/provision/index.tsx @@ -10,6 +10,7 @@ import {rpcDeviceToDevice} from '../rpc-utils' import {invalidPasswordErrorString} from '@/constants/config/util' import {clearModals, navigateAppend} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useWaitingState} from '../waiting' export type Device = { deviceNumberOfType: number @@ -122,7 +123,7 @@ export interface State extends Store { export const useProvisionState = Z.createZustand((set, get) => { const _cancel = C.wrapErrors((ignoreWarning?: boolean) => { - storeRegistry.getState('waiting').dispatch.clear(C.waitingKeyProvision) + useWaitingState.getState().dispatch.clear(C.waitingKeyProvision) if (!ignoreWarning) { console.log('Provision: cancel called while not overloaded') } @@ -259,7 +260,7 @@ export const useProvisionState = Z.createZustand((set, get) => { }, incomingCallMap: { 'keybase.1.provisionUi.DisplaySecretExchanged': () => { - storeRegistry.getState('waiting').dispatch.increment(C.waitingKeyProvision) + useWaitingState.getState().dispatch.increment(C.waitingKeyProvision) }, 'keybase.1.provisionUi.ProvisioneeSuccess': () => {}, 'keybase.1.provisionUi.ProvisionerSuccess': () => {}, @@ -502,7 +503,7 @@ export const useProvisionState = Z.createZustand((set, get) => { incomingCallMap: { 'keybase.1.loginUi.displayPrimaryPaperKey': () => {}, 'keybase.1.provisionUi.DisplaySecretExchanged': () => { - storeRegistry.getState('waiting').dispatch.increment(C.waitingKeyProvision) + useWaitingState.getState().dispatch.increment(C.waitingKeyProvision) }, 'keybase.1.provisionUi.ProvisioneeSuccess': () => {}, 'keybase.1.provisionUi.ProvisionerSuccess': () => {}, diff --git a/shared/constants/push.native.tsx b/shared/constants/push.native.tsx index ce2f85b70b0b..59272b34c86c 100644 --- a/shared/constants/push.native.tsx +++ b/shared/constants/push.native.tsx @@ -3,6 +3,9 @@ import * as S from './strings' import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from './utils' import {navigateAppend, navUpToScreen, switchTab} from './router2/util' import {storeRegistry} from './store-registry' +import {useCurrentUserState} from './current-user' +import {useLogoutState} from './logout' +import {useWaitingState} from './waiting' import * as Z from '@/util/zustand' import logger from '@/logger' import * as T from './types' @@ -109,9 +112,9 @@ export const usePushState = Z.createZustand((set, get) => { deleteToken: version => { const f = async () => { const waitKey = 'push:deleteToken' - storeRegistry.getState('logout').dispatch.wait(waitKey, version, true) + useLogoutState.getState().dispatch.wait(waitKey, version, true) try { - const deviceID = storeRegistry.getState('current-user').deviceID + const deviceID = useCurrentUserState.getState().deviceID if (!deviceID) { logger.info('[PushToken] no device id') return @@ -127,7 +130,7 @@ export const usePushState = Z.createZustand((set, get) => { } catch (e) { logger.error('[PushToken] delete failed', e) } finally { - storeRegistry.getState('logout').dispatch.wait(waitKey, version, false) + useLogoutState.getState().dispatch.wait(waitKey, version, false) } } ignorePromise(f()) @@ -226,7 +229,7 @@ export const usePushState = Z.createZustand((set, get) => { } try { storeRegistry.getState('config').dispatch.dynamic.openAppSettings?.() - const {increment} = storeRegistry.getState('waiting').dispatch + const {increment} = useWaitingState.getState().dispatch increment(S.waitingKeyPushPermissionsRequesting) await requestPermissionsFromNative() const permissions = await checkPermissionsFromNative() @@ -242,7 +245,7 @@ export const usePushState = Z.createZustand((set, get) => { }) } } finally { - const {decrement} = storeRegistry.getState('waiting').dispatch + const {decrement} = useWaitingState.getState().dispatch decrement(S.waitingKeyPushPermissionsRequesting) get().dispatch.showPermissionsPrompt({persistSkip: true, show: false}) } @@ -256,7 +259,7 @@ export const usePushState = Z.createZustand((set, get) => { }) const uploadPushToken = async () => { - const {deviceID, username} = storeRegistry.getState('current-user') + const {deviceID, username} = useCurrentUserState.getState() if (!username || !deviceID) { return } diff --git a/shared/constants/settings-contacts.native.tsx b/shared/constants/settings-contacts.native.tsx index 3d0f7da0407e..2471a0051cbb 100644 --- a/shared/constants/settings-contacts.native.tsx +++ b/shared/constants/settings-contacts.native.tsx @@ -12,6 +12,8 @@ import {getE164} from './settings-phone' import {pluralize} from '@/util/string' import {navigateAppend} from './router2/util' import {storeRegistry} from './store-registry' +import {useCurrentUserState} from './current-user' +import {useWaitingState} from './waiting' const importContactsConfigKey = (username: string) => `ui.importContacts.${username}` @@ -80,7 +82,7 @@ export const useSettingsContactsState = Z.createZustand((set, get) => { }) } const f = async () => { - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username if (!username) { logger.warn('no username') return @@ -103,7 +105,7 @@ export const useSettingsContactsState = Z.createZustand((set, get) => { if (!storeRegistry.getState('config').loggedIn) { return } - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username if (!username) { logger.warn('no username') return @@ -241,7 +243,7 @@ export const useSettingsContactsState = Z.createZustand((set, get) => { }, requestPermissions: (thenToggleImportOn?: boolean, fromSettings?: boolean) => { const f = async () => { - const {decrement, increment} = storeRegistry.getState('waiting').dispatch + const {decrement, increment} = useWaitingState.getState().dispatch increment(C.importContactsWaitingKey) const status = (await Contacts.requestPermissionsAsync()).status diff --git a/shared/constants/settings-password/index.tsx b/shared/constants/settings-password/index.tsx index ac305c0f6159..6f1c95cb7a7d 100644 --- a/shared/constants/settings-password/index.tsx +++ b/shared/constants/settings-password/index.tsx @@ -6,6 +6,7 @@ import {RPCError} from '@/util/errors' import * as T from '../types' import {navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useLogoutState} from '../logout' type Store = T.Immutable<{ error: string @@ -141,7 +142,7 @@ export const usePWState = Z.createZustand((set, get) => { ) if (thenLogout) { - storeRegistry.getState('logout').dispatch.requestLogout() + useLogoutState.getState().dispatch.requestLogout() } navigateUp() } catch (error) { diff --git a/shared/constants/settings/index.tsx b/shared/constants/settings/index.tsx index 7680d636aa63..8832c7ff5792 100644 --- a/shared/constants/settings/index.tsx +++ b/shared/constants/settings/index.tsx @@ -10,6 +10,8 @@ import * as Tabs from '../tabs' import logger from '@/logger' import {clearModals, navigateAppend, switchTab} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' +import {useWaitingState} from '../waiting' import {processorProfileInProgressKey, traceInProgressKey} from './util' export * from './util' @@ -89,7 +91,7 @@ export const useSettingsState = Z.createZustand(set => { }, deleteAccountForever: passphrase => { const f = async () => { - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username if (!username) { throw new Error('Unable to delete account: no username set') @@ -204,7 +206,7 @@ export const useSettingsState = Z.createZustand(set => { logDirForMobile: pprofDir, profileDurationSeconds, }) - const {decrement, increment} = storeRegistry.getState('waiting').dispatch + const {decrement, increment} = useWaitingState.getState().dispatch increment(processorProfileInProgressKey) await timeoutPromise(profileDurationSeconds * 1_000) decrement(processorProfileInProgressKey) @@ -262,7 +264,7 @@ export const useSettingsState = Z.createZustand(set => { logDirForMobile: pprofDir, traceDurationSeconds: durationSeconds, }) - const {decrement, increment} = storeRegistry.getState('waiting').dispatch + const {decrement, increment} = useWaitingState.getState().dispatch increment(traceInProgressKey) await timeoutPromise(durationSeconds * 1_000) decrement(traceInProgressKey) diff --git a/shared/constants/store-registry.tsx b/shared/constants/store-registry.tsx index f62f57f25e1f..354d01a3fa1b 100644 --- a/shared/constants/store-registry.tsx +++ b/shared/constants/store-registry.tsx @@ -7,24 +7,18 @@ import type {ConvoState} from './chat2/convostate' import type {State as ActiveState, useActiveState} from './active' import type {State as ArchiveState, useArchiveState} from './archive' import type {State as AutoResetState, useAutoResetState} from './autoreset' -import type {State as AvatarState, useAvatarState} from '@/common-adapters/avatar/store' import type {State as BotsState, useBotsState} from './bots' import type {State as ChatState, useChatState} from './chat2' import type {State as ConfigState, useConfigState} from './config' import type {State as CryptoState, useCryptoState} from './crypto' -import type {State as CurrentUserState, useCurrentUserState} from './current-user' import type {State as DaemonState, useDaemonState} from './daemon' -import type {State as DarkModeState, useDarkModeState} from './darkmode' import type {State as DeepLinksState, useDeepLinksState} from './deeplinks' import type {State as DevicesState, useDevicesState} from './devices' import type {State as EngineState, useEngineState} from './engine' -import type {State as FollowersState, useFollowerState} from './followers' import type {State as FSState, useFSState} from './fs' import type {State as GitState, useGitState} from './git' -import type {State as LogoutState, useLogoutState} from './logout' import type {State as NotificationsState, useNotifState} from './notifications' import type {State as PeopleState, usePeopleState} from './people' -import type {State as PinentryState, usePinentryState} from './pinentry' import type {State as ProfileState, useProfileState} from './profile' import type {State as ProvisionState, useProvisionState} from './provision' import type {State as PushState, usePushState} from './push' @@ -41,31 +35,23 @@ import type {State as TeamsState, useTeamsState} from './teams' import type {State as Tracker2State, useTrackerState} from './tracker2' import type {State as UnlockFoldersState, useUnlockFoldersState} from './unlock-folders' import type {State as UsersState, useUsersState} from './users' -import type {State as WaitingState, useWaitingState} from './waiting' -import type {State as WhatsNewState, useWhatsNewState} from './whats-new' type StoreName = | 'active' | 'archive' | 'autoreset' - | 'avatar' | 'bots' | 'chat' | 'config' | 'crypto' - | 'current-user' | 'daemon' - | 'dark-mode' | 'deeplinks' | 'devices' | 'engine' - | 'followers' | 'fs' | 'git' - | 'logout' | 'notifications' | 'people' - | 'pinentry' | 'profile' | 'provision' | 'push' @@ -82,31 +68,23 @@ type StoreName = | 'tracker2' | 'unlock-folders' | 'users' - | 'waiting' - | 'whats-new' type StoreStates = { active: ActiveState archive: ArchiveState autoreset: AutoResetState - avatar: AvatarState bots: BotsState chat: ChatState config: ConfigState crypto: CryptoState - 'current-user': CurrentUserState daemon: DaemonState - 'dark-mode': DarkModeState deeplinks: DeepLinksState devices: DevicesState engine: EngineState - followers: FollowersState fs: FSState git: GitState - logout: LogoutState notifications: NotificationsState people: PeopleState - pinentry: PinentryState profile: ProfileState provision: ProvisionState push: PushState @@ -123,32 +101,24 @@ type StoreStates = { tracker2: Tracker2State 'unlock-folders': UnlockFoldersState users: UsersState - waiting: WaitingState - 'whats-new': WhatsNewState } type StoreHooks = { active: typeof useActiveState archive: typeof useArchiveState autoreset: typeof useAutoResetState - avatar: typeof useAvatarState bots: typeof useBotsState chat: typeof useChatState config: typeof useConfigState crypto: typeof useCryptoState - 'current-user': typeof useCurrentUserState daemon: typeof useDaemonState - 'dark-mode': typeof useDarkModeState deeplinks: typeof useDeepLinksState devices: typeof useDevicesState engine: typeof useEngineState - followers: typeof useFollowerState fs: typeof useFSState git: typeof useGitState - logout: typeof useLogoutState notifications: typeof useNotifState people: typeof usePeopleState - pinentry: typeof usePinentryState profile: typeof useProfileState provision: typeof useProvisionState push: typeof usePushState @@ -165,8 +135,6 @@ type StoreHooks = { tracker2: typeof useTrackerState 'unlock-folders': typeof useUnlockFoldersState users: typeof useUsersState - waiting: typeof useWaitingState - 'whats-new': typeof useWhatsNewState } class StoreRegistry { @@ -185,10 +153,6 @@ class StoreRegistry { const {useAutoResetState} = require('./autoreset') return useAutoResetState } - case 'avatar': { - const {useAvatarState} = require('@/common-adapters/avatar/store') - return useAvatarState - } case 'bots': { const {useBotsState} = require('./bots') return useBotsState @@ -201,10 +165,6 @@ class StoreRegistry { const {useConfigState} = require('./config') return useConfigState } - case 'current-user': { - const {useCurrentUserState} = require('./current-user') - return useCurrentUserState - } case 'crypto': { const {useCryptoState} = require('./crypto') return useCryptoState @@ -213,10 +173,6 @@ class StoreRegistry { const {useDaemonState} = require('./daemon') return useDaemonState } - case 'dark-mode': { - const {useDarkModeState} = require('./darkmode') - return useDarkModeState - } case 'deeplinks': { const {useDeepLinksState} = require('./deeplinks') return useDeepLinksState @@ -229,10 +185,6 @@ class StoreRegistry { const {useEngineState} = require('./engine') return useEngineState } - case 'followers': { - const {useFollowerState} = require('./followers') - return useFollowerState - } case 'fs': { const {useFSState} = require('./fs') return useFSState @@ -241,10 +193,6 @@ class StoreRegistry { const {useGitState} = require('./git') return useGitState } - case 'logout': { - const {useLogoutState} = require('./logout') - return useLogoutState - } case 'notifications': { const {useNotifState} = require('./notifications') return useNotifState @@ -253,10 +201,6 @@ class StoreRegistry { const {usePeopleState} = require('./people') return usePeopleState } - case 'pinentry': { - const {usePinentryState} = require('./pinentry') - return usePinentryState - } case 'profile': { const {useProfileState} = require('./profile') return useProfileState @@ -321,14 +265,6 @@ class StoreRegistry { const {useUsersState} = require('./users') return useUsersState } - case 'waiting': { - const {useWaitingState} = require('./waiting') - return useWaitingState - } - case 'whats-new': { - const {useWhatsNewState} = require('./whats-new') - return useWhatsNewState - } default: throw new Error(`Unknown store: ${storeName}`) } diff --git a/shared/constants/teams/index.tsx b/shared/constants/teams/index.tsx index d221afa1fddd..3c99b98e7e04 100644 --- a/shared/constants/teams/index.tsx +++ b/shared/constants/teams/index.tsx @@ -20,6 +20,7 @@ import {mapGetEnsureValue} from '@/util/map' import {bodyToJSON} from '../rpc-utils' import {fixCrop} from '@/util/crop' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' import * as Util from './util' import {getTab} from '../router2/util' @@ -304,7 +305,7 @@ export const getDisabledReasonsForRolePicker = ( theyAreOwner = membersToModify.some(username => members.get(username)?.type === 'owner') } - const myUsername = storeRegistry.getState('current-user').username + const myUsername = useCurrentUserState.getState().username const you = members.get(myUsername) // Fallback to the lowest role, although this shouldn't happen const yourRole = you?.type ?? 'reader' @@ -1519,7 +1520,7 @@ export const useTeamsState = Z.createZustand((set, get) => { set(s => { s.errorInTeamCreation = '' }) - const me = storeRegistry.getState('current-user').username + const me = useCurrentUserState.getState().username const participantInfo = storeRegistry.getConvoState(conversationIDKey).participants // exclude bots from the newly created team, they can be added back later. const participants = participantInfo.name.filter(p => p !== me) // we will already be in as 'owner' @@ -1790,7 +1791,7 @@ export const useTeamsState = Z.createZustand((set, get) => { } const f = async () => { - const username = storeRegistry.getState('current-user').username + const username = useCurrentUserState.getState().username const loggedIn = storeRegistry.getState('config').loggedIn if (!username || !loggedIn) { logger.warn('getTeams while logged out') diff --git a/shared/constants/tracker2/index.tsx b/shared/constants/tracker2/index.tsx index 8ea35a1b511e..4d4e32101536 100644 --- a/shared/constants/tracker2/index.tsx +++ b/shared/constants/tracker2/index.tsx @@ -8,6 +8,7 @@ import {RPCError} from '@/util/errors' import {mapGetEnsureValue} from '@/util/map' import {navigateAppend, navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useCurrentUserState} from '../current-user' export const noDetails: T.Tracker.Details = { assertions: new Map(), @@ -531,11 +532,11 @@ export const useTrackerState = Z.createZustand((set, get) => { } // if we mutated somehow reload ourselves and reget the suggestions case EngineGen.keybase1NotifyUsersUserChanged: { - if (storeRegistry.getState('current-user').uid !== action.payload.params.uid) { + if (useCurrentUserState.getState().uid !== action.payload.params.uid) { return } get().dispatch.load({ - assertion: storeRegistry.getState('current-user').username, + assertion: useCurrentUserState.getState().username, forceDisplay: false, fromDaemon: false, guiID: generateGUIID(), diff --git a/shared/constants/waiting/index.tsx b/shared/constants/waiting/index.tsx index 4ba0a2f8388a..c98dd7515a17 100644 --- a/shared/constants/waiting/index.tsx +++ b/shared/constants/waiting/index.tsx @@ -2,6 +2,7 @@ import type {RPCError} from '@/util/errors' import type * as T from '../types' import * as Z from '@/util/zustand' +// This store has no dependencies on other stores and is safe to import directly from other stores. const initialStore: T.Waiting.State = { counts: new Map(), errors: new Map(), diff --git a/shared/constants/whats-new/index.tsx b/shared/constants/whats-new/index.tsx index 526d9e4473d7..4a2d0bddcac0 100644 --- a/shared/constants/whats-new/index.tsx +++ b/shared/constants/whats-new/index.tsx @@ -5,6 +5,7 @@ import {noVersion, getSeenVersions} from './utils' export {currentVersion, lastVersion, lastLastVersion, keybaseFM} from './utils' +// This store has no dependencies on other stores and is safe to import directly from other stores. type SeenVersionsMap = {[key in string]: boolean} type Store = T.Immutable<{ From f34ebb33a134c839e7cbf41f478aaa6702519b8e Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Tue, 6 Jan 2026 10:03:02 -0500 Subject: [PATCH 02/20] WIP --- shared/constants/crypto/index.tsx | 1 - shared/constants/pinentry/util.tsx | 1 - shared/constants/platform-specific/kbfs-notifications.tsx | 1 - shared/constants/settings-password/index.tsx | 1 - 4 files changed, 4 deletions(-) diff --git a/shared/constants/crypto/index.tsx b/shared/constants/crypto/index.tsx index dbf1f6c551bf..1d0a1de56944 100644 --- a/shared/constants/crypto/index.tsx +++ b/shared/constants/crypto/index.tsx @@ -7,7 +7,6 @@ import logger from '@/logger' import * as T from '../types' import {RPCError} from '@/util/errors' import {navigateAppend} from '../router2/util' -import {storeRegistry} from '../store-registry' import {useCurrentUserState} from '../current-user' import {Operations} from './util' export * from './util' diff --git a/shared/constants/pinentry/util.tsx b/shared/constants/pinentry/util.tsx index 6bc86e3001f6..5bc792128d6e 100644 --- a/shared/constants/pinentry/util.tsx +++ b/shared/constants/pinentry/util.tsx @@ -1,7 +1,6 @@ import * as T from '../types' import {ignorePromise} from '../utils' import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' import {usePinentryState} from '../pinentry' import logger from '@/logger' diff --git a/shared/constants/platform-specific/kbfs-notifications.tsx b/shared/constants/platform-specific/kbfs-notifications.tsx index f23791bd2d4e..6d5b97e4a18b 100644 --- a/shared/constants/platform-specific/kbfs-notifications.tsx +++ b/shared/constants/platform-specific/kbfs-notifications.tsx @@ -1,5 +1,4 @@ import {pathSep} from '@/constants/platform' -import {storeRegistry} from '@/constants/store-registry' import {useCurrentUserState} from '@/constants/current-user' import capitalize from 'lodash/capitalize' import * as T from '@/constants/types' diff --git a/shared/constants/settings-password/index.tsx b/shared/constants/settings-password/index.tsx index 6f1c95cb7a7d..40123b264cd8 100644 --- a/shared/constants/settings-password/index.tsx +++ b/shared/constants/settings-password/index.tsx @@ -5,7 +5,6 @@ import logger from '@/logger' import {RPCError} from '@/util/errors' import * as T from '../types' import {navigateUp} from '../router2/util' -import {storeRegistry} from '../store-registry' import {useLogoutState} from '../logout' type Store = T.Immutable<{ From e73bc173ae0feccd58d2404ddf1af76d879101af Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Tue, 6 Jan 2026 17:21:17 -0500 Subject: [PATCH 03/20] more subs (#28758) * more subs * WIP * store shift 5 (#28759) * WIP * move more onEngineIncoming * WIP * WIP * WIP * WIP * store shift 6 (#28765) * WIP * WIP * WIP (#28767) --------- Co-authored-by: chrisnojima --------- Co-authored-by: chrisnojima --------- Co-authored-by: chrisnojima --- shared/common-adapters/avatar/util.tsx | 14 + shared/constants/config/index.tsx | 306 +--------------- shared/constants/engine/index.tsx | 37 +- shared/constants/followers/util.tsx | 29 ++ .../platform-specific/index.desktop.tsx | 343 +++++++++++++----- .../platform-specific/index.native.tsx | 83 +++-- shared/constants/platform-specific/shared.tsx | 147 ++++++++ shared/desktop/renderer/main2.desktop.tsx | 5 +- shared/devices/device-revoke.tsx | 4 +- 9 files changed, 513 insertions(+), 455 deletions(-) create mode 100644 shared/common-adapters/avatar/util.tsx create mode 100644 shared/constants/followers/util.tsx create mode 100644 shared/constants/platform-specific/shared.tsx diff --git a/shared/common-adapters/avatar/util.tsx b/shared/common-adapters/avatar/util.tsx new file mode 100644 index 000000000000..6e08e360ab2f --- /dev/null +++ b/shared/common-adapters/avatar/util.tsx @@ -0,0 +1,14 @@ +import * as EngineGen from '@/actions/engine-gen-gen' +import {useAvatarState} from '@/common-adapters/avatar/store' + +export const onEngineIncoming = (action: EngineGen.Actions) => { + switch (action.type) { + case EngineGen.keybase1NotifyTeamAvatarUpdated: { + const {name} = action.payload.params + useAvatarState.getState().dispatch.updated(name) + break + } + default: + } +} + diff --git a/shared/constants/config/index.tsx b/shared/constants/config/index.tsx index 2ca66cf343cc..01a496551e42 100644 --- a/shared/constants/config/index.tsx +++ b/shared/constants/config/index.tsx @@ -1,9 +1,7 @@ import * as T from '../types' import {ignorePromise, timeoutPromise} from '../utils' -import {serverConfigFileName} from '../platform' import {waitingKeyConfigLogin} from '../strings' import * as EngineGen from '@/actions/engine-gen-gen' -import * as RemoteGen from '@/actions/remote-gen' import * as Stats from '@/engine/stats' import * as Z from '@/util/zustand' import {noConversationIDKey} from '../types/chat2/common' @@ -14,14 +12,9 @@ import {RPCError, convertToError, isEOFError, isErrorTransient, niceError} from import {defaultUseNativeFrame, isMobile} from '../platform' import {type CommonResponseHandler} from '@/engine/types' import {invalidPasswordErrorString} from './util' -import {navigateAppend, switchTab} from '../router2/util' +import {navigateAppend} from '../router2/util' import {storeRegistry} from '../store-registry' -import {useAvatarState} from '@/common-adapters/avatar/store' -import {useCurrentUserState} from '../current-user' -import {useFollowerState} from '../followers' -import {usePinentryState} from '../pinentry' import {useWhatsNewState} from '../whats-new' -import {getSelectedConversation} from '@/constants/chat2/common' type Store = T.Immutable<{ forceSmallNav: boolean @@ -168,7 +161,6 @@ export interface State extends Store { changedFocus: (f: boolean) => void checkForUpdate: () => void dumpLogs: (reason: string) => Promise - eventFromRemoteWindows: (action: RemoteGen.Actions) => void filePickerError: (error: Error) => void initAppUpdateLoop: () => void initNotifySound: () => void @@ -190,7 +182,7 @@ export interface State extends Store { resetState: (isDebug?: boolean) => void remoteWindowNeedsProps: (component: string, params: string) => void resetRevokedSelf: () => void - revoke: (deviceName: string) => void + revoke: (deviceName: string, wasCurrentDevice: boolean) => void setAccounts: (a: Store['configuredAccounts']) => void setAndroidShare: (s: Store['androidShare']) => void setBadgeState: (b: State['badgeState']) => void @@ -206,8 +198,9 @@ export interface State extends Store { setStartupDetails: (st: Omit) => void setOpenAtLogin: (open: boolean) => void setOutOfDate: (outOfDate: T.Config.OutOfDate) => void - setUserSwitching: (sw: boolean) => void + setUpdating: () => void setUseNativeFrame: (use: boolean) => void + setUserSwitching: (sw: boolean) => void showMain: () => void toggleRuntimeStats: () => void updateGregorCategory: (category: string, body: string, dtime?: {offset: number; time: number}) => void @@ -250,15 +243,6 @@ export const useConfigState = Z.createZustand((set, get) => { set(s => { s.gregorReachable = r }) - // Re-get info about our account if you log in/we're done handshaking/became reachable - if (r === T.RPCGen.Reachable.yes) { - // not in waiting state - if (storeRegistry.getState('daemon').handshakeWaiters.size === 0) { - ignorePromise(storeRegistry.getState('daemon').dispatch.loadDaemonBootstrapStatus()) - } - } - - storeRegistry.getState('teams').dispatch.eagerLoadTeams() } const setGregorPushState = (state: T.RPCGen.Gregor1.State) => { @@ -286,26 +270,6 @@ export const useConfigState = Z.createZustand((set, get) => { useWhatsNewState.getState().dispatch.updateLastSeen(lastSeenItem) } - const updateApp = () => { - const f = async () => { - await T.RPCGen.configStartUpdateIfNeededRpcPromise() - } - ignorePromise(f()) - // * If user choose to update: - // We'd get killed and it doesn't matter what happens here. - // * If user hits "Ignore": - // Note that we ignore the snooze here, so the state shouldn't change, - // and we'd back to where we think we still need an update. So we could - // have just unset the "updating" flag.However, in case server has - // decided to pull out the update between last time we asked the updater - // and now, we'd be in a wrong state if we didn't check with the service. - // Since user has interacted with it, we still ask the service to make - // sure. - set(s => { - s.outOfDate.updating = true - }) - } - const updateRuntimeStats = (stats?: T.RPCGen.RuntimeStats) => { set(s => { if (!stats) { @@ -325,13 +289,6 @@ export const useConfigState = Z.createZustand((set, get) => { set(s => { s.appFocused = f }) - - if (!isMobile || !f) { - return - } - const {dispatch} = storeRegistry.getConvoState(getSelectedConversation()) - dispatch.loadMoreMessages({reason: 'foregrounding'}) - dispatch.markThreadAsRead() }, checkForUpdate: () => { const f = async () => { @@ -358,154 +315,6 @@ export const useConfigState = Z.createZustand((set, get) => { showMainNative: undefined, showShareActionSheet: undefined, }, - eventFromRemoteWindows: (action: RemoteGen.Actions) => { - switch (action.type) { - case RemoteGen.resetStore: - break - case RemoteGen.openChatFromWidget: { - get().dispatch.showMain() - storeRegistry - .getConvoState(action.payload.conversationIDKey) - .dispatch.navigateToThread('inboxSmall') - break - } - case RemoteGen.inboxRefresh: { - storeRegistry.getState('chat').dispatch.inboxRefresh('widgetRefresh') - break - } - case RemoteGen.engineConnection: { - if (action.payload.connected) { - storeRegistry.getState('engine').dispatch.onEngineConnected() - } else { - storeRegistry.getState('engine').dispatch.onEngineDisconnected() - } - break - } - case RemoteGen.switchTab: { - switchTab(action.payload.tab) - break - } - case RemoteGen.setCriticalUpdate: { - storeRegistry.getState('fs').dispatch.setCriticalUpdate(action.payload.critical) - break - } - case RemoteGen.userFileEditsLoad: { - storeRegistry.getState('fs').dispatch.userFileEditsLoad() - break - } - case RemoteGen.openFilesFromWidget: { - storeRegistry.getState('fs').dispatch.dynamic.openFilesFromWidgetDesktop?.(action.payload.path) - break - } - case RemoteGen.saltpackFileOpen: { - storeRegistry.getState('deeplinks').dispatch.handleSaltPackOpen(action.payload.path) - break - } - case RemoteGen.pinentryOnCancel: { - usePinentryState.getState().dispatch.dynamic.onCancel?.() - break - } - case RemoteGen.pinentryOnSubmit: { - usePinentryState.getState().dispatch.dynamic.onSubmit?.(action.payload.password) - break - } - case RemoteGen.openPathInSystemFileManager: { - storeRegistry - .getState('fs') - .dispatch.dynamic.openPathInSystemFileManagerDesktop?.(action.payload.path) - break - } - case RemoteGen.unlockFoldersSubmitPaperKey: { - T.RPCGen.loginPaperKeySubmitRpcPromise( - {paperPhrase: action.payload.paperKey}, - 'unlock-folders:waiting' - ) - .then(() => { - get().dispatch.openUnlockFolders([]) - }) - .catch((e: unknown) => { - if (!(e instanceof RPCError)) return - set(s => { - s.unlockFoldersError = e.desc - }) - }) - break - } - case RemoteGen.closeUnlockFolders: { - T.RPCGen.rekeyRekeyStatusFinishRpcPromise() - .then(() => {}) - .catch(() => {}) - get().dispatch.openUnlockFolders([]) - break - } - case RemoteGen.stop: { - storeRegistry.getState('settings').dispatch.stop(action.payload.exitCode) - break - } - case RemoteGen.trackerChangeFollow: { - storeRegistry - .getState('tracker2') - .dispatch.changeFollow(action.payload.guiID, action.payload.follow) - break - } - case RemoteGen.trackerIgnore: { - storeRegistry.getState('tracker2').dispatch.ignore(action.payload.guiID) - break - } - case RemoteGen.trackerCloseTracker: { - storeRegistry.getState('tracker2').dispatch.closeTracker(action.payload.guiID) - break - } - case RemoteGen.trackerLoad: { - storeRegistry.getState('tracker2').dispatch.load(action.payload) - break - } - case RemoteGen.link: - { - const {link} = action.payload - storeRegistry.getState('deeplinks').dispatch.handleAppLink(link) - } - break - case RemoteGen.installerRan: - get().dispatch.installerRan() - break - case RemoteGen.updateNow: - updateApp() - break - case RemoteGen.powerMonitorEvent: - get().dispatch.powerMonitorEvent(action.payload.event) - break - case RemoteGen.showMain: - get().dispatch.showMain() - break - case RemoteGen.dumpLogs: - ignorePromise(get().dispatch.dumpLogs(action.payload.reason)) - break - case RemoteGen.remoteWindowWantsProps: - get().dispatch.remoteWindowNeedsProps(action.payload.component, action.payload.param) - break - case RemoteGen.updateWindowMaxState: - set(s => { - s.windowState.isMaximized = action.payload.max - }) - break - case RemoteGen.updateWindowState: - get().dispatch.updateWindowState(action.payload.windowState) - break - case RemoteGen.updateWindowShown: { - const win = action.payload.component - set(s => { - s.windowShownCount.set(win, (s.windowShownCount.get(win) ?? 0) + 1) - }) - break - } - case RemoteGen.previewConversation: - storeRegistry - .getState('chat') - .dispatch.previewConversation({participants: [action.payload.participant], reason: 'tracker'}) - break - } - }, filePickerError: error => { get().dispatch.dynamic.onFilePickerError?.(error) }, @@ -576,8 +385,6 @@ export const useConfigState = Z.createZustand((set, get) => { set(s => { s.installerRanCount++ }) - - storeRegistry.getState('fs').dispatch.checkKbfsDaemonRpcStatus() }, loadIsOnline: () => { const f = async () => { @@ -597,59 +404,6 @@ export const useConfigState = Z.createZustand((set, get) => { set(s => { s.loadOnStartPhase = phase }) - - if (phase === 'startupOrReloginButNotInARush') { - const getFollowerInfo = () => { - const {uid} = useCurrentUserState.getState() - logger.info(`getFollowerInfo: init; uid=${uid}`) - if (uid) { - // request follower info in the background - T.RPCGen.configRequestFollowingAndUnverifiedFollowersRpcPromise() - .then(() => {}) - .catch(() => {}) - } - } - - const updateServerConfig = async () => { - if (get().loggedIn) { - try { - await T.RPCGen.configUpdateLastLoggedInAndServerConfigRpcPromise({ - serverConfigPath: serverConfigFileName, - }) - } catch {} - } - } - - const updateTeams = () => { - storeRegistry.getState('teams').dispatch.getTeams() - storeRegistry.getState('teams').dispatch.refreshTeamRoleMap() - } - - const updateSettings = () => { - storeRegistry.getState('settings-contacts').dispatch.loadContactImportEnabled() - } - - const updateChat = async () => { - // On login lets load the untrusted inbox. This helps make some flows easier - if (useCurrentUserState.getState().username) { - const {inboxRefresh} = storeRegistry.getState('chat').dispatch - inboxRefresh('bootstrap') - } - try { - const rows = await T.RPCGen.configGuiGetValueRpcPromise({path: 'ui.inboxSmallRows'}) - const ri = rows.i ?? -1 - if (ri > 0) { - storeRegistry.getState('chat').dispatch.setInboxNumSmallRows(ri, true) - } - } catch {} - } - - getFollowerInfo() - ignorePromise(updateServerConfig()) - updateTeams() - updateSettings() - ignorePromise(updateChat()) - } }, login: (username, passphrase) => { const cancelDesc = 'Canceling RPC' @@ -803,34 +557,6 @@ export const useConfigState = Z.createZustand((set, get) => { } break } - case EngineGen.keybase1NotifyTeamAvatarUpdated: { - const {name} = action.payload.params - useAvatarState.getState().dispatch.updated(name) - break - } - case EngineGen.keybase1NotifyTrackingTrackingChanged: { - const {isTracking, username} = action.payload.params - useFollowerState.getState().dispatch.updateFollowing(username, isTracking) - break - } - case EngineGen.keybase1NotifyTrackingTrackingInfo: { - const {uid, followers: _newFollowers, followees: _newFollowing} = action.payload.params - if (useCurrentUserState.getState().uid !== uid) { - return - } - const newFollowers = new Set(_newFollowers) - const newFollowing = new Set(_newFollowing) - const { - following: oldFollowing, - followers: oldFollowers, - dispatch, - } = useFollowerState.getState() - const following = isEqual(newFollowing, oldFollowing) ? oldFollowing : newFollowing - const followers = isEqual(newFollowers, oldFollowers) ? oldFollowers : newFollowers - dispatch.replace(followers, following) - break - } - case EngineGen.keybase1ReachabilityReachabilityChanged: if (get().loggedIn) { setGregorReachable(action.payload.params.reachability.reachable) @@ -914,8 +640,7 @@ export const useConfigState = Z.createZustand((set, get) => { userSwitching: s.userSwitching, })) }, - revoke: name => { - const wasCurrentDevice = useCurrentUserState.getState().deviceName === name + revoke: (name, wasCurrentDevice) => { if (wasCurrentDevice) { const {configuredAccounts, defaultUsername} = get() const acc = configuredAccounts.find(n => n.username !== defaultUsername) @@ -1020,11 +745,6 @@ export const useConfigState = Z.createZustand((set, get) => { if (!changed) return - if (loggedIn) { - ignorePromise(storeRegistry.getState('daemon').dispatch.loadDaemonBootstrapStatus()) - } - storeRegistry.getState('daemon').dispatch.loadDaemonAccounts() - const {loadOnStart} = get().dispatch if (loggedIn) { if (!causedByStartup) { @@ -1040,14 +760,6 @@ export const useConfigState = Z.createZustand((set, get) => { } else { Z.resetAllStores() } - - if (loggedIn) { - storeRegistry.getState('fs').dispatch.checkKbfsDaemonRpcStatus() - } - - if (!causedByStartup) { - ignorePromise(storeRegistry.getState('daemon').dispatch.refreshAccounts()) - } }, setLoginError: error => { set(s => { @@ -1062,9 +774,6 @@ export const useConfigState = Z.createZustand((set, get) => { set(s => { s.mobileAppState = nextAppState }) - if (nextAppState === 'background' && storeRegistry.getState('chat').inboxSearch) { - storeRegistry.getState('chat').dispatch.toggleInboxSearch(false) - } }, setNotifySound: n => { set(s => { @@ -1104,6 +813,11 @@ export const useConfigState = Z.createZustand((set, get) => { } }) }, + setUpdating: () => { + set(s => { + s.outOfDate.updating = true + }) + }, setUseNativeFrame: use => { set(s => { s.useNativeFrame = use diff --git a/shared/constants/engine/index.tsx b/shared/constants/engine/index.tsx index e2d651083c6b..9b8a73cf31cd 100644 --- a/shared/constants/engine/index.tsx +++ b/shared/constants/engine/index.tsx @@ -1,23 +1,13 @@ -import * as Z from '@/util/zustand' -import {storeRegistry} from '../store-registry' import type * as EngineGen from '@/actions/engine-gen-gen' -import * as ArchiveUtil from '../archive/util' -import * as AutoResetUtil from '../autoreset/util' -import * as BotsUtil from '../bots/util' +import * as Z from '@/util/zustand' import * as ChatUtil from '../chat2/util' -import * as DeepLinksUtil from '../deeplinks/util' -import * as DevicesUtil from '../devices/util' -import * as FSUtil from '../fs/util' -import * as GitUtil from '../git/util' import * as NotifUtil from '../notifications/util' import * as PeopleUtil from '../people/util' import * as PinentryUtil from '../pinentry/util' -import * as SettingsUtil from '../settings/util' -import * as SignupUtil from '../signup/util' -import * as TeamsUtil from '../teams/util' +import {onEngineIncoming as onEngineIncomingShared} from '../platform-specific/shared' +import {storeRegistry} from '../store-registry' import * as TrackerUtil from '../tracker2/util' import * as UnlockFoldersUtil from '../unlock-folders/util' -import * as UsersUtil from '../users/util' type Store = object const initialStore: Store = {} @@ -50,26 +40,7 @@ export const useEngineState = Z.createZustand(set => { // defer a frame so its more like before incomingTimeout = setTimeout(() => { // we delegate to these utils so we don't need to load stores that we don't need yet - ArchiveUtil.onEngineIncoming(action) - AutoResetUtil.onEngineIncoming(action) - BotsUtil.onEngineIncoming(action) - ChatUtil.onEngineIncoming(action) - storeRegistry.getState('config').dispatch.dynamic.onEngineIncomingDesktop?.(action) - storeRegistry.getState('config').dispatch.dynamic.onEngineIncomingNative?.(action) - storeRegistry.getState('config').dispatch.onEngineIncoming(action) - DeepLinksUtil.onEngineIncoming(action) - DevicesUtil.onEngineIncoming(action) - FSUtil.onEngineIncoming(action) - GitUtil.onEngineIncoming(action) - NotifUtil.onEngineIncoming(action) - PeopleUtil.onEngineIncoming(action) - PinentryUtil.onEngineIncoming(action) - SettingsUtil.onEngineIncoming(action) - SignupUtil.onEngineIncoming(action) - TeamsUtil.onEngineIncoming(action) - TrackerUtil.onEngineIncoming(action) - UnlockFoldersUtil.onEngineIncoming(action) - UsersUtil.onEngineIncoming(action) + onEngineIncomingShared(action) }, 0) }, resetState: () => { diff --git a/shared/constants/followers/util.tsx b/shared/constants/followers/util.tsx new file mode 100644 index 000000000000..34ea577cab45 --- /dev/null +++ b/shared/constants/followers/util.tsx @@ -0,0 +1,29 @@ +import * as EngineGen from '@/actions/engine-gen-gen' +import isEqual from 'lodash/isEqual' +import {useCurrentUserState} from '../current-user' +import {useFollowerState} from '../followers' + +export const onEngineIncoming = (action: EngineGen.Actions) => { + switch (action.type) { + case EngineGen.keybase1NotifyTrackingTrackingChanged: { + const {isTracking, username} = action.payload.params + useFollowerState.getState().dispatch.updateFollowing(username, isTracking) + break + } + case EngineGen.keybase1NotifyTrackingTrackingInfo: { + const {uid, followers: _newFollowers, followees: _newFollowing} = action.payload.params + if (useCurrentUserState.getState().uid !== uid) { + return + } + const newFollowers = new Set(_newFollowers) + const newFollowing = new Set(_newFollowing) + const {following: oldFollowing, followers: oldFollowers, dispatch} = useFollowerState.getState() + const following = isEqual(newFollowing, oldFollowing) ? oldFollowing : newFollowing + const followers = isEqual(newFollowers, oldFollowers) ? oldFollowers : newFollowers + dispatch.replace(followers, following) + break + } + default: + } +} + diff --git a/shared/constants/platform-specific/index.desktop.tsx b/shared/constants/platform-specific/index.desktop.tsx index b9f8f70f7ade..50fca882c4ef 100644 --- a/shared/constants/platform-specific/index.desktop.tsx +++ b/shared/constants/platform-specific/index.desktop.tsx @@ -1,20 +1,31 @@ import * as Chat from '../chat2' import {ignorePromise} from '../utils' -import {storeRegistry} from '../store-registry' +import {useActiveState} from '../active' +import {useConfigState} from '../config' import * as ConfigConstants from '../config' +import {useDaemonState} from '../daemon' +import {useFSState} from '../fs' +import {usePinentryState} from '../pinentry' +import {useProfileState} from '../profile' +import {useRouterState} from '../router2' import * as EngineGen from '@/actions/engine-gen-gen' +import * as RemoteGen from '@/actions/remote-gen' import * as T from '../types' import InputMonitor from './input-monitor.desktop' import KB2 from '@/util/electron.desktop' import logger from '@/logger' -import type {RPCError} from '@/util/errors' +import {RPCError} from '@/util/errors' import {getEngine} from '@/engine' import {isLinux, isWindows} from '../platform.desktop' import {kbfsNotification} from './kbfs-notifications' import {skipAppFocusActions} from '@/local-debug.desktop' import NotifyPopup from '@/util/notify-popup' import {noKBFSFailReason} from '@/constants/config/util' +import {initSharedSubscriptions} from './shared' +import {switchTab} from '../router2/util' +import {storeRegistry} from '../store-registry' import {wrapErrors} from '@/util/debug' +import {getSelectedConversation} from '@/constants/chat2/common' const {showMainWindow, activeChanged, requestWindowsStartService, dumpNodeLogger} = KB2.functions const {quitApp, exitApp, setOpenAtLogin, ctlQuit, copyToClipboard} = KB2.functions @@ -34,7 +45,7 @@ export const requestLocationPermission = async () => Promise.resolve() export const watchPositionForMap = async () => Promise.resolve(() => {}) const maybePauseVideos = () => { - const {appFocused} = storeRegistry.getState('config') + const {appFocused} = useConfigState.getState() const videos = document.querySelectorAll('video') const allVideos = Array.from(videos) @@ -67,7 +78,7 @@ export const dumpLogs = async (reason?: string) => { } export const initPlatformListener = () => { - storeRegistry.getStore('config').setState(s => { + useConfigState.setState(s => { s.dispatch.dynamic.dumpLogsNative = dumpLogs s.dispatch.dynamic.showMainNative = wrapErrors(() => showMainWindow?.()) s.dispatch.dynamic.copyToClipboard = wrapErrors((s: string) => copyToClipboard?.(s)) @@ -136,8 +147,8 @@ export const initPlatformListener = () => { const body = upgradeMsg || `Please update to ${upgradeTo} by going to ${upgradeURI}` NotifyPopup('Client out of date!', {body}, 60 * 60) // This is from the API server. Consider notifications from server always critical. - storeRegistry - .getState('config') + useConfigState + .getState() .dispatch.setOutOfDate({critical: true, message: upgradeMsg, outOfDate: true, updating: false}) break } @@ -146,40 +157,50 @@ export const initPlatformListener = () => { }) }) - storeRegistry.getStore('config').subscribe((s, old) => { - if (s.loggedIn === old.loggedIn) return - storeRegistry.getState('config').dispatch.osNetworkStatusChanged(navigator.onLine, 'notavailable', true) - }) + useConfigState.subscribe((s, old) => { + if (s.loggedIn !== old.loggedIn) { + s.dispatch.osNetworkStatusChanged(navigator.onLine, 'notavailable', true) + } - storeRegistry.getStore('config').subscribe((s, prev) => { - if (s.appFocused !== prev.appFocused) { + if (s.appFocused !== old.appFocused) { maybePauseVideos() + if (!old.appFocused && s.appFocused) { + const {dispatch} = storeRegistry.getConvoState(getSelectedConversation()) + dispatch.loadMoreMessages({reason: 'foregrounding'}) + dispatch.markThreadAsRead() + } } - }) - storeRegistry.getStore('daemon').subscribe((s, old) => { - if (s.handshakeVersion === old.handshakeVersion) return - if (!isWindows) return - - const f = async () => { - const waitKey = 'pipeCheckFail' - const version = s.handshakeVersion - const {wait} = storeRegistry.getState('daemon').dispatch - wait(waitKey, version, true) - try { - logger.info('Checking RPC ownership') - if (KB2.functions.winCheckRPCOwnership) { - await KB2.functions.winCheckRPCOwnership() + if (s.openAtLogin !== old.openAtLogin) { + const {openAtLogin} = s + const f = async () => { + if (__DEV__) { + console.log('onSetOpenAtLogin disabled for dev mode') + return + } else { + await T.RPCGen.configGuiSetValueRpcPromise({ + path: ConfigConstants.openAtLoginKey, + value: {b: openAtLogin, isNull: false}, + }) + } + if (isLinux || isWindows) { + const enabled = + (await T.RPCGen.ctlGetOnLoginStartupRpcPromise()) === T.RPCGen.OnLoginStartupStatus.enabled + if (enabled !== openAtLogin) { + try { + await T.RPCGen.ctlSetOnLoginStartupRpcPromise({enabled: openAtLogin}) + } catch (error_) { + const error = error_ as RPCError + logger.warn(`Error in sending ctlSetOnLoginStartup: ${error.message}`) + } + } + } else { + logger.info(`Login item settings changed! now ${openAtLogin ? 'on' : 'off'}`) + await setOpenAtLogin?.(openAtLogin) } - wait(waitKey, version, false) - } catch (error_) { - // error will be logged in bootstrap check - getEngine().reset() - const error = error_ as RPCError - wait(waitKey, version, false, error.message || 'windows pipe owner fail', true) } + ignorePromise(f()) } - ignorePromise(f()) }) const handleWindowFocusEvents = () => { @@ -187,7 +208,7 @@ export const initPlatformListener = () => { if (skipAppFocusActions) { console.log('Skipping app focus actions!') } else { - storeRegistry.getState('config').dispatch.changedFocus(appFocused) + useConfigState.getState().dispatch.changedFocus(appFocused) } } window.addEventListener('focus', () => handle(true)) @@ -197,68 +218,61 @@ export const initPlatformListener = () => { const setupReachabilityWatcher = () => { window.addEventListener('online', () => - storeRegistry.getState('config').dispatch.osNetworkStatusChanged(true, 'notavailable') + useConfigState.getState().dispatch.osNetworkStatusChanged(true, 'notavailable') ) window.addEventListener('offline', () => - storeRegistry.getState('config').dispatch.osNetworkStatusChanged(false, 'notavailable') + useConfigState.getState().dispatch.osNetworkStatusChanged(false, 'notavailable') ) } setupReachabilityWatcher() - storeRegistry.getStore('config').subscribe((s, old) => { - if (s.openAtLogin === old.openAtLogin) return - const {openAtLogin} = s - const f = async () => { - if (__DEV__) { - console.log('onSetOpenAtLogin disabled for dev mode') - return - } else { - await T.RPCGen.configGuiSetValueRpcPromise({ - path: ConfigConstants.openAtLoginKey, - value: {b: openAtLogin, isNull: false}, - }) - } - if (isLinux || isWindows) { - const enabled = - (await T.RPCGen.ctlGetOnLoginStartupRpcPromise()) === T.RPCGen.OnLoginStartupStatus.enabled - if (enabled !== openAtLogin) { - try { - await T.RPCGen.ctlSetOnLoginStartupRpcPromise({enabled: openAtLogin}) - } catch (error_) { - const error = error_ as RPCError - logger.warn(`Error in sending ctlSetOnLoginStartup: ${error.message}`) + useDaemonState.subscribe((s, old) => { + if (s.handshakeVersion !== old.handshakeVersion) { + if (!isWindows) return + + const f = async () => { + const waitKey = 'pipeCheckFail' + const version = s.handshakeVersion + const {wait} = s.dispatch + wait(waitKey, version, true) + try { + logger.info('Checking RPC ownership') + if (KB2.functions.winCheckRPCOwnership) { + await KB2.functions.winCheckRPCOwnership() } + wait(waitKey, version, false) + } catch (error_) { + // error will be logged in bootstrap check + getEngine().reset() + const error = error_ as RPCError + wait(waitKey, version, false, error.message || 'windows pipe owner fail', true) } - } else { - logger.info(`Login item settings changed! now ${openAtLogin ? 'on' : 'off'}`) - await setOpenAtLogin?.(openAtLogin) } + ignorePromise(f()) } - ignorePromise(f()) - }) - storeRegistry.getStore('daemon').subscribe((s, old) => { - if (s.handshakeState === old.handshakeState || s.handshakeState !== 'done') return - storeRegistry.getState('config').dispatch.setStartupDetails({ - conversation: Chat.noConversationIDKey, - followUser: '', - link: '', - tab: undefined, - }) + if (s.handshakeState !== old.handshakeState && s.handshakeState === 'done') { + useConfigState.getState().dispatch.setStartupDetails({ + conversation: Chat.noConversationIDKey, + followUser: '', + link: '', + tab: undefined, + }) + } }) if (isLinux) { - storeRegistry.getState('config').dispatch.initUseNativeFrame() + useConfigState.getState().dispatch.initUseNativeFrame() } - storeRegistry.getState('config').dispatch.initNotifySound() - storeRegistry.getState('config').dispatch.initForceSmallNav() - storeRegistry.getState('config').dispatch.initOpenAtLogin() - storeRegistry.getState('config').dispatch.initAppUpdateLoop() + useConfigState.getState().dispatch.initNotifySound() + useConfigState.getState().dispatch.initForceSmallNav() + useConfigState.getState().dispatch.initOpenAtLogin() + useConfigState.getState().dispatch.initAppUpdateLoop() - storeRegistry.getStore('profile').setState(s => { + useProfileState.setState(s => { s.dispatch.editAvatar = () => { - storeRegistry - .getState('router') + useRouterState + .getState() .dispatch.navigateAppend({props: {image: undefined}, selected: 'profileEditAvatar'}) } }) @@ -269,7 +283,7 @@ export const initPlatformListener = () => { if (skipAppFocusActions) { console.log('Skipping app focus actions!') } else { - storeRegistry.getState('active').dispatch.setActive(userActive) + useActiveState.getState().dispatch.setActive(userActive) // let node thread save file activeChanged?.(Date.now(), userActive) } @@ -277,14 +291,177 @@ export const initPlatformListener = () => { } initializeInputMonitor() - storeRegistry.getStore('daemon').setState(s => { + useDaemonState.setState(s => { s.dispatch.onRestartHandshakeNative = () => { - const {handshakeFailedReason} = storeRegistry.getState('daemon') + const {handshakeFailedReason} = useDaemonState.getState() if (isWindows && handshakeFailedReason === noKBFSFailReason) { requestWindowsStartService?.() } } }) - ignorePromise(storeRegistry.getState('fs').dispatch.setupSubscriptions()) + initSharedSubscriptions() + + ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) +} + +const updateApp = () => { + const f = async () => { + await T.RPCGen.configStartUpdateIfNeededRpcPromise() + } + ignorePromise(f()) + // * If user choose to update: + // We'd get killed and it doesn't matter what happens here. + // * If user hits "Ignore": + // Note that we ignore the snooze here, so the state shouldn't change, + // and we'd back to where we think we still need an update. So we could + // have just unset the "updating" flag.However, in case server has + // decided to pull out the update between last time we asked the updater + // and now, we'd be in a wrong state if we didn't check with the service. + // Since user has interacted with it, we still ask the service to make + // sure. + + useConfigState.getState().dispatch.setUpdating() +} + +export const eventFromRemoteWindows = (action: RemoteGen.Actions) => { + switch (action.type) { + case RemoteGen.resetStore: + break + case RemoteGen.openChatFromWidget: { + useConfigState.getState().dispatch.showMain() + storeRegistry.getConvoState(action.payload.conversationIDKey).dispatch.navigateToThread('inboxSmall') + break + } + case RemoteGen.inboxRefresh: { + storeRegistry.getState('chat').dispatch.inboxRefresh('widgetRefresh') + break + } + case RemoteGen.engineConnection: { + if (action.payload.connected) { + storeRegistry.getState('engine').dispatch.onEngineConnected() + } else { + storeRegistry.getState('engine').dispatch.onEngineDisconnected() + } + break + } + case RemoteGen.switchTab: { + switchTab(action.payload.tab) + break + } + case RemoteGen.setCriticalUpdate: { + storeRegistry.getState('fs').dispatch.setCriticalUpdate(action.payload.critical) + break + } + case RemoteGen.userFileEditsLoad: { + storeRegistry.getState('fs').dispatch.userFileEditsLoad() + break + } + case RemoteGen.openFilesFromWidget: { + storeRegistry.getState('fs').dispatch.dynamic.openFilesFromWidgetDesktop?.(action.payload.path) + break + } + case RemoteGen.saltpackFileOpen: { + storeRegistry.getState('deeplinks').dispatch.handleSaltPackOpen(action.payload.path) + break + } + case RemoteGen.pinentryOnCancel: { + usePinentryState.getState().dispatch.dynamic.onCancel?.() + break + } + case RemoteGen.pinentryOnSubmit: { + usePinentryState.getState().dispatch.dynamic.onSubmit?.(action.payload.password) + break + } + case RemoteGen.openPathInSystemFileManager: { + storeRegistry.getState('fs').dispatch.dynamic.openPathInSystemFileManagerDesktop?.(action.payload.path) + break + } + case RemoteGen.unlockFoldersSubmitPaperKey: { + T.RPCGen.loginPaperKeySubmitRpcPromise({paperPhrase: action.payload.paperKey}, 'unlock-folders:waiting') + .then(() => { + useConfigState.getState().dispatch.openUnlockFolders([]) + }) + .catch((e: unknown) => { + if (!(e instanceof RPCError)) return + useConfigState.setState(s => { + s.unlockFoldersError = e.desc + }) + }) + break + } + case RemoteGen.closeUnlockFolders: { + T.RPCGen.rekeyRekeyStatusFinishRpcPromise() + .then(() => {}) + .catch(() => {}) + useConfigState.getState().dispatch.openUnlockFolders([]) + break + } + case RemoteGen.stop: { + storeRegistry.getState('settings').dispatch.stop(action.payload.exitCode) + break + } + case RemoteGen.trackerChangeFollow: { + storeRegistry.getState('tracker2').dispatch.changeFollow(action.payload.guiID, action.payload.follow) + break + } + case RemoteGen.trackerIgnore: { + storeRegistry.getState('tracker2').dispatch.ignore(action.payload.guiID) + break + } + case RemoteGen.trackerCloseTracker: { + storeRegistry.getState('tracker2').dispatch.closeTracker(action.payload.guiID) + break + } + case RemoteGen.trackerLoad: { + storeRegistry.getState('tracker2').dispatch.load(action.payload) + break + } + case RemoteGen.link: + { + const {link} = action.payload + storeRegistry.getState('deeplinks').dispatch.handleAppLink(link) + } + break + case RemoteGen.installerRan: + useConfigState.getState().dispatch.installerRan() + break + case RemoteGen.updateNow: + updateApp() + break + case RemoteGen.powerMonitorEvent: + useConfigState.getState().dispatch.powerMonitorEvent(action.payload.event) + break + case RemoteGen.showMain: + useConfigState.getState().dispatch.showMain() + break + case RemoteGen.dumpLogs: + ignorePromise(useConfigState.getState().dispatch.dumpLogs(action.payload.reason)) + break + case RemoteGen.remoteWindowWantsProps: + useConfigState + .getState() + .dispatch.remoteWindowNeedsProps(action.payload.component, action.payload.param) + break + case RemoteGen.updateWindowMaxState: + useConfigState.setState(s => { + s.windowState.isMaximized = action.payload.max + }) + break + case RemoteGen.updateWindowState: + useConfigState.getState().dispatch.updateWindowState(action.payload.windowState) + break + case RemoteGen.updateWindowShown: { + const win = action.payload.component + useConfigState.setState(s => { + s.windowShownCount.set(win, (s.windowShownCount.get(win) ?? 0) + 1) + }) + break + } + case RemoteGen.previewConversation: + storeRegistry + .getState('chat') + .dispatch.previewConversation({participants: [action.payload.participant], reason: 'tracker'}) + break + } } diff --git a/shared/constants/platform-specific/index.native.tsx b/shared/constants/platform-specific/index.native.tsx index 595195b7fe7f..6fe25bc4ccb0 100644 --- a/shared/constants/platform-specific/index.native.tsx +++ b/shared/constants/platform-specific/index.native.tsx @@ -1,7 +1,14 @@ import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from '../utils' -import {storeRegistry} from '../store-registry' +import {useChatState} from '../chat2' +import {getConvoState} from '../chat2/convostate' +import {useConfigState} from '../config' import {useCurrentUserState} from '../current-user' +import {useDaemonState} from '../daemon' import {useDarkModeState} from '../darkmode' +import {useFSState} from '../fs' +import {useProfileState} from '../profile' +import {useRouterState} from '../router2' +import {useSettingsContactsState} from '../settings-contacts' import * as T from '../types' import * as Clipboard from 'expo-clipboard' import * as EngineGen from '@/actions/engine-gen-gen' @@ -31,6 +38,7 @@ import { shareListenersRegistered, } from 'react-native-kb' import {initPushListener, getStartupDetailsFromInitialPush} from './push.native' +import {initSharedSubscriptions} from './shared' import type {ImageInfo} from '@/util/expo-image-picker.native' import {noConversationIDKey} from '@/constants/types/chat2/common' @@ -201,7 +209,7 @@ const loadStartupDetails = async () => { tab = '' } - storeRegistry.getState('config').dispatch.setStartupDetails({ + useConfigState.getState().dispatch.setStartupDetails({ conversation: conversation ?? noConversationIDKey, followUser, link, @@ -210,7 +218,7 @@ const loadStartupDetails = async () => { } const setPermissionDeniedCommandStatus = (conversationIDKey: T.Chat.ConversationIDKey, text: string) => { - storeRegistry.getConvoState(conversationIDKey).dispatch.setCommandStatusInfo({ + getConvoState(conversationIDKey).dispatch.setCommandStatusInfo({ actions: [T.RPCChat.UICommandStatusActionTyp.appsettings], displayText: text, displayType: T.RPCChat.UICommandStatusDisplayTyp.error, @@ -296,7 +304,7 @@ const ensureBackgroundTask = () => { lon: pos?.coords.longitude ?? 0, } - storeRegistry.getState('chat').dispatch.updateLastCoord(coord) + useChatState.getState().dispatch.updateLastCoord(coord) return Promise.resolve() }) } @@ -321,7 +329,7 @@ export const watchPositionForMap = async (conversationIDKey: T.Chat.Conversation lat: location.coords.latitude, lon: location.coords.longitude, } - storeRegistry.getState('chat').dispatch.updateLastCoord(coord) + useChatState.getState().dispatch.updateLastCoord(coord) } ) return () => sub.remove() @@ -335,10 +343,10 @@ export const watchPositionForMap = async (conversationIDKey: T.Chat.Conversation export const initPlatformListener = () => { let _lastPersist = '' - storeRegistry.getStore('config').setState(s => { + useConfigState.setState(s => { s.dispatch.dynamic.persistRoute = wrapErrors((path?: ReadonlyArray) => { const f = async () => { - if (!storeRegistry.getState('config').startup.loaded) { + if (!useConfigState.getState().startup.loaded) { return } let param = {} @@ -380,7 +388,7 @@ export const initPlatformListener = () => { }) }) - storeRegistry.getStore('config').subscribe((s, old) => { + useConfigState.subscribe((s, old) => { if (s.mobileAppState === old.mobileAppState) return let appFocused: boolean let logState: T.RPCGen.MobileAppState @@ -403,10 +411,10 @@ export const initPlatformListener = () => { } logger.info(`setting app state on service to: ${logState}`) - storeRegistry.getState('config').dispatch.changedFocus(appFocused) + s.dispatch.changedFocus(appFocused) }) - storeRegistry.getStore('config').setState(s => { + useConfigState.setState(s => { s.dispatch.dynamic.copyToClipboard = wrapErrors((s: string) => { Clipboard.setStringAsync(s) .then(() => {}) @@ -435,7 +443,7 @@ export const initPlatformListener = () => { } } - storeRegistry.getStore('daemon').subscribe((s, old) => { + useDaemonState.subscribe((s, old) => { const versionChanged = s.handshakeVersion !== old.handshakeVersion const stateChanged = s.handshakeState !== old.handshakeState const justBecameReady = stateChanged && s.handshakeState === 'done' && old.handshakeState !== 'done' @@ -445,7 +453,7 @@ export const initPlatformListener = () => { } }) - storeRegistry.getStore('config').setState(s => { + useConfigState.setState(s => { s.dispatch.dynamic.onFilePickerError = wrapErrors((error: Error) => { Alert.alert('Error', String(error)) }) @@ -458,7 +466,7 @@ export const initPlatformListener = () => { }) }) - storeRegistry.getStore('profile').setState(s => { + useProfileState.setState(s => { s.dispatch.editAvatar = () => { const f = async () => { try { @@ -470,30 +478,28 @@ export const initPlatformListener = () => { return acc }, undefined) if (!result.canceled && first) { - storeRegistry - .getState('router') + useRouterState + .getState() .dispatch.navigateAppend({props: {image: first}, selected: 'profileEditAvatar'}) } } catch (error) { - storeRegistry.getState('config').dispatch.filePickerError(new Error(String(error))) + useConfigState.getState().dispatch.filePickerError(new Error(String(error))) } } ignorePromise(f()) } }) - storeRegistry.getStore('config').subscribe((s, old) => { + useConfigState.subscribe((s, old) => { if (s.loggedIn === old.loggedIn) return const f = async () => { const {type} = await NetInfo.fetch() - storeRegistry - .getState('config') - .dispatch.osNetworkStatusChanged(type !== NetInfo.NetInfoStateType.none, type, true) + s.dispatch.osNetworkStatusChanged(type !== NetInfo.NetInfoStateType.none, type, true) } ignorePromise(f()) }) - storeRegistry.getStore('config').subscribe((s, old) => { + useConfigState.subscribe((s, old) => { if (s.networkStatus === old.networkStatus) return const type = s.networkStatus?.type if (!type) return @@ -507,7 +513,7 @@ export const initPlatformListener = () => { ignorePromise(f()) }) - storeRegistry.getStore('config').setState(s => { + useConfigState.setState(s => { s.dispatch.dynamic.showShareActionSheet = wrapErrors( (filePath: string, message: string, mimeType: string) => { const f = async () => { @@ -518,11 +524,11 @@ export const initPlatformListener = () => { ) }) - storeRegistry.getStore('config').subscribe((s, old) => { + useConfigState.subscribe((s, old) => { if (s.mobileAppState === old.mobileAppState) return if (s.mobileAppState === 'active') { // only reload on foreground - storeRegistry.getState('settings-contacts').dispatch.loadContactPermissions() + useSettingsContactsState.getState().dispatch.loadContactPermissions() } }) @@ -530,22 +536,21 @@ export const initPlatformListener = () => { if (isAndroid) { useDarkModeState.subscribe((s, old) => { if (s.darkModePreference === old.darkModePreference) return - const {darkModePreference} = useDarkModeState.getState() - androidAppColorSchemeChanged(darkModePreference) + androidAppColorSchemeChanged(s.darkModePreference) }) } // we call this when we're logged in. let calledShareListenersRegistered = false - storeRegistry.getStore('router').subscribe((s, old) => { + useRouterState.subscribe((s, old) => { const next = s.navState const prev = old.navState if (next === prev) return const f = async () => { await timeoutPromise(1000) const path = getVisiblePath() - storeRegistry.getState('config').dispatch.dynamic.persistRoute?.(path) + useConfigState.getState().dispatch.dynamic.persistRoute?.(path) } if (!calledShareListenersRegistered && logState().loggedIn) { @@ -560,8 +565,8 @@ export const initPlatformListener = () => { initPushListener() NetInfo.addEventListener(({type}) => { - storeRegistry - .getState('config') + useConfigState + .getState() .dispatch.osNetworkStatusChanged(type !== NetInfo.NetInfoStateType.none, type) }) @@ -571,13 +576,13 @@ export const initPlatformListener = () => { initAudioModes() if (isAndroid) { - const daemonState = storeRegistry.getState('daemon') + const daemonState = useDaemonState.getState() if (daemonState.handshakeState === 'done' || daemonState.handshakeVersion > 0) { configureAndroidCacheDir() } } - storeRegistry.getStore('config').setState(s => { + useConfigState.setState(s => { s.dispatch.dynamic.openAppSettings = wrapErrors(() => { const f = async () => { if (isAndroid) { @@ -598,7 +603,7 @@ export const initPlatformListener = () => { s.dispatch.dynamic.onEngineIncomingNative = wrapErrors((action: EngineGen.Actions) => { switch (action.type) { case EngineGen.chat1ChatUiTriggerContactSync: - storeRegistry.getState('settings-contacts').dispatch.manageContactsCache() + useSettingsContactsState.getState().dispatch.manageContactsCache() break case EngineGen.keybase1LogUiLog: { const {params} = action.payload @@ -620,18 +625,20 @@ export const initPlatformListener = () => { }) }) - storeRegistry.getStore('router').setState(s => { + useRouterState.setState(s => { s.dispatch.dynamic.tabLongPress = wrapErrors((tab: string) => { if (tab !== Tabs.peopleTab) return - const accountRows = storeRegistry.getState('config').configuredAccounts + const accountRows = useConfigState.getState().configuredAccounts const current = useCurrentUserState.getState().username const row = accountRows.find(a => a.username !== current && a.hasStoredSecret) if (row) { - storeRegistry.getState('config').dispatch.setUserSwitching(true) - storeRegistry.getState('config').dispatch.login(row.username, '') + useConfigState.getState().dispatch.setUserSwitching(true) + useConfigState.getState().dispatch.login(row.username, '') } }) }) - ignorePromise(storeRegistry.getState('fs').dispatch.setupSubscriptions()) + initSharedSubscriptions() + + ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) } diff --git a/shared/constants/platform-specific/shared.tsx b/shared/constants/platform-specific/shared.tsx new file mode 100644 index 000000000000..ebf3c4317f29 --- /dev/null +++ b/shared/constants/platform-specific/shared.tsx @@ -0,0 +1,147 @@ +import type * as EngineGen from '@/actions/engine-gen-gen' +import logger from '@/logger' +import {serverConfigFileName} from '../platform' +import * as T from '../types' +import {ignorePromise} from '../utils' +import * as ArchiveUtil from '../archive/util' +import * as AutoResetUtil from '../autoreset/util' +import * as AvatarUtil from '@/common-adapters/avatar/util' +import * as BotsUtil from '../bots/util' +import {useChatState} from '../chat2' +import * as ChatUtil from '../chat2/util' +import {useConfigState} from '../config' +import {useCurrentUserState} from '../current-user' +import * as DeepLinksUtil from '../deeplinks/util' +import * as DevicesUtil from '../devices/util' +import * as FollowerUtil from '../followers/util' +import * as FSUtil from '../fs/util' +import * as GitUtil from '../git/util' +import * as NotifUtil from '../notifications/util' +import * as PeopleUtil from '../people/util' +import * as PinentryUtil from '../pinentry/util' +import {storeRegistry} from '../store-registry' +import {useSettingsContactsState} from '../settings-contacts' +import * as SettingsUtil from '../settings/util' +import * as SignupUtil from '../signup/util' +import {useTeamsState} from '../teams' +import * as TeamsUtil from '../teams/util' +import * as TrackerUtil from '../tracker2/util' +import * as UnlockFoldersUtil from '../unlock-folders/util' +import * as UsersUtil from '../users/util' + +export const initSharedSubscriptions = () => { + useConfigState.subscribe((s, old) => { + if (s.loadOnStartPhase !== old.loadOnStartPhase) { + if (s.loadOnStartPhase === 'startupOrReloginButNotInARush') { + const getFollowerInfo = () => { + const {uid} = useCurrentUserState.getState() + logger.info(`getFollowerInfo: init; uid=${uid}`) + if (uid) { + // request follower info in the background + T.RPCGen.configRequestFollowingAndUnverifiedFollowersRpcPromise() + .then(() => {}) + .catch(() => {}) + } + } + + const updateServerConfig = async () => { + if (s.loggedIn) { + try { + await T.RPCGen.configUpdateLastLoggedInAndServerConfigRpcPromise({ + serverConfigPath: serverConfigFileName, + }) + } catch {} + } + } + + const updateTeams = () => { + useTeamsState.getState().dispatch.getTeams() + useTeamsState.getState().dispatch.refreshTeamRoleMap() + } + + const updateSettings = () => { + useSettingsContactsState.getState().dispatch.loadContactImportEnabled() + } + + const updateChat = async () => { + // On login lets load the untrusted inbox. This helps make some flows easier + if (useCurrentUserState.getState().username) { + const {inboxRefresh} = useChatState.getState().dispatch + inboxRefresh('bootstrap') + } + try { + const rows = await T.RPCGen.configGuiGetValueRpcPromise({path: 'ui.inboxSmallRows'}) + const ri = rows.i ?? -1 + if (ri > 0) { + useChatState.getState().dispatch.setInboxNumSmallRows(ri, true) + } + } catch {} + } + + getFollowerInfo() + ignorePromise(updateServerConfig()) + updateTeams() + updateSettings() + ignorePromise(updateChat()) + } + } + + if (s.gregorReachable !== old.gregorReachable) { + // Re-get info about our account if you log in/we're done handshaking/became reachable + if (s.gregorReachable === T.RPCGen.Reachable.yes) { + // not in waiting state + if (storeRegistry.getState('daemon').handshakeWaiters.size === 0) { + ignorePromise(storeRegistry.getState('daemon').dispatch.loadDaemonBootstrapStatus()) + } + storeRegistry.getState('teams').dispatch.eagerLoadTeams() + } + } + + if (s.installerRanCount !== old.installerRanCount) { + storeRegistry.getState('fs').dispatch.checkKbfsDaemonRpcStatus() + } + + if (s.loggedIn !== old.loggedIn) { + if (s.loggedIn) { + ignorePromise(storeRegistry.getState('daemon').dispatch.loadDaemonBootstrapStatus()) + storeRegistry.getState('fs').dispatch.checkKbfsDaemonRpcStatus() + } + storeRegistry.getState('daemon').dispatch.loadDaemonAccounts() + if (!s.loggedInCausedbyStartup) { + ignorePromise(storeRegistry.getState('daemon').dispatch.refreshAccounts()) + } + } + + if (s.mobileAppState !== old.mobileAppState) { + if (s.mobileAppState === 'background' && storeRegistry.getState('chat').inboxSearch) { + storeRegistry.getState('chat').dispatch.toggleInboxSearch(false) + } + } + }) +} + +export const onEngineIncoming = (action: EngineGen.Actions) => { + ArchiveUtil.onEngineIncoming(action) + AutoResetUtil.onEngineIncoming(action) + AvatarUtil.onEngineIncoming(action) + BotsUtil.onEngineIncoming(action) + ChatUtil.onEngineIncoming(action) + storeRegistry.getState('config').dispatch.dynamic.onEngineIncomingDesktop?.(action) + storeRegistry.getState('config').dispatch.dynamic.onEngineIncomingNative?.(action) + storeRegistry.getState('config').dispatch.onEngineIncoming(action) + DeepLinksUtil.onEngineIncoming(action) + DevicesUtil.onEngineIncoming(action) + FollowerUtil.onEngineIncoming(action) + FSUtil.onEngineIncoming(action) + GitUtil.onEngineIncoming(action) + NotifUtil.onEngineIncoming(action) + PeopleUtil.onEngineIncoming(action) + PinentryUtil.onEngineIncoming(action) + SettingsUtil.onEngineIncoming(action) + SignupUtil.onEngineIncoming(action) + TeamsUtil.onEngineIncoming(action) + TrackerUtil.onEngineIncoming(action) + UnlockFoldersUtil.onEngineIncoming(action) + UsersUtil.onEngineIncoming(action) +} + diff --git a/shared/desktop/renderer/main2.desktop.tsx b/shared/desktop/renderer/main2.desktop.tsx index 969a0917143b..1f5a194af580 100644 --- a/shared/desktop/renderer/main2.desktop.tsx +++ b/shared/desktop/renderer/main2.desktop.tsx @@ -8,12 +8,11 @@ import type * as RemoteGen from '@/actions/remote-gen' import Root from './container.desktop' import {makeEngine} from '@/engine' import {disableDragDrop} from '@/util/drag-drop.desktop' -import {dumpLogs} from '@/constants/platform-specific/index.desktop' +import {dumpLogs, eventFromRemoteWindows} from '@/constants/platform-specific/index.desktop' import {initDesktopStyles} from '@/styles/index.desktop' import {isWindows} from '@/constants/platform' import KB2 from '@/util/electron.desktop' import {debugWarning} from '@/util/debug-warning' -import {useConfigState} from '@/constants/config' import type {default as NewMainType} from '../../app/main.desktop' import {setServiceDecoration} from '@/common-adapters/markdown/react' import ServiceDecoration from '@/common-adapters/markdown/service-decoration' @@ -58,7 +57,7 @@ const setupApp = () => { ipcRendererOn?.('KBdispatchAction', (_: unknown, action: unknown) => { setTimeout(() => { try { - useConfigState.getState().dispatch.eventFromRemoteWindows(action as RemoteGen.Actions) + eventFromRemoteWindows(action as RemoteGen.Actions) } catch {} }, 0) }) diff --git a/shared/devices/device-revoke.tsx b/shared/devices/device-revoke.tsx index 374bc6d13354..0d4ead70adde 100644 --- a/shared/devices/device-revoke.tsx +++ b/shared/devices/device-revoke.tsx @@ -97,7 +97,7 @@ const useRevoke = (deviceID = '') => { try { await T.RPCGen.loginDeprovisionRpcPromise({doRevoke: true, username}, C.waitingKeyDevices) load() - useConfigState.getState().dispatch.revoke(deviceName) + useConfigState.getState().dispatch.revoke(deviceName, wasCurrentDevice) } catch {} } else { try { @@ -106,7 +106,7 @@ const useRevoke = (deviceID = '') => { C.waitingKeyDevices ) load() - useConfigState.getState().dispatch.revoke(deviceName) + useConfigState.getState().dispatch.revoke(deviceName, wasCurrentDevice) navUpToScreen( C.isMobile ? (C.isTablet ? C.Tabs.settingsTab : settingsDevicesTab) : C.Tabs.devicesTab ) From 7c4bfb15f185976e8f169503a09755eaf4e1881b Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:31:20 -0500 Subject: [PATCH 04/20] WIP: shift 8 (#28771) * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/constants/config/index.tsx | 36 +++++--- shared/constants/daemon/index.tsx | 84 ++++--------------- shared/constants/engine/index.tsx | 9 +- shared/constants/platform-specific/shared.tsx | 65 +++++++++++++- shared/constants/types/config.tsx | 1 + 5 files changed, 111 insertions(+), 84 deletions(-) diff --git a/shared/constants/config/index.tsx b/shared/constants/config/index.tsx index 01a496551e42..1501ce8e40d7 100644 --- a/shared/constants/config/index.tsx +++ b/shared/constants/config/index.tsx @@ -174,7 +174,6 @@ export interface State extends Store { setLoginError: (error?: RPCError) => void logoutAndTryToLogInAs: (username: string) => void onEngineConnected: () => void - onEngineDisonnected: () => void onEngineIncoming: (action: EngineGen.Actions) => void osNetworkStatusChanged: (online: boolean, type: T.Config.ConnectionType, isInit?: boolean) => void openUnlockFolders: (devices: ReadonlyArray) => void @@ -183,6 +182,7 @@ export interface State extends Store { remoteWindowNeedsProps: (component: string, params: string) => void resetRevokedSelf: () => void revoke: (deviceName: string, wasCurrentDevice: boolean) => void + refreshAccounts: () => Promise setAccounts: (a: Store['configuredAccounts']) => void setAndroidShare: (s: Store['androidShare']) => void setBadgeState: (b: State['badgeState']) => void @@ -488,8 +488,6 @@ export const useConfigState = Z.createZustand((set, get) => { ignorePromise(f()) }, onEngineConnected: () => { - storeRegistry.getState('daemon').dispatch.startHandshake() - // The startReachability RPC call both starts and returns the current // reachability state. Then we'll get updates of changes from this state via reachabilityChanged. // This should be run on app start and service re-connect in case the service somehow crashed or was restarted manually. @@ -517,13 +515,6 @@ export const useConfigState = Z.createZustand((set, get) => { get().dispatch.dynamic.onEngineConnectedDesktop?.() get().dispatch.loadOnStart('initialStartupAsEarlyAsPossible') }, - onEngineDisonnected: () => { - const f = async () => { - await logger.dump() - } - ignorePromise(f()) - storeRegistry.getState('daemon').dispatch.setError(new Error('Disconnected')) - }, onEngineIncoming: action => { switch (action.type) { case EngineGen.keybase1GregorUIPushState: { @@ -612,6 +603,30 @@ export const useConfigState = Z.createZustand((set, get) => { } ignorePromise(f()) }, + refreshAccounts: async () => { + const defaultUsername = get().defaultUsername + const configuredAccounts = (await T.RPCGen.loginGetConfiguredAccountsRpcPromise()) ?? [] + const {setAccounts, setDefaultUsername} = get().dispatch + + let existingDefaultFound = false as boolean + let currentName = '' + const nextConfiguredAccounts: Array = [] + + configuredAccounts.forEach(account => { + const {username, isCurrent, fullname, hasStoredSecret} = account + if (username === defaultUsername) { + existingDefaultFound = true + } + if (isCurrent) { + currentName = account.username + } + nextConfiguredAccounts.push({fullname, hasStoredSecret, username}) + }) + if (!existingDefaultFound) { + setDefaultUsername(currentName) + } + setAccounts(nextConfiguredAccounts) + }, remoteWindowNeedsProps: (component, params) => { set(s => { const map = s.remoteWindowNeedsProps.get(component) ?? new Map() @@ -650,7 +665,6 @@ export const useConfigState = Z.createZustand((set, get) => { s.justRevokedSelf = name s.revokedTrigger++ }) - storeRegistry.getState('daemon').dispatch.loadDaemonAccounts() } }, setAccounts: a => { diff --git a/shared/constants/daemon/index.tsx b/shared/constants/daemon/index.tsx index b08dff8bedc6..f87e335f757b 100644 --- a/shared/constants/daemon/index.tsx +++ b/shared/constants/daemon/index.tsx @@ -2,9 +2,6 @@ import logger from '@/logger' import {ignorePromise} from '../utils' import * as T from '../types' import * as Z from '@/util/zustand' -import {storeRegistry} from '../store-registry' -import {useCurrentUserState} from '../current-user' -import {useDarkModeState} from '../darkmode' import {maxHandshakeTries} from '../values' // Load accounts, this call can be slow so we attempt to continue w/o waiting if we determine we're logged in @@ -12,16 +9,18 @@ import {maxHandshakeTries} from '../values' const getAccountsWaitKey = 'config.getAccounts' type Store = T.Immutable<{ + bootstrapStatus?: T.RPCGen.BootstrapStatus error?: Error - handshakeState: T.Config.DaemonHandshakeState handshakeFailedReason: string handshakeRetriesLeft: number + handshakeState: T.Config.DaemonHandshakeState + handshakeVersion: number handshakeWaiters: Map // if we ever restart handshake up this so we can ignore any waiters for old things - handshakeVersion: number }> const initialStore: Store = { + bootstrapStatus: undefined, handshakeFailedReason: '', handshakeRetriesLeft: maxHandshakeTries, handshakeState: 'starting', @@ -31,9 +30,8 @@ const initialStore: Store = { export interface State extends Store { dispatch: { - loadDaemonAccounts: () => void + loadDaemonAccounts: (configuredAccountsLength: number, loggedIn: boolean, refreshAccounts: () => Promise) => void loadDaemonBootstrapStatus: () => Promise - refreshAccounts: () => Promise resetState: () => void setError: (e?: Error) => void setFailed: (r: string) => void @@ -93,7 +91,6 @@ export const useDaemonState = Z.createZustand((set, get) => { // When there are no more waiters, we can show the actual app - let _emitStartupOnLoadDaemonConnectedOnce = false const dispatch: State['dispatch'] = { daemonHandshake: version => { get().dispatch.setState('waitingForWaiters') @@ -111,22 +108,19 @@ export const useDaemonState = Z.createZustand((set, get) => { wait(name, version, true) try { await get().dispatch.loadDaemonBootstrapStatus() - useDarkModeState.getState().dispatch.loadDarkPrefs() - storeRegistry.getState('chat').dispatch.loadStaticConfig() } finally { wait(name, version, false) } } ignorePromise(f()) - get().dispatch.loadDaemonAccounts() }, daemonHandshakeDone: () => { get().dispatch.setState('done') }, - loadDaemonAccounts: () => { + loadDaemonAccounts: (configuredAccountsLength: number, loggedIn: boolean, refreshAccounts: () => Promise) => { const f = async () => { const version = get().handshakeVersion - if (storeRegistry.getState('config').configuredAccounts.length) { + if (configuredAccountsLength) { // bail on already loaded return } @@ -135,7 +129,7 @@ export const useDaemonState = Z.createZustand((set, get) => { const handshakeVersion = version // did we beat getBootstrapStatus? - if (!storeRegistry.getState('config').loggedIn) { + if (!loggedIn) { handshakeWait = true } @@ -145,7 +139,7 @@ export const useDaemonState = Z.createZustand((set, get) => { wait(getAccountsWaitKey, handshakeVersion, true) } - await get().dispatch.refreshAccounts() + await refreshAccounts() if (handshakeWait) { // someone dismissed this already? @@ -172,32 +166,22 @@ export const useDaemonState = Z.createZustand((set, get) => { const {wait} = get().dispatch const f = async () => { - const {setBootstrap} = useCurrentUserState.getState().dispatch - const {setDefaultUsername} = storeRegistry.getState('config').dispatch const s = await T.RPCGen.configGetBootstrapStatusRpcPromise() - const {userReacjis, deviceName, deviceID, uid, loggedIn, username} = s - setBootstrap({deviceID, deviceName, uid, username}) - if (username) { - setDefaultUsername(username) - } - if (loggedIn) { - storeRegistry.getState('config').dispatch.setUserSwitching(false) - } + set(state => { + state.bootstrapStatus = T.castDraft(s) + }) - logger.info(`[Bootstrap] loggedIn: ${loggedIn ? 1 : 0}`) - storeRegistry.getState('config').dispatch.setLoggedIn(loggedIn, false) - storeRegistry.getState('chat').dispatch.updateUserReacjis(userReacjis) + logger.info(`[Bootstrap] loggedIn: ${s.loggedIn ? 1 : 0}`) // set HTTP srv info if (s.httpSrvInfo) { logger.info(`[Bootstrap] http server: addr: ${s.httpSrvInfo.address} token: ${s.httpSrvInfo.token}`) - storeRegistry.getState('config').dispatch.setHTTPSrvInfo(s.httpSrvInfo.address, s.httpSrvInfo.token) } else { logger.info(`[Bootstrap] http server: no info given`) } // if we're logged in act like getAccounts is done already - if (loggedIn) { + if (s.loggedIn) { const {handshakeWaiters} = get() if (handshakeWaiters.get(getAccountsWaitKey)) { wait(getAccountsWaitKey, version, false) @@ -207,39 +191,6 @@ export const useDaemonState = Z.createZustand((set, get) => { return await f() }, onRestartHandshakeNative: _onRestartHandshakeNative, - refreshAccounts: async () => { - const configuredAccounts = (await T.RPCGen.loginGetConfiguredAccountsRpcPromise()) ?? [] - // already have one? - const {defaultUsername} = storeRegistry.getState('config') - const {setAccounts, setDefaultUsername} = storeRegistry.getState('config').dispatch - - let existingDefaultFound = false as boolean - let currentName = '' - const nextConfiguredAccounts: Array = [] - const usernameToFullname: {[username: string]: string} = {} - - configuredAccounts.forEach(account => { - const {username, isCurrent, fullname, hasStoredSecret} = account - if (username === defaultUsername) { - existingDefaultFound = true - } - if (isCurrent) { - currentName = account.username - } - nextConfiguredAccounts.push({hasStoredSecret, username}) - usernameToFullname[username] = fullname - }) - if (!existingDefaultFound) { - setDefaultUsername(currentName) - } - setAccounts(nextConfiguredAccounts) - storeRegistry.getState('users').dispatch.updates( - Object.keys(usernameToFullname).map(name => ({ - info: {fullname: usernameToFullname[name]}, - name, - })) - ) - }, resetState: () => { set(s => ({ ...s, @@ -270,13 +221,6 @@ export const useDaemonState = Z.createZustand((set, get) => { set(s => { s.handshakeState = ds }) - - if (ds !== 'done') return - - if (!_emitStartupOnLoadDaemonConnectedOnce) { - _emitStartupOnLoadDaemonConnectedOnce = true - storeRegistry.getState('config').dispatch.loadOnStart('connectedToDaemonForFirstTime') - } }, startHandshake: () => { get().dispatch.setError() diff --git a/shared/constants/engine/index.tsx b/shared/constants/engine/index.tsx index 9b8a73cf31cd..167add4ebbe4 100644 --- a/shared/constants/engine/index.tsx +++ b/shared/constants/engine/index.tsx @@ -6,8 +6,10 @@ import * as PeopleUtil from '../people/util' import * as PinentryUtil from '../pinentry/util' import {onEngineIncoming as onEngineIncomingShared} from '../platform-specific/shared' import {storeRegistry} from '../store-registry' +import {ignorePromise} from '../utils' import * as TrackerUtil from '../tracker2/util' import * as UnlockFoldersUtil from '../unlock-folders/util' +import logger from '@/logger' type Store = object const initialStore: Store = {} @@ -27,6 +29,7 @@ export const useEngineState = Z.createZustand(set => { onEngineConnected: () => { ChatUtil.onEngineConnected() storeRegistry.getState('config').dispatch.onEngineConnected() + storeRegistry.getState('daemon').dispatch.startHandshake() NotifUtil.onEngineConnected() PeopleUtil.onEngineConnected() PinentryUtil.onEngineConnected() @@ -34,7 +37,11 @@ export const useEngineState = Z.createZustand(set => { UnlockFoldersUtil.onEngineConnected() }, onEngineDisconnected: () => { - storeRegistry.getState('config').dispatch.onEngineDisonnected() + const f = async () => { + await logger.dump() + } + ignorePromise(f()) + storeRegistry.getState('daemon').dispatch.setError(new Error('Disconnected')) }, onEngineIncoming: action => { // defer a frame so its more like before diff --git a/shared/constants/platform-specific/shared.tsx b/shared/constants/platform-specific/shared.tsx index ebf3c4317f29..6f40376b42f5 100644 --- a/shared/constants/platform-specific/shared.tsx +++ b/shared/constants/platform-specific/shared.tsx @@ -11,6 +11,8 @@ import {useChatState} from '../chat2' import * as ChatUtil from '../chat2/util' import {useConfigState} from '../config' import {useCurrentUserState} from '../current-user' +import {useDaemonState} from '../daemon' +import {useDarkModeState} from '../darkmode' import * as DeepLinksUtil from '../deeplinks/util' import * as DevicesUtil from '../devices/util' import * as FollowerUtil from '../followers/util' @@ -29,6 +31,8 @@ import * as TrackerUtil from '../tracker2/util' import * as UnlockFoldersUtil from '../unlock-folders/util' import * as UsersUtil from '../users/util' +let _emitStartupOnLoadDaemonConnectedOnce = false + export const initSharedSubscriptions = () => { useConfigState.subscribe((s, old) => { if (s.loadOnStartPhase !== old.loadOnStartPhase) { @@ -106,9 +110,9 @@ export const initSharedSubscriptions = () => { ignorePromise(storeRegistry.getState('daemon').dispatch.loadDaemonBootstrapStatus()) storeRegistry.getState('fs').dispatch.checkKbfsDaemonRpcStatus() } - storeRegistry.getState('daemon').dispatch.loadDaemonAccounts() + storeRegistry.getState('daemon').dispatch.loadDaemonAccounts(s.configuredAccounts.length, s.loggedIn, storeRegistry.getState('config').dispatch.refreshAccounts) if (!s.loggedInCausedbyStartup) { - ignorePromise(storeRegistry.getState('daemon').dispatch.refreshAccounts()) + ignorePromise(storeRegistry.getState('config').dispatch.refreshAccounts()) } } @@ -117,6 +121,63 @@ export const initSharedSubscriptions = () => { storeRegistry.getState('chat').dispatch.toggleInboxSearch(false) } } + + if (s.revokedTrigger !== old.revokedTrigger) { + storeRegistry.getState('daemon').dispatch.loadDaemonAccounts(s.configuredAccounts.length, s.loggedIn, storeRegistry.getState('config').dispatch.refreshAccounts) + } + }) + + useDaemonState.subscribe((s, old) => { + if (s.handshakeVersion !== old.handshakeVersion) { + useDarkModeState.getState().dispatch.loadDarkPrefs() + storeRegistry.getState('chat').dispatch.loadStaticConfig() + const configState = storeRegistry.getState('config') + s.dispatch.loadDaemonAccounts(configState.configuredAccounts.length, configState.loggedIn, storeRegistry.getState('config').dispatch.refreshAccounts) + } + + if (s.bootstrapStatus !== old.bootstrapStatus) { + const bootstrap = s.bootstrapStatus + if (bootstrap) { + const {deviceID, deviceName, loggedIn, uid, username, userReacjis} = bootstrap + useCurrentUserState.getState().dispatch.setBootstrap({deviceID, deviceName, uid, username}) + + const configDispatch = storeRegistry.getState('config').dispatch + if (username) { + configDispatch.setDefaultUsername(username) + } + if (loggedIn) { + configDispatch.setUserSwitching(false) + } + configDispatch.setLoggedIn(loggedIn, false) + + if (bootstrap.httpSrvInfo) { + configDispatch.setHTTPSrvInfo(bootstrap.httpSrvInfo.address, bootstrap.httpSrvInfo.token) + } + + storeRegistry.getState('chat').dispatch.updateUserReacjis(userReacjis) + } + } + + if (s.handshakeState !== old.handshakeState) { + if (s.handshakeState === 'done') { + if (!_emitStartupOnLoadDaemonConnectedOnce) { + _emitStartupOnLoadDaemonConnectedOnce = true + storeRegistry.getState('config').dispatch.loadOnStart('connectedToDaemonForFirstTime') + } + } + } + }) + + useConfigState.subscribe((s, old) => { + if (s.configuredAccounts !== old.configuredAccounts) { + const updates = s.configuredAccounts.map(account => ({ + info: {fullname: account.fullname ?? ''}, + name: account.username, + })) + if (updates.length > 0) { + storeRegistry.getState('users').dispatch.updates(updates) + } + } }) } diff --git a/shared/constants/types/config.tsx b/shared/constants/types/config.tsx index e001a72201e9..fdebccf3474d 100644 --- a/shared/constants/types/config.tsx +++ b/shared/constants/types/config.tsx @@ -8,6 +8,7 @@ export type OutOfDate = { } export type DaemonHandshakeState = 'starting' | 'waitingForWaiters' | 'done' export type ConfiguredAccount = { + fullname?: string hasStoredSecret: boolean username: string } From 9dca46ea3866a8957a77dfa2d56baff285e7d12b Mon Sep 17 00:00:00 2001 From: Chris Nojima Date: Wed, 7 Jan 2026 14:39:18 -0500 Subject: [PATCH 05/20] WIP --- shared/constants/platform-specific/index.desktop.tsx | 6 ------ shared/constants/platform-specific/index.native.tsx | 9 ++++++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/shared/constants/platform-specific/index.desktop.tsx b/shared/constants/platform-specific/index.desktop.tsx index 50fca882c4ef..eef15f0e977b 100644 --- a/shared/constants/platform-specific/index.desktop.tsx +++ b/shared/constants/platform-specific/index.desktop.tsx @@ -25,7 +25,6 @@ import {initSharedSubscriptions} from './shared' import {switchTab} from '../router2/util' import {storeRegistry} from '../store-registry' import {wrapErrors} from '@/util/debug' -import {getSelectedConversation} from '@/constants/chat2/common' const {showMainWindow, activeChanged, requestWindowsStartService, dumpNodeLogger} = KB2.functions const {quitApp, exitApp, setOpenAtLogin, ctlQuit, copyToClipboard} = KB2.functions @@ -164,11 +163,6 @@ export const initPlatformListener = () => { if (s.appFocused !== old.appFocused) { maybePauseVideos() - if (!old.appFocused && s.appFocused) { - const {dispatch} = storeRegistry.getConvoState(getSelectedConversation()) - dispatch.loadMoreMessages({reason: 'foregrounding'}) - dispatch.markThreadAsRead() - } } if (s.openAtLogin !== old.openAtLogin) { diff --git a/shared/constants/platform-specific/index.native.tsx b/shared/constants/platform-specific/index.native.tsx index 6fe25bc4ccb0..ba779dec92cd 100644 --- a/shared/constants/platform-specific/index.native.tsx +++ b/shared/constants/platform-specific/index.native.tsx @@ -40,7 +40,8 @@ import { import {initPushListener, getStartupDetailsFromInitialPush} from './push.native' import {initSharedSubscriptions} from './shared' import type {ImageInfo} from '@/util/expo-image-picker.native' -import {noConversationIDKey} from '@/constants/types/chat2/common' +import {noConversationIDKey, getSelectedConversation} from '@/constants/types/chat2/common' +import {storeRegistry} from '../store-registry' export const requestPermissionsToWrite = async () => { if (isAndroid) { @@ -412,6 +413,12 @@ export const initPlatformListener = () => { logger.info(`setting app state on service to: ${logState}`) s.dispatch.changedFocus(appFocused) + + if (appFocused && old.mobileAppState !== 'active') { + const {dispatch} = storeRegistry.getConvoState(getSelectedConversation()) + dispatch.loadMoreMessages({reason: 'foregrounding'}) + dispatch.markThreadAsRead() + } }) useConfigState.setState(s => { From 10bd236ff5e6cc73461252a7fb6f13b8d8926620 Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Wed, 7 Jan 2026 14:56:42 -0500 Subject: [PATCH 06/20] WIP --- shared/constants/platform-specific/index.native.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/shared/constants/platform-specific/index.native.tsx b/shared/constants/platform-specific/index.native.tsx index ba779dec92cd..b3b45046629c 100644 --- a/shared/constants/platform-specific/index.native.tsx +++ b/shared/constants/platform-specific/index.native.tsx @@ -40,7 +40,8 @@ import { import {initPushListener, getStartupDetailsFromInitialPush} from './push.native' import {initSharedSubscriptions} from './shared' import type {ImageInfo} from '@/util/expo-image-picker.native' -import {noConversationIDKey, getSelectedConversation} from '@/constants/types/chat2/common' +import {noConversationIDKey} from '@/constants/types/chat2/common' +import {getSelectedConversation} from '@/constants/chat2/common' import {storeRegistry} from '../store-registry' export const requestPermissionsToWrite = async () => { @@ -572,9 +573,7 @@ export const initPlatformListener = () => { initPushListener() NetInfo.addEventListener(({type}) => { - useConfigState - .getState() - .dispatch.osNetworkStatusChanged(type !== NetInfo.NetInfoStateType.none, type) + useConfigState.getState().dispatch.osNetworkStatusChanged(type !== NetInfo.NetInfoStateType.none, type) }) const initAudioModes = () => { From 90f2d32f9cd7de3bb57588513d4119af84f0ba3a Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Wed, 7 Jan 2026 15:00:33 -0500 Subject: [PATCH 07/20] WIP --- shared/constants/platform-specific/shared.tsx | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/shared/constants/platform-specific/shared.tsx b/shared/constants/platform-specific/shared.tsx index 6f40376b42f5..ed3a135c1de9 100644 --- a/shared/constants/platform-specific/shared.tsx +++ b/shared/constants/platform-specific/shared.tsx @@ -110,7 +110,13 @@ export const initSharedSubscriptions = () => { ignorePromise(storeRegistry.getState('daemon').dispatch.loadDaemonBootstrapStatus()) storeRegistry.getState('fs').dispatch.checkKbfsDaemonRpcStatus() } - storeRegistry.getState('daemon').dispatch.loadDaemonAccounts(s.configuredAccounts.length, s.loggedIn, storeRegistry.getState('config').dispatch.refreshAccounts) + storeRegistry + .getState('daemon') + .dispatch.loadDaemonAccounts( + s.configuredAccounts.length, + s.loggedIn, + storeRegistry.getState('config').dispatch.refreshAccounts + ) if (!s.loggedInCausedbyStartup) { ignorePromise(storeRegistry.getState('config').dispatch.refreshAccounts()) } @@ -123,7 +129,23 @@ export const initSharedSubscriptions = () => { } if (s.revokedTrigger !== old.revokedTrigger) { - storeRegistry.getState('daemon').dispatch.loadDaemonAccounts(s.configuredAccounts.length, s.loggedIn, storeRegistry.getState('config').dispatch.refreshAccounts) + storeRegistry + .getState('daemon') + .dispatch.loadDaemonAccounts( + s.configuredAccounts.length, + s.loggedIn, + storeRegistry.getState('config').dispatch.refreshAccounts + ) + } + + if (s.configuredAccounts !== old.configuredAccounts) { + const updates = s.configuredAccounts.map(account => ({ + info: {fullname: account.fullname ?? ''}, + name: account.username, + })) + if (updates.length > 0) { + storeRegistry.getState('users').dispatch.updates(updates) + } } }) @@ -132,7 +154,11 @@ export const initSharedSubscriptions = () => { useDarkModeState.getState().dispatch.loadDarkPrefs() storeRegistry.getState('chat').dispatch.loadStaticConfig() const configState = storeRegistry.getState('config') - s.dispatch.loadDaemonAccounts(configState.configuredAccounts.length, configState.loggedIn, storeRegistry.getState('config').dispatch.refreshAccounts) + s.dispatch.loadDaemonAccounts( + configState.configuredAccounts.length, + configState.loggedIn, + storeRegistry.getState('config').dispatch.refreshAccounts + ) } if (s.bootstrapStatus !== old.bootstrapStatus) { @@ -167,18 +193,6 @@ export const initSharedSubscriptions = () => { } } }) - - useConfigState.subscribe((s, old) => { - if (s.configuredAccounts !== old.configuredAccounts) { - const updates = s.configuredAccounts.map(account => ({ - info: {fullname: account.fullname ?? ''}, - name: account.username, - })) - if (updates.length > 0) { - storeRegistry.getState('users').dispatch.updates(updates) - } - } - }) } export const onEngineIncoming = (action: EngineGen.Actions) => { @@ -205,4 +219,3 @@ export const onEngineIncoming = (action: EngineGen.Actions) => { UnlockFoldersUtil.onEngineIncoming(action) UsersUtil.onEngineIncoming(action) } - From 77bcd532e0c6fa2365c922e6271492445138bd38 Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Thu, 8 Jan 2026 21:28:45 -0500 Subject: [PATCH 08/20] WIP2: shift 9 (#28776) * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/app/index.native.tsx | 13 +- .../input-area/location-popup.d.ts | 3 + .../input-area/location-popup.desktop.tsx | 2 + ...on-popup.tsx => location-popup.native.tsx} | 54 +- ...nu-popup.tsx => moremenu-popup.native.tsx} | 0 .../normal2/platform-input.native.tsx | 2 +- .../markdown/service-decoration.tsx | 5 +- shared/constants/chat2/common.tsx | 3 +- shared/constants/chat2/convostate.tsx | 13 +- shared/constants/chat2/index.tsx | 31 +- shared/constants/config/index.tsx | 11 +- shared/constants/deeplinks/index.tsx | 389 ++++++------- shared/constants/deeplinks/util.tsx | 4 +- shared/constants/engine/index.tsx | 62 -- shared/constants/fs/index.tsx | 5 +- .../fs/platform-specific.desktop.tsx | 6 +- shared/constants/git/index.tsx | 3 +- shared/constants/init.d.ts | 5 + shared/constants/init.desktop.tsx | 275 +++++++++ shared/constants/init.native.tsx | 506 ++++++++++++++++ shared/constants/notifications/index.tsx | 11 +- shared/constants/people/index.tsx | 4 +- shared/constants/platform-specific/index.d.ts | 1 - .../platform-specific/index.desktop.tsx | 277 +-------- .../platform-specific/index.native.tsx | 543 +----------------- .../platform-specific/push.native.tsx | 7 +- shared/constants/platform-specific/shared.tsx | 64 ++- shared/constants/profile/index.tsx | 15 +- shared/constants/provision/index.tsx | 83 ++- shared/constants/push.native.tsx | 9 +- shared/constants/recover-password/index.tsx | 3 +- shared/constants/settings-chat/index.tsx | 10 +- shared/constants/settings-contacts.native.tsx | 14 +- shared/constants/settings/index.tsx | 11 +- shared/constants/signup/index.tsx | 3 +- shared/constants/store-registry.tsx | 32 -- shared/constants/team-building/index.tsx | 3 +- shared/constants/teams/index.tsx | 19 +- shared/constants/tracker2/index.tsx | 12 +- shared/constants/unlock-folders/index.tsx | 7 +- shared/constants/wallets/index.tsx | 4 +- shared/deeplinks/error.tsx | 11 +- shared/desktop/renderer/main2.desktop.tsx | 2 +- shared/engine/index-impl.tsx | 14 +- shared/provision/username-or-email.tsx | 9 +- shared/router-v2/hooks.native.tsx | 4 +- 46 files changed, 1254 insertions(+), 1310 deletions(-) create mode 100644 shared/chat/conversation/input-area/location-popup.d.ts create mode 100644 shared/chat/conversation/input-area/location-popup.desktop.tsx rename shared/chat/conversation/input-area/{location-popup.tsx => location-popup.native.tsx} (73%) rename shared/chat/conversation/input-area/normal2/{moremenu-popup.tsx => moremenu-popup.native.tsx} (100%) delete mode 100644 shared/constants/engine/index.tsx create mode 100644 shared/constants/init.d.ts create mode 100644 shared/constants/init.desktop.tsx create mode 100644 shared/constants/init.native.tsx diff --git a/shared/app/index.native.tsx b/shared/app/index.native.tsx index 4e2aae6b48eb..ba51cb977b5d 100644 --- a/shared/app/index.native.tsx +++ b/shared/app/index.native.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import {useConfigState} from '@/constants/config' import * as Kb from '@/common-adapters' import * as React from 'react' -import {useDeepLinksState} from '@/constants/deeplinks' +import {handleAppLink} from '@/constants/deeplinks' import Main from './main.native' import {KeyboardProvider} from 'react-native-keyboard-controller' import Animated, {ReducedMotionConfig, ReduceMotion} from 'react-native-reanimated' @@ -18,9 +18,9 @@ import ServiceDecoration from '@/common-adapters/markdown/service-decoration' import {useUnmountAll} from '@/util/debug-react' import {darkModeSupported, guiConfig} from 'react-native-kb' import {install} from 'react-native-kb' -import {useEngineState} from '@/constants/engine' import * as DarkMode from '@/constants/darkmode' -import {initPlatformListener} from '@/constants/platform-specific' +import {onEngineConnected, onEngineDisconnected} from '@/constants/platform-specific/shared' +import {initPlatformListener} from '@/constants/init' enableFreeze(true) setServiceDecoration(ServiceDecoration) @@ -107,7 +107,6 @@ const StoreHelper = (p: {children: React.ReactNode}): React.ReactNode => { const {children} = p useDarkHookup() useKeyboardHookup() - const handleAppLink = useDeepLinksState(s => s.dispatch.handleAppLink) React.useEffect(() => { const linkingSub = Linking.addEventListener('url', ({url}: {url: string}) => { @@ -116,7 +115,7 @@ const StoreHelper = (p: {children: React.ReactNode}): React.ReactNode => { return () => { linkingSub.remove() } - }, [handleAppLink]) + }, []) return children } @@ -136,9 +135,9 @@ const useInit = () => { const {batch} = C.useWaitingState.getState().dispatch const eng = makeEngine(batch, c => { if (c) { - useEngineState.getState().dispatch.onEngineConnected() + onEngineConnected() } else { - useEngineState.getState().dispatch.onEngineDisconnected() + onEngineDisconnected() } }) initPlatformListener() diff --git a/shared/chat/conversation/input-area/location-popup.d.ts b/shared/chat/conversation/input-area/location-popup.d.ts new file mode 100644 index 000000000000..251868e41272 --- /dev/null +++ b/shared/chat/conversation/input-area/location-popup.d.ts @@ -0,0 +1,3 @@ +import type * as React from 'react' +declare const LocationPopup: () => React.ReactNode +export default LocationPopup diff --git a/shared/chat/conversation/input-area/location-popup.desktop.tsx b/shared/chat/conversation/input-area/location-popup.desktop.tsx new file mode 100644 index 000000000000..c07558b9f77f --- /dev/null +++ b/shared/chat/conversation/input-area/location-popup.desktop.tsx @@ -0,0 +1,2 @@ +const LocationPopup = () => null +export default LocationPopup diff --git a/shared/chat/conversation/input-area/location-popup.tsx b/shared/chat/conversation/input-area/location-popup.native.tsx similarity index 73% rename from shared/chat/conversation/input-area/location-popup.tsx rename to shared/chat/conversation/input-area/location-popup.native.tsx index fff570f758c7..1225ddfcd0eb 100644 --- a/shared/chat/conversation/input-area/location-popup.tsx +++ b/shared/chat/conversation/input-area/location-popup.native.tsx @@ -2,10 +2,52 @@ import * as C from '@/constants' import * as Chat from '@/constants/chat2' import * as React from 'react' import {useConfigState} from '@/constants/config' +import logger from '@/logger' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import LocationMap from '@/chat/location-map' import {useCurrentUserState} from '@/constants/current-user' +import {requestLocationPermission} from '@/constants/platform-specific' +import * as ExpoLocation from 'expo-location' + +const useWatchPosition = (conversationIDKey: T.Chat.ConversationIDKey) => { + const updateLastCoord = Chat.useChatState(s => s.dispatch.updateLastCoord) + const setCommandStatusInfo = Chat.useChatContext(s => s.dispatch.setCommandStatusInfo) + React.useEffect(() => { + let unsub = () => {} + logger.info('[location] perms check due to map') + const f = async () => { + try { + await requestLocationPermission(T.RPCChat.UIWatchPositionPerm.base) + const sub = await ExpoLocation.watchPositionAsync( + {accuracy: ExpoLocation.LocationAccuracy.Highest}, + (location: ExpoLocation.LocationObject) => { + const coord = { + accuracy: Math.floor(location.coords.accuracy ?? 0), + lat: location.coords.latitude, + lon: location.coords.longitude, + } + updateLastCoord(coord) + } + ) + unsub = () => sub.remove() + } catch (_error) { + const error = _error as {message?: string} + logger.info('failed to get location: ' + error.message) + setCommandStatusInfo({ + actions: [T.RPCChat.UICommandStatusActionTyp.appsettings], + displayText: `Failed to access location. ${error.message}`, + displayType: T.RPCChat.UICommandStatusDisplayTyp.error, + }) + } + } + + C.ignorePromise(f()) + return () => { + unsub() + } + }, [conversationIDKey, updateLastCoord, setCommandStatusInfo]) +} const LocationPopup = () => { const conversationIDKey = Chat.useChatContext(s => s.id) @@ -27,17 +69,7 @@ const LocationPopup = () => { sendMessage(duration ? `/location live ${duration}` : '/location') } - React.useEffect(() => { - let unwatch: undefined | (() => void) - C.PlatformSpecific.watchPositionForMap(conversationIDKey) - .then(unsub => { - unwatch = unsub - }) - .catch(() => {}) - return () => { - unwatch?.() - } - }, [conversationIDKey]) + useWatchPosition(conversationIDKey) const width = Math.ceil(Kb.Styles.dimensionWidth) const height = Math.ceil(Kb.Styles.dimensionHeight - 320) diff --git a/shared/chat/conversation/input-area/normal2/moremenu-popup.tsx b/shared/chat/conversation/input-area/normal2/moremenu-popup.native.tsx similarity index 100% rename from shared/chat/conversation/input-area/normal2/moremenu-popup.tsx rename to shared/chat/conversation/input-area/normal2/moremenu-popup.native.tsx diff --git a/shared/chat/conversation/input-area/normal2/platform-input.native.tsx b/shared/chat/conversation/input-area/normal2/platform-input.native.tsx index 4194566d7d99..134412c3846e 100644 --- a/shared/chat/conversation/input-area/normal2/platform-input.native.tsx +++ b/shared/chat/conversation/input-area/normal2/platform-input.native.tsx @@ -5,7 +5,7 @@ import * as React from 'react' import AudioRecorder from '@/chat/audio/audio-recorder.native' import FilePickerPopup from '../filepicker-popup' import {onHWKeyPressed, removeOnHWKeyPressed} from 'react-native-kb' -import MoreMenuPopup from './moremenu-popup' +import MoreMenuPopup from './moremenu-popup.native' import SetExplodingMessagePicker from './set-explode-popup' import Typing from './typing' import type * as ImagePicker from 'expo-image-picker' diff --git a/shared/common-adapters/markdown/service-decoration.tsx b/shared/common-adapters/markdown/service-decoration.tsx index 9951adafed94..90879a58e0b2 100644 --- a/shared/common-adapters/markdown/service-decoration.tsx +++ b/shared/common-adapters/markdown/service-decoration.tsx @@ -1,7 +1,7 @@ import * as T from '@/constants/types' import * as React from 'react' import * as C from '@/constants' -import {useDeepLinksState} from '@/constants/deeplinks' +import {handleAppLink} from '@/constants/deeplinks' import * as Styles from '@/styles' import Channel from './channel' import KbfsPath from '@/fs/common/kbfs-path' @@ -29,10 +29,9 @@ type KeybaseLinkProps = { } const KeybaseLink = (props: KeybaseLinkProps) => { - const handleAppLink = useDeepLinksState(s => s.dispatch.handleAppLink) const onClick = React.useCallback(() => { handleAppLink(props.link) - }, [handleAppLink, props.link]) + }, [props.link]) return ( = (set, get) => { } const onClick = () => { - storeRegistry.getState('config').dispatch.showMain() + useConfigState.getState().dispatch.showMain() storeRegistry.getState('chat').dispatch.navigateToInbox() get().dispatch.navigateToThread('desktopNotification') } const onClose = () => {} logger.info('invoking NotifyPopup for chat notification') - const sound = storeRegistry.getState('config').notifySound + const sound = useConfigState.getState().notifySound const cleanBody = body.replaceAll(/!>(.*?) = (set, get) => { blockConversation: reportUser => { const f = async () => { storeRegistry.getState('chat').dispatch.navigateToInbox() - storeRegistry.getState('config').dispatch.dynamic.persistRoute?.() + useConfigState.getState().dispatch.dynamic.persistRoute?.() await T.RPCChat.localSetConversationStatusLocalRpcPromise({ conversationID: get().getConvID(), identifyBehavior: T.RPCGen.TLFIdentifyBehavior.chatGui, @@ -1754,7 +1755,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { }, markTeamAsRead: teamID => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { logger.info('bail on not logged in') return } @@ -1765,7 +1766,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { }, markThreadAsRead: force => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { logger.info('mark read bail on not logged in') return } @@ -2703,7 +2704,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { } const conversationIDKey = get().id const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { logger.info('mark unread bail on not logged in') return } diff --git a/shared/constants/chat2/index.tsx b/shared/constants/chat2/index.tsx index b0991b30975f..79cc8a00fedf 100644 --- a/shared/constants/chat2/index.tsx +++ b/shared/constants/chat2/index.tsx @@ -18,6 +18,7 @@ import isEqual from 'lodash/isEqual' import {bodyToJSON} from '../rpc-utils' import {navigateAppend, navUpToScreen, switchTab} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' import {useCurrentUserState} from '../current-user' import {useWaitingState} from '../waiting' import * as S from '../strings' @@ -527,7 +528,7 @@ export const useChatState = Z.createZustand((set, get) => { inboxRefresh: reason => { const f = async () => { const {username} = useCurrentUserState.getState() - const {loggedIn} = storeRegistry.getState('config') + const {loggedIn} = useConfigState.getState() if (!loggedIn || !username) { return } @@ -1566,12 +1567,13 @@ export const useChatState = Z.createZustand((set, get) => { const first = resultMetas[0] if (!first) { if (p.reason === 'appLink') { - storeRegistry - .getState('deeplinks') - .dispatch.setLinkError( - "We couldn't find this team chat channel. Please check that you're a member of the team and the channel exists." - ) - navigateAppend('keybaseLinkError') + navigateAppend({ + props: { + error: + "We couldn't find this team chat channel. Please check that you're a member of the team and the channel exists.", + }, + selected: 'keybaseLinkError', + }) return } else { return @@ -1595,12 +1597,13 @@ export const useChatState = Z.createZustand((set, get) => { error.code === T.RPCGen.StatusCode.scteamnotfound && reason === 'appLink' ) { - storeRegistry - .getState('deeplinks') - .dispatch.setLinkError( - "We couldn't find this team. Please check that you're a member of the team and the channel exists." - ) - navigateAppend('keybaseLinkError') + navigateAppend({ + props: { + error: + "We couldn't find this team. Please check that you're a member of the team and the channel exists.", + }, + selected: 'keybaseLinkError', + }) return } else { throw error @@ -1757,7 +1760,7 @@ export const useChatState = Z.createZustand((set, get) => { unboxRows: (ids, force) => { // We want to unbox rows that have scroll into view const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } diff --git a/shared/constants/config/index.tsx b/shared/constants/config/index.tsx index 1501ce8e40d7..f52577a959cc 100644 --- a/shared/constants/config/index.tsx +++ b/shared/constants/config/index.tsx @@ -13,8 +13,6 @@ import {defaultUseNativeFrame, isMobile} from '../platform' import {type CommonResponseHandler} from '@/engine/types' import {invalidPasswordErrorString} from './util' import {navigateAppend} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {useWhatsNewState} from '../whats-new' type Store = T.Immutable<{ forceSmallNav: boolean @@ -151,8 +149,6 @@ export interface State extends Store { openAppSettings?: () => void openAppStore?: () => void onEngineConnectedDesktop?: () => void - onEngineIncomingDesktop?: (action: EngineGen.Actions) => void - onEngineIncomingNative?: (action: EngineGen.Actions) => void persistRoute?: (path?: ReadonlyArray) => void setNavigatorExistsNative?: () => void showMainNative?: () => void @@ -265,9 +261,6 @@ export const useConfigState = Z.createZustand((set, get) => { set(s => { s.allowAnimatedEmojis = allowAnimatedEmojis }) - - const lastSeenItem = goodState.find(i => i.item.category === 'whatsNewLastSeenVersion') - useWhatsNewState.getState().dispatch.updateLastSeen(lastSeenItem) } const updateRuntimeStats = (stats?: T.RPCGen.RuntimeStats) => { @@ -305,8 +298,6 @@ export const useConfigState = Z.createZustand((set, get) => { }, dumpLogsNative: undefined, onEngineConnectedDesktop: undefined, - onEngineIncomingDesktop: undefined, - onEngineIncomingNative: undefined, onFilePickerError: undefined, openAppSettings: undefined, openAppStore: undefined, @@ -420,7 +411,7 @@ export const useConfigState = Z.createZustand((set, get) => { 'keybase.1.provisionUi.DisplayAndPromptSecret': cancelOnCallback, 'keybase.1.provisionUi.PromptNewDeviceName': (_, response) => { cancelOnCallback(undefined, response) - storeRegistry.getState('provision').dispatch.dynamic.setUsername?.(username) + navigateAppend({props: {username}, selected: 'username'}) }, 'keybase.1.provisionUi.chooseDevice': cancelOnCallback, 'keybase.1.provisionUi.chooseGPGMethod': cancelOnCallback, diff --git a/shared/constants/deeplinks/index.tsx b/shared/constants/deeplinks/index.tsx index def8e1b6cc84..97d432d954eb 100644 --- a/shared/constants/deeplinks/index.tsx +++ b/shared/constants/deeplinks/index.tsx @@ -1,7 +1,6 @@ import * as Crypto from '../crypto/util' import * as Tabs from '../tabs' import {isPathSaltpackEncrypted, isPathSaltpackSigned} from '@/util/path' -import * as Z from '@/util/zustand' import * as EngineGen from '@/actions/engine-gen-gen' import type HiddenString from '@/util/hidden-string' import URL from 'url-parse' @@ -9,11 +8,10 @@ import logger from '@/logger' import * as T from '@/constants/types' import {navigateAppend, switchTab} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useCryptoState} from '../crypto' +import {useConfigState} from '../config' const prefix = 'keybase://' -type Store = T.Immutable<{ - keybaseLinkError: string -}> export const linkFromConvAndMessage = (conv: string, messageID: number) => `${prefix}chat/${conv}/${messageID}` @@ -40,23 +38,6 @@ const validTeamnamePart = (s: string): boolean => { } const validTeamname = (s: string) => s.split('.').every(validTeamnamePart) - -const initialStore: Store = { - keybaseLinkError: '', -} - -export interface State extends Store { - dispatch: { - handleAppLink: (link: string) => void - handleKeybaseLink: (link: string) => void - handleSaltPackOpen: (_path: string | HiddenString) => void - onEngineIncomingImpl: (action: EngineGen.Actions) => void - resetState: 'default' - setLinkError: (e: string) => void - } -} - -export const useDeepLinksState = Z.createZustand((set, get) => { const handleShowUserProfileLink = (username: string) => { switchTab(Tabs.peopleTab) storeRegistry.getState('profile').dispatch.showUserProfile(username) @@ -129,209 +110,197 @@ export const useDeepLinksState = Z.createZustand((set, get) => { ) } - const dispatch: State['dispatch'] = { - handleAppLink: link => { - if (link.startsWith('keybase://')) { - get().dispatch.handleKeybaseLink(link.replace('keybase://', '')) +export const handleAppLink = (link: string) => { + if (link.startsWith('keybase://')) { + handleKeybaseLink(link.replace('keybase://', '')) + return + } else { + // Normal deeplink + const url = new URL(link) + const username = urlToUsername(url) + if (username === 'phone-app') { + const phoneState = storeRegistry.getState('settings-phone') + const phones = (phoneState as {phones?: Map}).phones + if (!phones || phones.size > 0) { return - } else { - // Normal deeplink - const url = new URL(link) - const username = urlToUsername(url) - if (username === 'phone-app') { - const phones = storeRegistry.getState('settings-phone').phones - if (!phones || phones.size > 0) { - return - } - switchTab(Tabs.settingsTab) - navigateAppend('settingsAddPhone') - } else if (username && username !== 'app') { - handleShowUserProfileLink(username) - return + } + switchTab(Tabs.settingsTab) + navigateAppend('settingsAddPhone') + } else if (username && username !== 'app') { + handleShowUserProfileLink(username) + return + } + const teamLink = urlToTeamDeepLink(url) + if (teamLink) { + handleTeamPageLink(teamLink.teamName, teamLink.action) + return + } + } +} + +export const handleKeybaseLink = (link: string) => { + if (!link) return + const error = + "We couldn't read this link. The link might be bad, or your Keybase app might be out of date and needs to be updated." + const parts = link.split('/') + // List guaranteed to contain at least one elem. + switch (parts[0]) { + case 'profile': + if (parts[1] === 'new-proof' && (parts.length === 3 || parts.length === 4)) { + parts.length === 4 && + parts[3] && + storeRegistry.getState('profile').dispatch.showUserProfile(parts[3]) + storeRegistry.getState('profile').dispatch.addProof(parts[2]!, 'appLink') + return + } else if (parts[1] === 'show' && parts.length === 3) { + // Username is basically a team name part, we can use the same logic to + // validate deep link. + const username = parts[2]! + if (username.length && validTeamnamePart(username)) { + return handleShowUserProfileLink(username) } - const teamLink = urlToTeamDeepLink(url) - if (teamLink) { - handleTeamPageLink(teamLink.teamName, teamLink.action) - return + } + break + // Fall-through + case 'private': + case 'public': + case 'team': + try { + const decoded = decodeURIComponent(link) + switchTab(Tabs.fsTab) + storeRegistry + .getState('router') + .dispatch.navigateAppend({props: {path: `/keybase/${decoded}`}, selected: 'fsRoot'}) + return + } catch { + logger.warn("Coudn't decode KBFS URI") + return + } + case 'convid': + if (parts.length === 2) { + const conversationIDKey = parts[1] + if (conversationIDKey) { + storeRegistry.getConvoState(conversationIDKey).dispatch.navigateToThread('navChanged') } + return } - }, - handleKeybaseLink: link => { - if (!link) return - const error = - "We couldn't read this link. The link might be bad, or your Keybase app might be out of date and needs to be updated." - const parts = link.split('/') - // List guaranteed to contain at least one elem. - switch (parts[0]) { - case 'profile': - if (parts[1] === 'new-proof' && (parts.length === 3 || parts.length === 4)) { - parts.length === 4 && - parts[3] && - storeRegistry.getState('profile').dispatch.showUserProfile(parts[3]) - storeRegistry.getState('profile').dispatch.addProof(parts[2]!, 'appLink') + break + case 'chat': + if (parts.length === 2 || parts.length === 3) { + if (parts[1]!.includes('#')) { + const teamChat = parts[1]!.split('#') + if (teamChat.length !== 2) { + navigateAppend({props: {error}, selected: 'keybaseLinkError'}) return - } else if (parts[1] === 'show' && parts.length === 3) { - // Username is basically a team name part, we can use the same logic to - // validate deep link. - const username = parts[2]! - if (username.length && validTeamnamePart(username)) { - return handleShowUserProfileLink(username) - } } - break - // Fall-through - case 'private': - case 'public': - case 'team': - try { - const decoded = decodeURIComponent(link) - switchTab(Tabs.fsTab) - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {path: `/keybase/${decoded}`}, selected: 'fsRoot'}) - return - } catch { - logger.warn("Coudn't decode KBFS URI") - return - } - case 'convid': - if (parts.length === 2) { - const conversationIDKey = parts[1] - if (conversationIDKey) { - storeRegistry.getConvoState(conversationIDKey).dispatch.navigateToThread('navChanged') - } + const [teamname, channelname] = teamChat + const _highlightMessageID = parseInt(parts[2]!, 10) + if (_highlightMessageID < 0) { + logger.warn(`invalid chat message id: ${_highlightMessageID}`) return } - break - case 'chat': - if (parts.length === 2 || parts.length === 3) { - if (parts[1]!.includes('#')) { - const teamChat = parts[1]!.split('#') - if (teamChat.length !== 2) { - get().dispatch.setLinkError(error) - navigateAppend('keybaseLinkError') - return - } - const [teamname, channelname] = teamChat - const _highlightMessageID = parseInt(parts[2]!, 10) - if (_highlightMessageID < 0) { - logger.warn(`invalid chat message id: ${_highlightMessageID}`) - return - } - const highlightMessageID = T.Chat.numberToMessageID(_highlightMessageID) - const {previewConversation} = storeRegistry.getState('chat').dispatch - previewConversation({ - channelname, - highlightMessageID, - reason: 'appLink', - teamname, - }) - return - } else { - const highlightMessageID = parseInt(parts[2]!, 10) - if (highlightMessageID < 0) { - logger.warn(`invalid chat message id: ${highlightMessageID}`) - return - } - const {previewConversation} = storeRegistry.getState('chat').dispatch - previewConversation({ - highlightMessageID: T.Chat.numberToMessageID(highlightMessageID), - participants: parts[1]!.split(','), - reason: 'appLink', - }) - return - } - } - break - case 'team-page': // keybase://team-page/{team_name}/{manage_settings,add_or_invite}? - if (parts.length >= 2) { - const teamName = parts[1]! - if (teamName.length && validTeamname(teamName)) { - const actionPart = parts[2] - const action = isTeamPageAction(actionPart) ? actionPart : undefined - handleTeamPageLink(teamName, action) - return - } - } - break - case 'incoming-share': - // android needs to render first when coming back - setTimeout(() => { - navigateAppend('incomingShareNew') - }, 500) - return - case 'team-invite-link': - storeRegistry.getState('teams').dispatch.openInviteLink(parts[1] ?? '', parts[2] || '') - return - case 'settingsPushPrompt': - navigateAppend('settingsPushPrompt') + const highlightMessageID = T.Chat.numberToMessageID(_highlightMessageID) + const {previewConversation} = storeRegistry.getState('chat').dispatch + previewConversation({ + channelname, + highlightMessageID, + reason: 'appLink', + teamname, + }) return - case Tabs.teamsTab: - switchTab(Tabs.teamsTab) - return - case Tabs.fsTab: - switchTab(Tabs.fsTab) - return - case Tabs.chatTab: - switchTab(Tabs.chatTab) - return - case Tabs.peopleTab: - switchTab(Tabs.peopleTab) + } else { + const highlightMessageID = parseInt(parts[2]!, 10) + if (highlightMessageID < 0) { + logger.warn(`invalid chat message id: ${highlightMessageID}`) + return + } + const {previewConversation} = storeRegistry.getState('chat').dispatch + previewConversation({ + highlightMessageID: T.Chat.numberToMessageID(highlightMessageID), + participants: parts[1]!.split(','), + reason: 'appLink', + }) return - case Tabs.settingsTab: - switchTab(Tabs.settingsTab) + } + } + break + case 'team-page': // keybase://team-page/{team_name}/{manage_settings,add_or_invite}? + if (parts.length >= 2) { + const teamName = parts[1]! + if (teamName.length && validTeamname(teamName)) { + const actionPart = parts[2] + const action = isTeamPageAction(actionPart) ? actionPart : undefined + handleTeamPageLink(teamName, action) return - default: - // Fall through to the error return below. + } } - get().dispatch.setLinkError(error) - navigateAppend('keybaseLinkError') - }, - handleSaltPackOpen: _path => { - const path = typeof _path === 'string' ? _path : _path.stringValue() + break + case 'incoming-share': + // android needs to render first when coming back + setTimeout(() => { + navigateAppend('incomingShareNew') + }, 500) + return + case 'team-invite-link': + storeRegistry.getState('teams').dispatch.openInviteLink(parts[1] ?? '', parts[2] || '') + return + case 'settingsPushPrompt': + navigateAppend('settingsPushPrompt') + return + case Tabs.teamsTab: + switchTab(Tabs.teamsTab) + return + case Tabs.fsTab: + switchTab(Tabs.fsTab) + return + case Tabs.chatTab: + switchTab(Tabs.chatTab) + return + case Tabs.peopleTab: + switchTab(Tabs.peopleTab) + return + case Tabs.settingsTab: + switchTab(Tabs.settingsTab) + return + default: + // Fall through to the error return below. + } + navigateAppend({props: {error}, selected: 'keybaseLinkError'}) +} - if (!storeRegistry.getState('config').loggedIn) { - console.warn('Tried to open a saltpack file before being logged in') - return - } - let operation: T.Crypto.Operations | undefined - if (isPathSaltpackEncrypted(path)) { - operation = Crypto.Operations.Decrypt - } else if (isPathSaltpackSigned(path)) { - operation = Crypto.Operations.Verify - } else { - logger.warn( - 'Deeplink received saltpack file path not ending in ".encrypted.saltpack" or ".signed.saltpack"' - ) - return - } - storeRegistry.getState('crypto').dispatch.onSaltpackOpenFile(operation, path) - switchTab(Tabs.cryptoTab) - }, +export const handleSaltPackOpen = (_path: string | HiddenString) => { + const path = typeof _path === 'string' ? _path : _path.stringValue() - onEngineIncomingImpl: action => { - switch (action.type) { - case EngineGen.keybase1NotifyServiceHandleKeybaseLink: { - const {link, deferred} = action.payload.params - if (deferred && !link.startsWith('keybase://team-invite-link/')) { - return - } - get().dispatch.handleKeybaseLink(link) - break - } - default: - } - }, - resetState: 'default', - setLinkError: e => { - set(s => { - s.keybaseLinkError = e - }) - }, + if (!useConfigState.getState().loggedIn) { + console.warn('Tried to open a saltpack file before being logged in') + return + } + let operation: T.Crypto.Operations | undefined + if (isPathSaltpackEncrypted(path)) { + operation = Crypto.Operations.Decrypt + } else if (isPathSaltpackSigned(path)) { + operation = Crypto.Operations.Verify + } else { + logger.warn( + 'Deeplink received saltpack file path not ending in ".encrypted.saltpack" or ".signed.saltpack"' + ) + return } - return { - ...initialStore, - dispatch, + useCryptoState.getState().dispatch.onSaltpackOpenFile(operation, path) + switchTab(Tabs.cryptoTab) +} + +export const onEngineIncomingImpl = (action: EngineGen.Actions) => { + switch (action.type) { + case EngineGen.keybase1NotifyServiceHandleKeybaseLink: { + const {link, deferred} = action.payload.params + if (deferred && !link.startsWith('keybase://team-invite-link/')) { + return + } + handleKeybaseLink(link) + break + } + default: } -}) +} diff --git a/shared/constants/deeplinks/util.tsx b/shared/constants/deeplinks/util.tsx index 7d1d3078ac54..e5f2d279fcc6 100644 --- a/shared/constants/deeplinks/util.tsx +++ b/shared/constants/deeplinks/util.tsx @@ -1,11 +1,11 @@ import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' +import {onEngineIncomingImpl} from './index' export const onEngineIncoming = (action: EngineGen.Actions) => { switch (action.type) { case EngineGen.keybase1NotifyServiceHandleKeybaseLink: { - storeRegistry.getState('deeplinks').dispatch.onEngineIncomingImpl(action) + onEngineIncomingImpl(action) } break default: diff --git a/shared/constants/engine/index.tsx b/shared/constants/engine/index.tsx deleted file mode 100644 index 167add4ebbe4..000000000000 --- a/shared/constants/engine/index.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import type * as EngineGen from '@/actions/engine-gen-gen' -import * as Z from '@/util/zustand' -import * as ChatUtil from '../chat2/util' -import * as NotifUtil from '../notifications/util' -import * as PeopleUtil from '../people/util' -import * as PinentryUtil from '../pinentry/util' -import {onEngineIncoming as onEngineIncomingShared} from '../platform-specific/shared' -import {storeRegistry} from '../store-registry' -import {ignorePromise} from '../utils' -import * as TrackerUtil from '../tracker2/util' -import * as UnlockFoldersUtil from '../unlock-folders/util' -import logger from '@/logger' - -type Store = object -const initialStore: Store = {} - -export interface State extends Store { - dispatch: { - onEngineConnected: () => void - onEngineDisconnected: () => void - onEngineIncoming: (action: EngineGen.Actions) => void - resetState: () => void - } -} - -export const useEngineState = Z.createZustand(set => { - let incomingTimeout: NodeJS.Timeout - const dispatch: State['dispatch'] = { - onEngineConnected: () => { - ChatUtil.onEngineConnected() - storeRegistry.getState('config').dispatch.onEngineConnected() - storeRegistry.getState('daemon').dispatch.startHandshake() - NotifUtil.onEngineConnected() - PeopleUtil.onEngineConnected() - PinentryUtil.onEngineConnected() - TrackerUtil.onEngineConnected() - UnlockFoldersUtil.onEngineConnected() - }, - onEngineDisconnected: () => { - const f = async () => { - await logger.dump() - } - ignorePromise(f()) - storeRegistry.getState('daemon').dispatch.setError(new Error('Disconnected')) - }, - onEngineIncoming: action => { - // defer a frame so its more like before - incomingTimeout = setTimeout(() => { - // we delegate to these utils so we don't need to load stores that we don't need yet - onEngineIncomingShared(action) - }, 0) - }, - resetState: () => { - set(s => ({...s, ...initialStore, dispatch: s.dispatch})) - clearTimeout(incomingTimeout) - }, - } - return { - ...initialStore, - dispatch, - } -}) diff --git a/shared/constants/fs/index.tsx b/shared/constants/fs/index.tsx index 16e08313c52b..afccb5d7f7bc 100644 --- a/shared/constants/fs/index.tsx +++ b/shared/constants/fs/index.tsx @@ -15,6 +15,7 @@ import isEqual from 'lodash/isEqual' import {settingsFsTab} from '../settings/util' import {navigateAppend, navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' import {useCurrentUserState} from '../current-user' export {makeActionForOpenPathInFilesTab} from './util' @@ -1582,7 +1583,7 @@ export const useFSState = Z.createZustand((set, get) => { favoritesLoad: () => { const f = async () => { try { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } const results = await T.RPCGen.SimpleFSSimpleFSListFavoritesRpcPromise() @@ -2217,7 +2218,7 @@ export const useFSState = Z.createZustand((set, get) => { src: { PathType: T.RPCGen.PathType.local, local: T.FS.getNormalizedLocalPath( - storeRegistry.getState('config').incomingShareUseOriginal + useConfigState.getState().incomingShareUseOriginal ? originalPath : scaledPath || originalPath ), diff --git a/shared/constants/fs/platform-specific.desktop.tsx b/shared/constants/fs/platform-specific.desktop.tsx index b9e372eded7c..71bee000e649 100644 --- a/shared/constants/fs/platform-specific.desktop.tsx +++ b/shared/constants/fs/platform-specific.desktop.tsx @@ -9,7 +9,7 @@ import KB2 from '@/util/electron.desktop' import {uint8ArrayToHex} from 'uint8array-extras' import {useFSState} from '.' import {navigateAppend} from '../router2/util' -import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' const {openPathInFinder, openURL, getPathType, selectFilesToUploadDialog} = KB2.functions const {darwinCopyToKBFSTempUploadFile, relaunchApp, uninstallKBFSDialog, uninstallDokanDialog} = KB2.functions @@ -133,7 +133,7 @@ const onInstallCachedDokan = async () => { } const initPlatformSpecific = () => { - storeRegistry.getStore('config').subscribe((s, old) => { + useConfigState.subscribe((s, old) => { if (s.appFocused === old.appFocused) return useFSState.getState().dispatch.onChangedFocus(s.appFocused) }) @@ -274,7 +274,7 @@ const initPlatformSpecific = () => { }) s.dispatch.dynamic.openFilesFromWidgetDesktop = wrapErrors((path: T.FS.Path) => { - storeRegistry.getState('config').dispatch.showMain() + useConfigState.getState().dispatch.showMain() if (path) { Constants.makeActionForOpenPathInFilesTab(path) } else { diff --git a/shared/constants/git/index.tsx b/shared/constants/git/index.tsx index ffe070ae3f3f..497136984873 100644 --- a/shared/constants/git/index.tsx +++ b/shared/constants/git/index.tsx @@ -6,6 +6,7 @@ import * as dateFns from 'date-fns' import * as Z from '@/util/zustand' import debounce from 'lodash/debounce' import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' const parseRepos = (results: ReadonlyArray) => { const errors: Array = [] @@ -105,7 +106,7 @@ export const useGitState = Z.createZustand((set, get) => { async () => { const results = await T.RPCGen.gitGetAllGitMetadataRpcPromise(undefined, S.waitingKeyGitLoading) const {errors, repos} = parseRepos(results || []) - const {setGlobalError} = storeRegistry.getState('config').dispatch + const {setGlobalError} = useConfigState.getState().dispatch errors.forEach(e => setGlobalError(e)) set(s => { s.idToInfo = repos diff --git a/shared/constants/init.d.ts b/shared/constants/init.d.ts new file mode 100644 index 000000000000..aa0eb1800753 --- /dev/null +++ b/shared/constants/init.d.ts @@ -0,0 +1,5 @@ +import type * as EngineGen from '@/actions/engine-gen-gen' + +export declare function initPlatformListener(): void +export declare function onEngineIncoming(action: EngineGen.Actions): void + diff --git a/shared/constants/init.desktop.tsx b/shared/constants/init.desktop.tsx new file mode 100644 index 000000000000..910c0f076402 --- /dev/null +++ b/shared/constants/init.desktop.tsx @@ -0,0 +1,275 @@ +import * as Chat from './chat2' +import {ignorePromise} from './utils' +import {useActiveState} from './active' +import {useConfigState} from './config' +import * as ConfigConstants from './config' +import {useDaemonState} from './daemon' +import {useFSState} from './fs' +import {useProfileState} from './profile' +import {useRouterState} from './router2' +import * as EngineGen from '@/actions/engine-gen-gen' +import * as T from './types' +import InputMonitor from './platform-specific/input-monitor.desktop' +import KB2 from '@/util/electron.desktop' +import logger from '@/logger' +import type {RPCError} from '@/util/errors' +import {getEngine} from '@/engine' +import {isLinux, isWindows} from './platform.desktop' +import {kbfsNotification} from './platform-specific/kbfs-notifications' +import {skipAppFocusActions} from '@/local-debug.desktop' +import NotifyPopup from '@/util/notify-popup' +import {noKBFSFailReason} from './config/util' +import {initSharedSubscriptions} from './platform-specific/shared' +import {wrapErrors} from '@/util/debug' +import {dumpLogs} from './platform-specific/index.desktop' + +const {showMainWindow, activeChanged, requestWindowsStartService} = KB2.functions +const {quitApp, exitApp, setOpenAtLogin, copyToClipboard} = KB2.functions + +const maybePauseVideos = () => { + const {appFocused} = useConfigState.getState() + const videos = document.querySelectorAll('video') + const allVideos = Array.from(videos) + + allVideos.forEach(v => { + if (appFocused) { + if (v.hasAttribute('data-focus-paused')) { + if (v.paused) { + v.play() + .then(() => {}) + .catch(() => {}) + } + } + } else { + // only pause looping videos + if (!v.paused && v.hasAttribute('loop') && v.hasAttribute('autoplay')) { + v.setAttribute('data-focus-paused', 'true') + v.pause() + } + } + }) +} + +export const onEngineIncoming = (action: EngineGen.Actions) => { + switch (action.type) { + case EngineGen.keybase1LogsendPrepareLogsend: { + const f = async () => { + const response = action.payload.response + try { + await dumpLogs() + } finally { + response.result() + } + } + ignorePromise(f()) + break + } + case EngineGen.keybase1NotifyAppExit: + console.log('App exit requested') + exitApp?.(0) + break + case EngineGen.keybase1NotifyFSFSActivity: + kbfsNotification(action.payload.params.notification, NotifyPopup) + break + case EngineGen.keybase1NotifyPGPPgpKeyInSecretStoreFile: { + const f = async () => { + try { + await T.RPCGen.pgpPgpStorageDismissRpcPromise() + } catch (err) { + console.warn('Error in sending pgpPgpStorageDismissRpc:', err) + } + } + ignorePromise(f()) + break + } + case EngineGen.keybase1NotifyServiceShutdown: { + const {code} = action.payload.params + if (isWindows && code !== (T.RPCGen.ExitCode.restart as number)) { + console.log('Quitting due to service shutdown with code: ', code) + // Quit just the app, not the service + quitApp?.() + } + break + } + + case EngineGen.keybase1LogUiLog: { + const {params} = action.payload + const {level, text} = params + logger.info('keybase.1.logUi.log:', params.text.data) + if (level >= T.RPCGen.LogLevel.error) { + NotifyPopup(text.data) + } + break + } + + case EngineGen.keybase1NotifySessionClientOutOfDate: { + const {upgradeTo, upgradeURI, upgradeMsg} = action.payload.params + const body = upgradeMsg || `Please update to ${upgradeTo} by going to ${upgradeURI}` + NotifyPopup('Client out of date!', {body}, 60 * 60) + // This is from the API server. Consider notifications from server always critical. + useConfigState + .getState() + .dispatch.setOutOfDate({critical: true, message: upgradeMsg, outOfDate: true, updating: false}) + break + } + default: + } +} + +export const initPlatformListener = () => { + useConfigState.setState(s => { + s.dispatch.dynamic.dumpLogsNative = dumpLogs + s.dispatch.dynamic.showMainNative = wrapErrors(() => showMainWindow?.()) + s.dispatch.dynamic.copyToClipboard = wrapErrors((s: string) => copyToClipboard?.(s)) + s.dispatch.dynamic.onEngineConnectedDesktop = wrapErrors(() => { + // Introduce ourselves to the service + const f = async () => { + await T.RPCGen.configHelloIAmRpcPromise({details: KB2.constants.helloDetails}) + } + ignorePromise(f()) + }) + + }) + + useConfigState.subscribe((s, old) => { + if (s.loggedIn !== old.loggedIn) { + s.dispatch.osNetworkStatusChanged(navigator.onLine, 'notavailable', true) + } + + if (s.appFocused !== old.appFocused) { + maybePauseVideos() + } + + if (s.openAtLogin !== old.openAtLogin) { + const {openAtLogin} = s + const f = async () => { + if (__DEV__) { + console.log('onSetOpenAtLogin disabled for dev mode') + return + } else { + await T.RPCGen.configGuiSetValueRpcPromise({ + path: ConfigConstants.openAtLoginKey, + value: {b: openAtLogin, isNull: false}, + }) + } + if (isLinux || isWindows) { + const enabled = + (await T.RPCGen.ctlGetOnLoginStartupRpcPromise()) === T.RPCGen.OnLoginStartupStatus.enabled + if (enabled !== openAtLogin) { + try { + await T.RPCGen.ctlSetOnLoginStartupRpcPromise({enabled: openAtLogin}) + } catch (error_) { + const error = error_ as RPCError + logger.warn(`Error in sending ctlSetOnLoginStartup: ${error.message}`) + } + } + } else { + logger.info(`Login item settings changed! now ${openAtLogin ? 'on' : 'off'}`) + await setOpenAtLogin?.(openAtLogin) + } + } + ignorePromise(f()) + } + }) + + const handleWindowFocusEvents = () => { + const handle = (appFocused: boolean) => { + if (skipAppFocusActions) { + console.log('Skipping app focus actions!') + } else { + useConfigState.getState().dispatch.changedFocus(appFocused) + } + } + window.addEventListener('focus', () => handle(true)) + window.addEventListener('blur', () => handle(false)) + } + handleWindowFocusEvents() + + const setupReachabilityWatcher = () => { + window.addEventListener('online', () => + useConfigState.getState().dispatch.osNetworkStatusChanged(true, 'notavailable') + ) + window.addEventListener('offline', () => + useConfigState.getState().dispatch.osNetworkStatusChanged(false, 'notavailable') + ) + } + setupReachabilityWatcher() + + useDaemonState.subscribe((s, old) => { + if (s.handshakeVersion !== old.handshakeVersion) { + if (!isWindows) return + + const f = async () => { + const waitKey = 'pipeCheckFail' + const version = s.handshakeVersion + const {wait} = s.dispatch + wait(waitKey, version, true) + try { + logger.info('Checking RPC ownership') + if (KB2.functions.winCheckRPCOwnership) { + await KB2.functions.winCheckRPCOwnership() + } + wait(waitKey, version, false) + } catch (error_) { + // error will be logged in bootstrap check + getEngine().reset() + const error = error_ as RPCError + wait(waitKey, version, false, error.message || 'windows pipe owner fail', true) + } + } + ignorePromise(f()) + } + + if (s.handshakeState !== old.handshakeState && s.handshakeState === 'done') { + useConfigState.getState().dispatch.setStartupDetails({ + conversation: Chat.noConversationIDKey, + followUser: '', + link: '', + tab: undefined, + }) + } + }) + + if (isLinux) { + useConfigState.getState().dispatch.initUseNativeFrame() + } + useConfigState.getState().dispatch.initNotifySound() + useConfigState.getState().dispatch.initForceSmallNav() + useConfigState.getState().dispatch.initOpenAtLogin() + useConfigState.getState().dispatch.initAppUpdateLoop() + + useProfileState.setState(s => { + s.dispatch.editAvatar = () => { + useRouterState + .getState() + .dispatch.navigateAppend({props: {image: undefined}, selected: 'profileEditAvatar'}) + } + }) + + const initializeInputMonitor = () => { + const inputMonitor = new InputMonitor() + inputMonitor.notifyActive = (userActive: boolean) => { + if (skipAppFocusActions) { + console.log('Skipping app focus actions!') + } else { + useActiveState.getState().dispatch.setActive(userActive) + // let node thread save file + activeChanged?.(Date.now(), userActive) + } + } + } + initializeInputMonitor() + + useDaemonState.setState(s => { + s.dispatch.onRestartHandshakeNative = () => { + const {handshakeFailedReason} = useDaemonState.getState() + if (isWindows && handshakeFailedReason === noKBFSFailReason) { + requestWindowsStartService?.() + } + } + }) + + initSharedSubscriptions() + + ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) +} diff --git a/shared/constants/init.native.tsx b/shared/constants/init.native.tsx new file mode 100644 index 000000000000..31ec34f7d372 --- /dev/null +++ b/shared/constants/init.native.tsx @@ -0,0 +1,506 @@ +import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from './utils' +import {useChatState} from './chat2' +import {useConfigState} from './config' +import {useCurrentUserState} from './current-user' +import {useDaemonState} from './daemon' +import {useDarkModeState} from './darkmode' +import {useFSState} from './fs' +import {useProfileState} from './profile' +import {useRouterState} from './router2' +import {useSettingsContactsState} from './settings-contacts' +import * as T from './types' +import * as Clipboard from 'expo-clipboard' +import * as EngineGen from '@/actions/engine-gen-gen' +import * as ExpoLocation from 'expo-location' +import * as ExpoTaskManager from 'expo-task-manager' +import * as Tabs from './tabs' +import * as NetInfo from '@react-native-community/netinfo' +import NotifyPopup from '@/util/notify-popup' +import logger from '@/logger' +import {Alert, Linking} from 'react-native' +import {isAndroid} from './platform.native' +import {wrapErrors} from '@/util/debug' +import {getTab, getVisiblePath, logState} from './router2' +import {launchImageLibraryAsync} from '@/util/expo-image-picker.native' +import {setupAudioMode} from '@/util/audio.native' +import { + androidOpenSettings, + fsCacheDir, + fsDownloadDir, + androidAppColorSchemeChanged, + guiConfig, + shareListenersRegistered, +} from 'react-native-kb' +import {initPushListener, getStartupDetailsFromInitialPush} from './platform-specific/push.native' +import {initSharedSubscriptions} from './platform-specific/shared' +import type {ImageInfo} from '@/util/expo-image-picker.native' +import {noConversationIDKey} from './types/chat2/common' +import {getSelectedConversation} from './chat2/common' +import {getConvoState} from './chat2/convostate' +import {requestLocationPermission, showShareActionSheet} from './platform-specific/index.native' + +const loadStartupDetails = async () => { + const [routeState, initialUrl, push] = await Promise.all([ + neverThrowPromiseFunc(async () => { + try { + const config = JSON.parse(guiConfig) as {ui?: {routeState2?: string}} | undefined + return Promise.resolve(config?.ui?.routeState2 ?? '') + } catch { + return Promise.resolve('') + } + }), + neverThrowPromiseFunc(async () => Linking.getInitialURL()), + neverThrowPromiseFunc(getStartupDetailsFromInitialPush), + ] as const) + + // Clear last value to be extra safe bad things don't hose us forever + try { + await T.RPCGen.configGuiSetValueRpcPromise({ + path: 'ui.routeState2', + value: {isNull: false, s: ''}, + }) + } catch {} + + let conversation: T.Chat.ConversationIDKey | undefined + let followUser = '' + let link = '' + let tab = '' + + // Top priority, push + if (push) { + logger.info('initialState: push', push.startupConversation, push.startupFollowUser) + conversation = push.startupConversation + followUser = push.startupFollowUser ?? '' + } else if (initialUrl) { + // Second priority, deep link + link = initialUrl + } else if (routeState) { + // Last priority, saved from last session + try { + const item = JSON.parse(routeState) as + | undefined + | {param?: {selectedConversationIDKey?: unknown}; routeName?: string} + if (item) { + const _convo = item.param?.selectedConversationIDKey || undefined + if (typeof _convo === 'string') { + conversation = _convo + logger.info('initialState: routeState', conversation) + } + const _rn = item.routeName || undefined + if (typeof _rn === 'string') { + tab = _rn as unknown as typeof tab + } + } + } catch { + logger.info('initialState: routeState parseFail') + conversation = undefined + tab = '' + } + } + + // never allow this case + if (tab === 'blank') { + tab = '' + } + + useConfigState.getState().dispatch.setStartupDetails({ + conversation: conversation ?? noConversationIDKey, + followUser, + link, + tab: tab as Tabs.Tab, + }) +} + +const locationTaskName = 'background-location-task' +let locationRefs = 0 +let madeBackgroundTask = false + +const ensureBackgroundTask = () => { + if (madeBackgroundTask) return + madeBackgroundTask = true + + ExpoTaskManager.defineTask(locationTaskName, async ({data, error}) => { + if (error) { + // check `error.message` for more details. + return Promise.resolve() + } + + if (!data) { + return Promise.resolve() + } + const d = data as {locations?: Array} + const locations = d.locations + if (!locations?.length) { + return Promise.resolve() + } + const pos = locations.at(-1) + const coord = { + accuracy: Math.floor(pos?.coords.accuracy ?? 0), + lat: pos?.coords.latitude ?? 0, + lon: pos?.coords.longitude ?? 0, + } + + useChatState.getState().dispatch.updateLastCoord(coord) + return Promise.resolve() + }) +} + +const setPermissionDeniedCommandStatus = (conversationIDKey: T.Chat.ConversationIDKey, text: string) => { + getConvoState(conversationIDKey).dispatch.setCommandStatusInfo({ + actions: [T.RPCChat.UICommandStatusActionTyp.appsettings], + displayText: text, + displayType: T.RPCChat.UICommandStatusDisplayTyp.error, + }) +} + +const onChatWatchPosition = async (action: EngineGen.Chat1ChatUiChatWatchPositionPayload) => { + const response = action.payload.response + response.result(0) + try { + await requestLocationPermission(action.payload.params.perm) + } catch (_error) { + const error = _error as {message?: string} + logger.info('failed to get location perms: ' + error.message) + setPermissionDeniedCommandStatus( + T.Chat.conversationIDToKey(action.payload.params.convID), + `Failed to access location. ${error.message}` + ) + } + + locationRefs++ + + if (locationRefs === 1) { + try { + logger.info( + '[location] location watch start due to ', + T.Chat.conversationIDToKey(action.payload.params.convID) + ) + ensureBackgroundTask() + await ExpoLocation.startLocationUpdatesAsync(locationTaskName, { + deferredUpdatesDistance: 65, + pausesUpdatesAutomatically: true, + showsBackgroundLocationIndicator: true, + }) + logger.info('[location] start success') + } catch { + logger.info('[location] start failed') + locationRefs-- + } + } +} + +const onChatClearWatch = async () => { + locationRefs-- + if (locationRefs <= 0) { + try { + logger.info('[location] end start') + ensureBackgroundTask() + await ExpoLocation.stopLocationUpdatesAsync(locationTaskName) + logger.info('[location] end success') + } catch { + logger.info('[location] end failed') + } + } +} + +export const onEngineIncoming = (action: EngineGen.Actions) => { + switch (action.type) { + case EngineGen.chat1ChatUiTriggerContactSync: + useSettingsContactsState.getState().dispatch.manageContactsCache() + break + case EngineGen.keybase1LogUiLog: { + const {params} = action.payload + const {level, text} = params + logger.info('keybase.1.logUi.log:', params.text.data) + if (level >= T.RPCGen.LogLevel.error) { + NotifyPopup(text.data) + } + break + } + case EngineGen.chat1ChatUiChatWatchPosition: + ignorePromise(onChatWatchPosition(action)) + break + case EngineGen.chat1ChatUiChatClearWatch: + ignorePromise(onChatClearWatch()) + break + default: + } +} + +export const initPlatformListener = () => { + let _lastPersist = '' + useConfigState.setState(s => { + s.dispatch.dynamic.persistRoute = wrapErrors((path?: ReadonlyArray) => { + const f = async () => { + if (!useConfigState.getState().startup.loaded) { + return + } + let param = {} + let routeName = Tabs.peopleTab + if (path) { + const cur = getTab() + if (cur) { + routeName = cur + } + const ap = getVisiblePath() + ap.some(r => { + if (r.name === 'chatConversation') { + const rParams = r.params as undefined | {conversationIDKey?: T.Chat.ConversationIDKey} + param = {selectedConversationIDKey: rParams?.conversationIDKey} + return true + } + return false + }) + } + const s = JSON.stringify({param, routeName}) + // don't keep rewriting + if (_lastPersist === s) { + return + } + _lastPersist = s + + await T.RPCGen.configGuiSetValueRpcPromise({ + path: 'ui.routeState2', + value: {isNull: false, s}, + }) + } + ignorePromise(f()) + }) + + }) + + useConfigState.subscribe((s, old) => { + if (s.mobileAppState === old.mobileAppState) return + let appFocused: boolean + let logState: T.RPCGen.MobileAppState + switch (s.mobileAppState) { + case 'active': + appFocused = true + logState = T.RPCGen.MobileAppState.foreground + break + case 'background': + appFocused = false + logState = T.RPCGen.MobileAppState.background + break + case 'inactive': + appFocused = false + logState = T.RPCGen.MobileAppState.inactive + break + default: + appFocused = false + logState = T.RPCGen.MobileAppState.foreground + } + + logger.info(`setting app state on service to: ${logState}`) + s.dispatch.changedFocus(appFocused) + + if (appFocused && old.mobileAppState !== 'active') { + const {dispatch} = getConvoState(getSelectedConversation()) + dispatch.loadMoreMessages({reason: 'foregrounding'}) + dispatch.markThreadAsRead() + } + }) + + useConfigState.setState(s => { + s.dispatch.dynamic.copyToClipboard = wrapErrors((s: string) => { + Clipboard.setStringAsync(s) + .then(() => {}) + .catch(() => {}) + }) + }) + + const configureAndroidCacheDir = () => { + if (isAndroid && fsCacheDir && fsDownloadDir) { + ignorePromise( + T.RPCChat.localConfigureFileAttachmentDownloadLocalRpcPromise({ + // Android's cache dir is (when I tried) [app]/cache but Go side uses + // [app]/.cache by default, which can't be used for sharing to other apps. + cacheDirOverride: fsCacheDir, + downloadDirOverride: fsDownloadDir, + }) + .then(() => {}) + .catch((e: unknown) => { + logger.error(`[Android cache override] Failed to configure: ${String(e)}`) + }) + ) + } else if (isAndroid) { + logger.warn( + `[Android cache override] Missing dirs - cacheDir: ${fsCacheDir}, downloadDir: ${fsDownloadDir}` + ) + } + } + + useDaemonState.subscribe((s, old) => { + const versionChanged = s.handshakeVersion !== old.handshakeVersion + const stateChanged = s.handshakeState !== old.handshakeState + const justBecameReady = stateChanged && s.handshakeState === 'done' && old.handshakeState !== 'done' + + if (versionChanged || justBecameReady) { + configureAndroidCacheDir() + } + }) + + useConfigState.setState(s => { + s.dispatch.dynamic.onFilePickerError = wrapErrors((error: Error) => { + Alert.alert('Error', String(error)) + }) + s.dispatch.dynamic.openAppStore = wrapErrors(() => { + Linking.openURL( + isAndroid + ? 'http://play.google.com/store/apps/details?id=io.keybase.ossifrage' + : 'https://itunes.apple.com/us/app/keybase-crypto-for-everyone/id1044461770?mt=8' + ).catch(() => {}) + }) + }) + + useProfileState.setState(s => { + s.dispatch.editAvatar = () => { + const f = async () => { + try { + const result = await launchImageLibraryAsync('photo') + const first = result.assets?.reduce((acc, a) => { + if (!acc && (a.type === 'image' || a.type === 'video')) { + return a as ImageInfo + } + return acc + }, undefined) + if (!result.canceled && first) { + useRouterState + .getState() + .dispatch.navigateAppend({props: {image: first}, selected: 'profileEditAvatar'}) + } + } catch (error) { + useConfigState.getState().dispatch.filePickerError(new Error(String(error))) + } + } + ignorePromise(f()) + } + }) + + useConfigState.subscribe((s, old) => { + if (s.loggedIn === old.loggedIn) return + const f = async () => { + const {type} = await NetInfo.fetch() + s.dispatch.osNetworkStatusChanged(type !== NetInfo.NetInfoStateType.none, type, true) + } + ignorePromise(f()) + }) + + useConfigState.subscribe((s, old) => { + if (s.networkStatus === old.networkStatus) return + const type = s.networkStatus?.type + if (!type) return + const f = async () => { + try { + await T.RPCGen.appStateUpdateMobileNetStateRpcPromise({state: type}) + } catch (err) { + console.warn('Error sending mobileNetStateUpdate', err) + } + } + ignorePromise(f()) + }) + + useConfigState.setState(s => { + s.dispatch.dynamic.showShareActionSheet = wrapErrors( + (filePath: string, message: string, mimeType: string) => { + const f = async () => { + await showShareActionSheet({filePath, message, mimeType}) + } + ignorePromise(f()) + } + ) + }) + + useConfigState.subscribe((s, old) => { + if (s.mobileAppState === old.mobileAppState) return + if (s.mobileAppState === 'active') { + // only reload on foreground + useSettingsContactsState.getState().dispatch.loadContactPermissions() + } + }) + + // Location + if (isAndroid) { + useDarkModeState.subscribe((s, old) => { + if (s.darkModePreference === old.darkModePreference) return + androidAppColorSchemeChanged(s.darkModePreference) + }) + } + + // we call this when we're logged in. + let calledShareListenersRegistered = false + + useRouterState.subscribe((s, old) => { + const next = s.navState + const prev = old.navState + if (next === prev) return + const f = async () => { + await timeoutPromise(1000) + const path = getVisiblePath() + useConfigState.getState().dispatch.dynamic.persistRoute?.(path) + } + + if (!calledShareListenersRegistered && logState().loggedIn) { + calledShareListenersRegistered = true + shareListenersRegistered() + } + ignorePromise(f()) + }) + + // Start this immediately instead of waiting so we can do more things in parallel + ignorePromise(loadStartupDetails()) + initPushListener() + + NetInfo.addEventListener(({type}) => { + useConfigState.getState().dispatch.osNetworkStatusChanged(type !== NetInfo.NetInfoStateType.none, type) + }) + + const initAudioModes = () => { + ignorePromise(setupAudioMode(false)) + } + initAudioModes() + + if (isAndroid) { + const daemonState = useDaemonState.getState() + if (daemonState.handshakeState === 'done' || daemonState.handshakeVersion > 0) { + configureAndroidCacheDir() + } + } + + useConfigState.setState(s => { + s.dispatch.dynamic.openAppSettings = wrapErrors(() => { + const f = async () => { + if (isAndroid) { + androidOpenSettings() + } else { + const settingsURL = 'app-settings:' + const can = await Linking.canOpenURL(settingsURL) + if (can) { + await Linking.openURL(settingsURL) + } else { + logger.warn('Unable to open app settings') + } + } + } + ignorePromise(f()) + }) + + }) + + useRouterState.setState(s => { + s.dispatch.dynamic.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) { + useConfigState.getState().dispatch.setUserSwitching(true) + useConfigState.getState().dispatch.login(row.username, '') + } + }) + }) + + initSharedSubscriptions() + + ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) +} diff --git a/shared/constants/notifications/index.tsx b/shared/constants/notifications/index.tsx index c619e197f9c4..de0802fff654 100644 --- a/shared/constants/notifications/index.tsx +++ b/shared/constants/notifications/index.tsx @@ -5,6 +5,7 @@ import {isMobile} from '../platform' import isEqual from 'lodash/isEqual' import * as Tabs from '../tabs' import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' import {useCurrentUserState} from '../current-user' export type BadgeType = 'regular' | 'update' | 'error' | 'uploading' @@ -103,16 +104,16 @@ export const useNotifState = Z.createZustand((set, get) => { onEngineIncomingImpl: action => { switch (action.type) { case EngineGen.keybase1NotifyAuditRootAuditError: - storeRegistry - .getState('config') + useConfigState + .getState() .dispatch.setGlobalError( new Error(`Keybase is buggy, please report this: ${action.payload.params.message}`) ) break case EngineGen.keybase1NotifyAuditBoxAuditError: - storeRegistry - .getState('config') + useConfigState + .getState() .dispatch.setGlobalError( new Error( `Keybase had a problem loading a team, please report this with \`keybase log send\`: ${action.payload.params.message}` @@ -121,7 +122,7 @@ export const useNotifState = Z.createZustand((set, get) => { break case EngineGen.keybase1NotifyBadgesBadgeState: { const badgeState = action.payload.params.badgeState - storeRegistry.getState('config').dispatch.setBadgeState(badgeState) + useConfigState.getState().dispatch.setBadgeState(badgeState) const counts = badgeStateToBadgeCounts(badgeState) if (!isMobile && shouldTriggerTlfLoad(badgeState)) { diff --git a/shared/constants/people/index.tsx b/shared/constants/people/index.tsx index a6f559bccc9e..7599680c75f4 100644 --- a/shared/constants/people/index.tsx +++ b/shared/constants/people/index.tsx @@ -9,7 +9,7 @@ import type {IconType} from '@/common-adapters/icon.constants-gen' // do NOT pul import {isMobile} from '../platform' import type {e164ToDisplay as e164ToDisplayType} from '@/util/phone-numbers' import debounce from 'lodash/debounce' -import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' import {useFollowerState} from '../followers' import {RPCError, isNetworkErr} from '../utils' @@ -388,7 +388,7 @@ export const usePeopleState = Z.createZustand((set, get) => { logger.info( 'getPeopleData: appFocused:', 'loggedIn', - storeRegistry.getState('config').loggedIn, + useConfigState.getState().loggedIn, 'action', {markViewed, numFollowSuggestionsWanted} ) diff --git a/shared/constants/platform-specific/index.d.ts b/shared/constants/platform-specific/index.d.ts index 7eefb9fc101e..a5c165a8b3c6 100644 --- a/shared/constants/platform-specific/index.d.ts +++ b/shared/constants/platform-specific/index.d.ts @@ -15,5 +15,4 @@ export declare function saveAttachmentToCameraRoll(fileURL: string, mimeType: st export declare function requestLocationPermission(mode: T.RPCChat.UIWatchPositionPerm): Promise export declare function watchPositionForMap(conversationIDKey: T.Chat.ConversationIDKey): Promise<() => void> -export declare function initPlatformListener(): void export declare function requestPermissionsToWrite(): Promise diff --git a/shared/constants/platform-specific/index.desktop.tsx b/shared/constants/platform-specific/index.desktop.tsx index eef15f0e977b..72e46a605293 100644 --- a/shared/constants/platform-specific/index.desktop.tsx +++ b/shared/constants/platform-specific/index.desktop.tsx @@ -1,33 +1,17 @@ -import * as Chat from '../chat2' import {ignorePromise} from '../utils' -import {useActiveState} from '../active' import {useConfigState} from '../config' -import * as ConfigConstants from '../config' -import {useDaemonState} from '../daemon' -import {useFSState} from '../fs' import {usePinentryState} from '../pinentry' -import {useProfileState} from '../profile' -import {useRouterState} from '../router2' -import * as EngineGen from '@/actions/engine-gen-gen' import * as RemoteGen from '@/actions/remote-gen' import * as T from '../types' -import InputMonitor from './input-monitor.desktop' import KB2 from '@/util/electron.desktop' import logger from '@/logger' import {RPCError} from '@/util/errors' -import {getEngine} from '@/engine' -import {isLinux, isWindows} from '../platform.desktop' -import {kbfsNotification} from './kbfs-notifications' -import {skipAppFocusActions} from '@/local-debug.desktop' -import NotifyPopup from '@/util/notify-popup' -import {noKBFSFailReason} from '@/constants/config/util' -import {initSharedSubscriptions} from './shared' import {switchTab} from '../router2/util' import {storeRegistry} from '../store-registry' -import {wrapErrors} from '@/util/debug' +import {onEngineConnected, onEngineDisconnected} from '@/constants/platform-specific/shared' +import {handleAppLink, handleSaltPackOpen} from '../deeplinks' -const {showMainWindow, activeChanged, requestWindowsStartService, dumpNodeLogger} = KB2.functions -const {quitApp, exitApp, setOpenAtLogin, ctlQuit, copyToClipboard} = KB2.functions +const {ctlQuit, dumpNodeLogger} = KB2.functions export const requestPermissionsToWrite = async () => { return Promise.resolve(true) @@ -43,30 +27,6 @@ export async function saveAttachmentToCameraRoll() { export const requestLocationPermission = async () => Promise.resolve() export const watchPositionForMap = async () => Promise.resolve(() => {}) -const maybePauseVideos = () => { - const {appFocused} = useConfigState.getState() - const videos = document.querySelectorAll('video') - const allVideos = Array.from(videos) - - allVideos.forEach(v => { - if (appFocused) { - if (v.hasAttribute('data-focus-paused')) { - if (v.paused) { - v.play() - .then(() => {}) - .catch(() => {}) - } - } - } else { - // only pause looping videos - if (!v.paused && v.hasAttribute('loop') && v.hasAttribute('autoplay')) { - v.setAttribute('data-focus-paused', 'true') - v.pause() - } - } - }) -} - export const dumpLogs = async (reason?: string) => { await logger.dump() await (dumpNodeLogger?.() ?? Promise.resolve([])) @@ -76,229 +36,6 @@ export const dumpLogs = async (reason?: string) => { } } -export const initPlatformListener = () => { - useConfigState.setState(s => { - s.dispatch.dynamic.dumpLogsNative = dumpLogs - s.dispatch.dynamic.showMainNative = wrapErrors(() => showMainWindow?.()) - s.dispatch.dynamic.copyToClipboard = wrapErrors((s: string) => copyToClipboard?.(s)) - s.dispatch.dynamic.onEngineConnectedDesktop = wrapErrors(() => { - // Introduce ourselves to the service - const f = async () => { - await T.RPCGen.configHelloIAmRpcPromise({details: KB2.constants.helloDetails}) - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.onEngineIncomingDesktop = wrapErrors((action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1LogsendPrepareLogsend: { - const f = async () => { - const response = action.payload.response - try { - await dumpLogs() - } finally { - response.result() - } - } - ignorePromise(f()) - break - } - case EngineGen.keybase1NotifyAppExit: - console.log('App exit requested') - exitApp?.(0) - break - case EngineGen.keybase1NotifyFSFSActivity: - kbfsNotification(action.payload.params.notification, NotifyPopup) - break - case EngineGen.keybase1NotifyPGPPgpKeyInSecretStoreFile: { - const f = async () => { - try { - await T.RPCGen.pgpPgpStorageDismissRpcPromise() - } catch (err) { - console.warn('Error in sending pgpPgpStorageDismissRpc:', err) - } - } - ignorePromise(f()) - break - } - case EngineGen.keybase1NotifyServiceShutdown: { - const {code} = action.payload.params - if (isWindows && code !== (T.RPCGen.ExitCode.restart as number)) { - console.log('Quitting due to service shutdown with code: ', code) - // Quit just the app, not the service - quitApp?.() - } - break - } - - case EngineGen.keybase1LogUiLog: { - const {params} = action.payload - const {level, text} = params - logger.info('keybase.1.logUi.log:', params.text.data) - if (level >= T.RPCGen.LogLevel.error) { - NotifyPopup(text.data) - } - break - } - - case EngineGen.keybase1NotifySessionClientOutOfDate: { - const {upgradeTo, upgradeURI, upgradeMsg} = action.payload.params - const body = upgradeMsg || `Please update to ${upgradeTo} by going to ${upgradeURI}` - NotifyPopup('Client out of date!', {body}, 60 * 60) - // This is from the API server. Consider notifications from server always critical. - useConfigState - .getState() - .dispatch.setOutOfDate({critical: true, message: upgradeMsg, outOfDate: true, updating: false}) - break - } - default: - } - }) - }) - - useConfigState.subscribe((s, old) => { - if (s.loggedIn !== old.loggedIn) { - s.dispatch.osNetworkStatusChanged(navigator.onLine, 'notavailable', true) - } - - if (s.appFocused !== old.appFocused) { - maybePauseVideos() - } - - if (s.openAtLogin !== old.openAtLogin) { - const {openAtLogin} = s - const f = async () => { - if (__DEV__) { - console.log('onSetOpenAtLogin disabled for dev mode') - return - } else { - await T.RPCGen.configGuiSetValueRpcPromise({ - path: ConfigConstants.openAtLoginKey, - value: {b: openAtLogin, isNull: false}, - }) - } - if (isLinux || isWindows) { - const enabled = - (await T.RPCGen.ctlGetOnLoginStartupRpcPromise()) === T.RPCGen.OnLoginStartupStatus.enabled - if (enabled !== openAtLogin) { - try { - await T.RPCGen.ctlSetOnLoginStartupRpcPromise({enabled: openAtLogin}) - } catch (error_) { - const error = error_ as RPCError - logger.warn(`Error in sending ctlSetOnLoginStartup: ${error.message}`) - } - } - } else { - logger.info(`Login item settings changed! now ${openAtLogin ? 'on' : 'off'}`) - await setOpenAtLogin?.(openAtLogin) - } - } - ignorePromise(f()) - } - }) - - const handleWindowFocusEvents = () => { - const handle = (appFocused: boolean) => { - if (skipAppFocusActions) { - console.log('Skipping app focus actions!') - } else { - useConfigState.getState().dispatch.changedFocus(appFocused) - } - } - window.addEventListener('focus', () => handle(true)) - window.addEventListener('blur', () => handle(false)) - } - handleWindowFocusEvents() - - const setupReachabilityWatcher = () => { - window.addEventListener('online', () => - useConfigState.getState().dispatch.osNetworkStatusChanged(true, 'notavailable') - ) - window.addEventListener('offline', () => - useConfigState.getState().dispatch.osNetworkStatusChanged(false, 'notavailable') - ) - } - setupReachabilityWatcher() - - useDaemonState.subscribe((s, old) => { - if (s.handshakeVersion !== old.handshakeVersion) { - if (!isWindows) return - - const f = async () => { - const waitKey = 'pipeCheckFail' - const version = s.handshakeVersion - const {wait} = s.dispatch - wait(waitKey, version, true) - try { - logger.info('Checking RPC ownership') - if (KB2.functions.winCheckRPCOwnership) { - await KB2.functions.winCheckRPCOwnership() - } - wait(waitKey, version, false) - } catch (error_) { - // error will be logged in bootstrap check - getEngine().reset() - const error = error_ as RPCError - wait(waitKey, version, false, error.message || 'windows pipe owner fail', true) - } - } - ignorePromise(f()) - } - - if (s.handshakeState !== old.handshakeState && s.handshakeState === 'done') { - useConfigState.getState().dispatch.setStartupDetails({ - conversation: Chat.noConversationIDKey, - followUser: '', - link: '', - tab: undefined, - }) - } - }) - - if (isLinux) { - useConfigState.getState().dispatch.initUseNativeFrame() - } - useConfigState.getState().dispatch.initNotifySound() - useConfigState.getState().dispatch.initForceSmallNav() - useConfigState.getState().dispatch.initOpenAtLogin() - useConfigState.getState().dispatch.initAppUpdateLoop() - - useProfileState.setState(s => { - s.dispatch.editAvatar = () => { - useRouterState - .getState() - .dispatch.navigateAppend({props: {image: undefined}, selected: 'profileEditAvatar'}) - } - }) - - const initializeInputMonitor = () => { - const inputMonitor = new InputMonitor() - inputMonitor.notifyActive = (userActive: boolean) => { - if (skipAppFocusActions) { - console.log('Skipping app focus actions!') - } else { - useActiveState.getState().dispatch.setActive(userActive) - // let node thread save file - activeChanged?.(Date.now(), userActive) - } - } - } - initializeInputMonitor() - - useDaemonState.setState(s => { - s.dispatch.onRestartHandshakeNative = () => { - const {handshakeFailedReason} = useDaemonState.getState() - if (isWindows && handshakeFailedReason === noKBFSFailReason) { - requestWindowsStartService?.() - } - } - }) - - initSharedSubscriptions() - - ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) -} - const updateApp = () => { const f = async () => { await T.RPCGen.configStartUpdateIfNeededRpcPromise() @@ -333,9 +70,9 @@ export const eventFromRemoteWindows = (action: RemoteGen.Actions) => { } case RemoteGen.engineConnection: { if (action.payload.connected) { - storeRegistry.getState('engine').dispatch.onEngineConnected() + onEngineConnected() } else { - storeRegistry.getState('engine').dispatch.onEngineDisconnected() + onEngineDisconnected() } break } @@ -356,7 +93,7 @@ export const eventFromRemoteWindows = (action: RemoteGen.Actions) => { break } case RemoteGen.saltpackFileOpen: { - storeRegistry.getState('deeplinks').dispatch.handleSaltPackOpen(action.payload.path) + handleSaltPackOpen(action.payload.path) break } case RemoteGen.pinentryOnCancel: { @@ -414,7 +151,7 @@ export const eventFromRemoteWindows = (action: RemoteGen.Actions) => { case RemoteGen.link: { const {link} = action.payload - storeRegistry.getState('deeplinks').dispatch.handleAppLink(link) + handleAppLink(link) } break case RemoteGen.installerRan: diff --git a/shared/constants/platform-specific/index.native.tsx b/shared/constants/platform-specific/index.native.tsx index b3b45046629c..3f0a71e13dfc 100644 --- a/shared/constants/platform-specific/index.native.tsx +++ b/shared/constants/platform-specific/index.native.tsx @@ -1,48 +1,11 @@ -import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from '../utils' -import {useChatState} from '../chat2' -import {getConvoState} from '../chat2/convostate' -import {useConfigState} from '../config' -import {useCurrentUserState} from '../current-user' -import {useDaemonState} from '../daemon' -import {useDarkModeState} from '../darkmode' -import {useFSState} from '../fs' -import {useProfileState} from '../profile' -import {useRouterState} from '../router2' -import {useSettingsContactsState} from '../settings-contacts' import * as T from '../types' -import * as Clipboard from 'expo-clipboard' -import * as EngineGen from '@/actions/engine-gen-gen' import * as ExpoLocation from 'expo-location' -import * as ExpoTaskManager from 'expo-task-manager' import * as MediaLibrary from 'expo-media-library' -import * as Tabs from '../tabs' -import * as NetInfo from '@react-native-community/netinfo' -import NotifyPopup from '@/util/notify-popup' import {addNotificationRequest} from 'react-native-kb' import logger from '@/logger' -import {Alert, Linking, ActionSheetIOS} from 'react-native' +import {ActionSheetIOS} from 'react-native' import {isIOS, isAndroid} from '../platform.native' -import {wrapErrors} from '@/util/debug' -import {getTab, getVisiblePath, logState} from '../router2' -import {launchImageLibraryAsync} from '@/util/expo-image-picker.native' -import {setupAudioMode} from '@/util/audio.native' -import { - androidOpenSettings, - androidShare, - androidShareText, - androidUnlink, - fsCacheDir, - fsDownloadDir, - androidAppColorSchemeChanged, - guiConfig, - shareListenersRegistered, -} from 'react-native-kb' -import {initPushListener, getStartupDetailsFromInitialPush} from './push.native' -import {initSharedSubscriptions} from './shared' -import type {ImageInfo} from '@/util/expo-image-picker.native' -import {noConversationIDKey} from '@/constants/types/chat2/common' -import {getSelectedConversation} from '@/constants/chat2/common' -import {storeRegistry} from '../store-registry' +import {androidShare, androidShareText, androidUnlink} from 'react-native-kb' export const requestPermissionsToWrite = async () => { if (isAndroid) { @@ -146,505 +109,3 @@ export const showShareActionSheet = async (options: { } } } - -const loadStartupDetails = async () => { - const [routeState, initialUrl, push] = await Promise.all([ - neverThrowPromiseFunc(async () => { - try { - const config = JSON.parse(guiConfig) as {ui?: {routeState2?: string}} | undefined - return Promise.resolve(config?.ui?.routeState2 ?? '') - } catch { - return Promise.resolve('') - } - }), - neverThrowPromiseFunc(async () => Linking.getInitialURL()), - neverThrowPromiseFunc(getStartupDetailsFromInitialPush), - ] as const) - - // Clear last value to be extra safe bad things don't hose us forever - try { - await T.RPCGen.configGuiSetValueRpcPromise({ - path: 'ui.routeState2', - value: {isNull: false, s: ''}, - }) - } catch {} - - let conversation: T.Chat.ConversationIDKey | undefined - let followUser = '' - let link = '' - let tab = '' - - // Top priority, push - if (push) { - logger.info('initialState: push', push.startupConversation, push.startupFollowUser) - conversation = push.startupConversation - followUser = push.startupFollowUser ?? '' - } else if (initialUrl) { - // Second priority, deep link - link = initialUrl - } else if (routeState) { - // Last priority, saved from last session - try { - const item = JSON.parse(routeState) as - | undefined - | {param?: {selectedConversationIDKey?: unknown}; routeName?: string} - if (item) { - const _convo = item.param?.selectedConversationIDKey || undefined - if (typeof _convo === 'string') { - conversation = _convo - logger.info('initialState: routeState', conversation) - } - const _rn = item.routeName || undefined - if (typeof _rn === 'string') { - tab = _rn as unknown as typeof tab - } - } - } catch { - logger.info('initialState: routeState parseFail') - conversation = undefined - tab = '' - } - } - - // never allow this case - if (tab === 'blank') { - tab = '' - } - - useConfigState.getState().dispatch.setStartupDetails({ - conversation: conversation ?? noConversationIDKey, - followUser, - link, - tab: tab as Tabs.Tab, - }) -} - -const setPermissionDeniedCommandStatus = (conversationIDKey: T.Chat.ConversationIDKey, text: string) => { - getConvoState(conversationIDKey).dispatch.setCommandStatusInfo({ - actions: [T.RPCChat.UICommandStatusActionTyp.appsettings], - displayText: text, - displayType: T.RPCChat.UICommandStatusDisplayTyp.error, - }) -} - -const onChatWatchPosition = async (action: EngineGen.Chat1ChatUiChatWatchPositionPayload) => { - const response = action.payload.response - response.result(0) - try { - await requestLocationPermission(action.payload.params.perm) - } catch (_error) { - const error = _error as {message?: string} - logger.info('failed to get location perms: ' + error.message) - setPermissionDeniedCommandStatus( - T.Chat.conversationIDToKey(action.payload.params.convID), - `Failed to access location. ${error.message}` - ) - } - - locationRefs++ - - if (locationRefs === 1) { - try { - logger.info( - '[location] location watch start due to ', - T.Chat.conversationIDToKey(action.payload.params.convID) - ) - ensureBackgroundTask() - await ExpoLocation.startLocationUpdatesAsync(locationTaskName, { - deferredUpdatesDistance: 65, - pausesUpdatesAutomatically: true, - showsBackgroundLocationIndicator: true, - }) - logger.info('[location] start success') - } catch { - logger.info('[location] start failed') - locationRefs-- - } - } -} - -const onChatClearWatch = async () => { - locationRefs-- - if (locationRefs <= 0) { - try { - logger.info('[location] end start') - ensureBackgroundTask() - await ExpoLocation.stopLocationUpdatesAsync(locationTaskName) - logger.info('[location] end success') - } catch { - logger.info('[location] end failed') - } - } -} - -const locationTaskName = 'background-location-task' -let locationRefs = 0 -let madeBackgroundTask = false - -const ensureBackgroundTask = () => { - if (madeBackgroundTask) return - madeBackgroundTask = true - - ExpoTaskManager.defineTask(locationTaskName, async ({data, error}) => { - if (error) { - // check `error.message` for more details. - return Promise.resolve() - } - - if (!data) { - return Promise.resolve() - } - const d = data as {locations?: Array} - const locations = d.locations - if (!locations?.length) { - return Promise.resolve() - } - const pos = locations.at(-1) - const coord = { - accuracy: Math.floor(pos?.coords.accuracy ?? 0), - lat: pos?.coords.latitude ?? 0, - lon: pos?.coords.longitude ?? 0, - } - - useChatState.getState().dispatch.updateLastCoord(coord) - return Promise.resolve() - }) -} - -export const watchPositionForMap = async (conversationIDKey: T.Chat.ConversationIDKey) => { - try { - logger.info('[location] perms check due to map') - await requestLocationPermission(T.RPCChat.UIWatchPositionPerm.base) - } catch (_error) { - const error = _error as {message?: string} - logger.info('failed to get location perms: ' + error.message) - setPermissionDeniedCommandStatus(conversationIDKey, `Failed to access location. ${error.message}`) - return () => {} - } - - try { - const sub = await ExpoLocation.watchPositionAsync( - {accuracy: ExpoLocation.LocationAccuracy.Highest}, - location => { - const coord = { - accuracy: Math.floor(location.coords.accuracy ?? 0), - lat: location.coords.latitude, - lon: location.coords.longitude, - } - useChatState.getState().dispatch.updateLastCoord(coord) - } - ) - return () => sub.remove() - } catch (_error) { - const error = _error as {message?: string} - logger.info('failed to get location: ' + error.message) - setPermissionDeniedCommandStatus(conversationIDKey, `Failed to access location. ${error.message}`) - return () => {} - } -} - -export const initPlatformListener = () => { - let _lastPersist = '' - useConfigState.setState(s => { - s.dispatch.dynamic.persistRoute = wrapErrors((path?: ReadonlyArray) => { - const f = async () => { - if (!useConfigState.getState().startup.loaded) { - return - } - let param = {} - let routeName = Tabs.peopleTab - if (path) { - const cur = getTab() - if (cur) { - routeName = cur - } - const ap = getVisiblePath() - ap.some(r => { - if (r.name === 'chatConversation') { - const rParams = r.params as undefined | {conversationIDKey?: T.Chat.ConversationIDKey} - param = {selectedConversationIDKey: rParams?.conversationIDKey} - return true - } - return false - }) - } - const s = JSON.stringify({param, routeName}) - // don't keep rewriting - if (_lastPersist === s) { - return - } - _lastPersist = s - - await T.RPCGen.configGuiSetValueRpcPromise({ - path: 'ui.routeState2', - value: {isNull: false, s}, - }) - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.onEngineIncomingNative = wrapErrors((action: EngineGen.Actions) => { - switch (action.type) { - default: - } - }) - }) - - useConfigState.subscribe((s, old) => { - if (s.mobileAppState === old.mobileAppState) return - let appFocused: boolean - let logState: T.RPCGen.MobileAppState - switch (s.mobileAppState) { - case 'active': - appFocused = true - logState = T.RPCGen.MobileAppState.foreground - break - case 'background': - appFocused = false - logState = T.RPCGen.MobileAppState.background - break - case 'inactive': - appFocused = false - logState = T.RPCGen.MobileAppState.inactive - break - default: - appFocused = false - logState = T.RPCGen.MobileAppState.foreground - } - - logger.info(`setting app state on service to: ${logState}`) - s.dispatch.changedFocus(appFocused) - - if (appFocused && old.mobileAppState !== 'active') { - const {dispatch} = storeRegistry.getConvoState(getSelectedConversation()) - dispatch.loadMoreMessages({reason: 'foregrounding'}) - dispatch.markThreadAsRead() - } - }) - - useConfigState.setState(s => { - s.dispatch.dynamic.copyToClipboard = wrapErrors((s: string) => { - Clipboard.setStringAsync(s) - .then(() => {}) - .catch(() => {}) - }) - }) - - const configureAndroidCacheDir = () => { - if (isAndroid && fsCacheDir && fsDownloadDir) { - ignorePromise( - T.RPCChat.localConfigureFileAttachmentDownloadLocalRpcPromise({ - // Android's cache dir is (when I tried) [app]/cache but Go side uses - // [app]/.cache by default, which can't be used for sharing to other apps. - cacheDirOverride: fsCacheDir, - downloadDirOverride: fsDownloadDir, - }) - .then(() => {}) - .catch((e: unknown) => { - logger.error(`[Android cache override] Failed to configure: ${String(e)}`) - }) - ) - } else if (isAndroid) { - logger.warn( - `[Android cache override] Missing dirs - cacheDir: ${fsCacheDir}, downloadDir: ${fsDownloadDir}` - ) - } - } - - useDaemonState.subscribe((s, old) => { - const versionChanged = s.handshakeVersion !== old.handshakeVersion - const stateChanged = s.handshakeState !== old.handshakeState - const justBecameReady = stateChanged && s.handshakeState === 'done' && old.handshakeState !== 'done' - - if (versionChanged || justBecameReady) { - configureAndroidCacheDir() - } - }) - - useConfigState.setState(s => { - s.dispatch.dynamic.onFilePickerError = wrapErrors((error: Error) => { - Alert.alert('Error', String(error)) - }) - s.dispatch.dynamic.openAppStore = wrapErrors(() => { - Linking.openURL( - isAndroid - ? 'http://play.google.com/store/apps/details?id=io.keybase.ossifrage' - : 'https://itunes.apple.com/us/app/keybase-crypto-for-everyone/id1044461770?mt=8' - ).catch(() => {}) - }) - }) - - useProfileState.setState(s => { - s.dispatch.editAvatar = () => { - const f = async () => { - try { - const result = await launchImageLibraryAsync('photo') - const first = result.assets?.reduce((acc, a) => { - if (!acc && (a.type === 'image' || a.type === 'video')) { - return a as ImageInfo - } - return acc - }, undefined) - if (!result.canceled && first) { - useRouterState - .getState() - .dispatch.navigateAppend({props: {image: first}, selected: 'profileEditAvatar'}) - } - } catch (error) { - useConfigState.getState().dispatch.filePickerError(new Error(String(error))) - } - } - ignorePromise(f()) - } - }) - - useConfigState.subscribe((s, old) => { - if (s.loggedIn === old.loggedIn) return - const f = async () => { - const {type} = await NetInfo.fetch() - s.dispatch.osNetworkStatusChanged(type !== NetInfo.NetInfoStateType.none, type, true) - } - ignorePromise(f()) - }) - - useConfigState.subscribe((s, old) => { - if (s.networkStatus === old.networkStatus) return - const type = s.networkStatus?.type - if (!type) return - const f = async () => { - try { - await T.RPCGen.appStateUpdateMobileNetStateRpcPromise({state: type}) - } catch (err) { - console.warn('Error sending mobileNetStateUpdate', err) - } - } - ignorePromise(f()) - }) - - useConfigState.setState(s => { - s.dispatch.dynamic.showShareActionSheet = wrapErrors( - (filePath: string, message: string, mimeType: string) => { - const f = async () => { - await showShareActionSheet({filePath, message, mimeType}) - } - ignorePromise(f()) - } - ) - }) - - useConfigState.subscribe((s, old) => { - if (s.mobileAppState === old.mobileAppState) return - if (s.mobileAppState === 'active') { - // only reload on foreground - useSettingsContactsState.getState().dispatch.loadContactPermissions() - } - }) - - // Location - if (isAndroid) { - useDarkModeState.subscribe((s, old) => { - if (s.darkModePreference === old.darkModePreference) return - androidAppColorSchemeChanged(s.darkModePreference) - }) - } - - // we call this when we're logged in. - let calledShareListenersRegistered = false - - useRouterState.subscribe((s, old) => { - const next = s.navState - const prev = old.navState - if (next === prev) return - const f = async () => { - await timeoutPromise(1000) - const path = getVisiblePath() - useConfigState.getState().dispatch.dynamic.persistRoute?.(path) - } - - if (!calledShareListenersRegistered && logState().loggedIn) { - calledShareListenersRegistered = true - shareListenersRegistered() - } - ignorePromise(f()) - }) - - // Start this immediately instead of waiting so we can do more things in parallel - ignorePromise(loadStartupDetails()) - initPushListener() - - NetInfo.addEventListener(({type}) => { - useConfigState.getState().dispatch.osNetworkStatusChanged(type !== NetInfo.NetInfoStateType.none, type) - }) - - const initAudioModes = () => { - ignorePromise(setupAudioMode(false)) - } - initAudioModes() - - if (isAndroid) { - const daemonState = useDaemonState.getState() - if (daemonState.handshakeState === 'done' || daemonState.handshakeVersion > 0) { - configureAndroidCacheDir() - } - } - - useConfigState.setState(s => { - s.dispatch.dynamic.openAppSettings = wrapErrors(() => { - const f = async () => { - if (isAndroid) { - androidOpenSettings() - } else { - const settingsURL = 'app-settings:' - const can = await Linking.canOpenURL(settingsURL) - if (can) { - await Linking.openURL(settingsURL) - } else { - logger.warn('Unable to open app settings') - } - } - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.onEngineIncomingNative = wrapErrors((action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.chat1ChatUiTriggerContactSync: - useSettingsContactsState.getState().dispatch.manageContactsCache() - break - case EngineGen.keybase1LogUiLog: { - const {params} = action.payload - const {level, text} = params - logger.info('keybase.1.logUi.log:', params.text.data) - if (level >= T.RPCGen.LogLevel.error) { - NotifyPopup(text.data) - } - break - } - case EngineGen.chat1ChatUiChatWatchPosition: - ignorePromise(onChatWatchPosition(action)) - break - case EngineGen.chat1ChatUiChatClearWatch: - ignorePromise(onChatClearWatch()) - break - default: - } - }) - }) - - useRouterState.setState(s => { - s.dispatch.dynamic.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) { - useConfigState.getState().dispatch.setUserSwitching(true) - useConfigState.getState().dispatch.login(row.username, '') - } - }) - }) - - initSharedSubscriptions() - - ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) -} diff --git a/shared/constants/platform-specific/push.native.tsx b/shared/constants/platform-specific/push.native.tsx index 87936d03820d..25f3ed270787 100644 --- a/shared/constants/platform-specific/push.native.tsx +++ b/shared/constants/platform-specific/push.native.tsx @@ -10,6 +10,7 @@ import { removeAllPendingNotificationRequests, } from 'react-native-kb' import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' import {useLogoutState} from '../logout' type DataCommon = { @@ -162,7 +163,7 @@ const getStartupDetailsFromInitialPush = async () => { export const initPushListener = () => { // Permissions - storeRegistry.getStore('config').subscribe((s, old) => { + useConfigState.subscribe((s, old) => { if (s.mobileAppState === old.mobileAppState) return // Only recheck on foreground, not background if (s.mobileAppState !== 'active') { @@ -184,7 +185,7 @@ export const initPushListener = () => { }) let lastCount = -1 - storeRegistry.getStore('config').subscribe((s, old) => { + useConfigState.subscribe((s, old) => { if (s.badgeState === old.badgeState) return if (!s.badgeState) return const count = s.badgeState.bigTeamBadgeCount + s.badgeState.smallTeamBadgeCount @@ -221,7 +222,7 @@ export const initPushListener = () => { if (isAndroid) { RNEmitter.addListener('onShareData', (evt: {text?: string; localPaths?: Array}) => { - const {setAndroidShare} = storeRegistry.getState('config').dispatch + const {setAndroidShare} = useConfigState.getState().dispatch const text = evt.text const urls = evt.localPaths diff --git a/shared/constants/platform-specific/shared.tsx b/shared/constants/platform-specific/shared.tsx index ed3a135c1de9..417cddd4cc44 100644 --- a/shared/constants/platform-specific/shared.tsx +++ b/shared/constants/platform-specific/shared.tsx @@ -21,6 +21,7 @@ import * as GitUtil from '../git/util' import * as NotifUtil from '../notifications/util' import * as PeopleUtil from '../people/util' import * as PinentryUtil from '../pinentry/util' +import {useProvisionState} from '../provision' import {storeRegistry} from '../store-registry' import {useSettingsContactsState} from '../settings-contacts' import * as SettingsUtil from '../settings/util' @@ -30,10 +31,32 @@ import * as TeamsUtil from '../teams/util' import * as TrackerUtil from '../tracker2/util' import * as UnlockFoldersUtil from '../unlock-folders/util' import * as UsersUtil from '../users/util' +import {useWhatsNewState} from '../whats-new' +import {onEngineIncoming as onEngineIncomingPlatform} from '../init' let _emitStartupOnLoadDaemonConnectedOnce = false +export const onEngineConnected = () => { + ChatUtil.onEngineConnected() + useConfigState.getState().dispatch.onEngineConnected() + storeRegistry.getState('daemon').dispatch.startHandshake() + NotifUtil.onEngineConnected() + PeopleUtil.onEngineConnected() + PinentryUtil.onEngineConnected() + TrackerUtil.onEngineConnected() + UnlockFoldersUtil.onEngineConnected() +} + +export const onEngineDisconnected = () => { + const f = async () => { + await logger.dump() + } + ignorePromise(f()) + storeRegistry.getState('daemon').dispatch.setError(new Error('Disconnected')) +} + export const initSharedSubscriptions = () => { + useConfigState.subscribe((s, old) => { if (s.loadOnStartPhase !== old.loadOnStartPhase) { if (s.loadOnStartPhase === 'startupOrReloginButNotInARush') { @@ -115,10 +138,10 @@ export const initSharedSubscriptions = () => { .dispatch.loadDaemonAccounts( s.configuredAccounts.length, s.loggedIn, - storeRegistry.getState('config').dispatch.refreshAccounts + useConfigState.getState().dispatch.refreshAccounts ) if (!s.loggedInCausedbyStartup) { - ignorePromise(storeRegistry.getState('config').dispatch.refreshAccounts()) + ignorePromise(useConfigState.getState().dispatch.refreshAccounts()) } } @@ -134,7 +157,7 @@ export const initSharedSubscriptions = () => { .dispatch.loadDaemonAccounts( s.configuredAccounts.length, s.loggedIn, - storeRegistry.getState('config').dispatch.refreshAccounts + useConfigState.getState().dispatch.refreshAccounts ) } @@ -147,17 +170,22 @@ export const initSharedSubscriptions = () => { storeRegistry.getState('users').dispatch.updates(updates) } } + + if (s.gregorPushState !== old.gregorPushState) { + const lastSeenItem = s.gregorPushState.find(i => i.item.category === 'whatsNewLastSeenVersion') + useWhatsNewState.getState().dispatch.updateLastSeen(lastSeenItem) + } }) useDaemonState.subscribe((s, old) => { if (s.handshakeVersion !== old.handshakeVersion) { useDarkModeState.getState().dispatch.loadDarkPrefs() storeRegistry.getState('chat').dispatch.loadStaticConfig() - const configState = storeRegistry.getState('config') + const configState = useConfigState.getState() s.dispatch.loadDaemonAccounts( configState.configuredAccounts.length, configState.loggedIn, - storeRegistry.getState('config').dispatch.refreshAccounts + useConfigState.getState().dispatch.refreshAccounts ) } @@ -167,7 +195,7 @@ export const initSharedSubscriptions = () => { const {deviceID, deviceName, loggedIn, uid, username, userReacjis} = bootstrap useCurrentUserState.getState().dispatch.setBootstrap({deviceID, deviceName, uid, username}) - const configDispatch = storeRegistry.getState('config').dispatch + const configDispatch = useConfigState.getState().dispatch if (username) { configDispatch.setDefaultUsername(username) } @@ -188,9 +216,26 @@ export const initSharedSubscriptions = () => { if (s.handshakeState === 'done') { if (!_emitStartupOnLoadDaemonConnectedOnce) { _emitStartupOnLoadDaemonConnectedOnce = true - storeRegistry.getState('config').dispatch.loadOnStart('connectedToDaemonForFirstTime') + useConfigState.getState().dispatch.loadOnStart('connectedToDaemonForFirstTime') + } + } + } + }) + + useProvisionState.subscribe((s, old) => { + if (s.startProvisionTrigger !== old.startProvisionTrigger) { + useConfigState.getState().dispatch.setLoginError() + useConfigState.getState().dispatch.resetRevokedSelf() + const f = async () => { + // If we're logged in, we're coming from the user switcher; log out first to prevent the service from getting out of sync with the GUI about our logged-in-ness + if (useConfigState.getState().loggedIn) { + await T.RPCGen.loginLogoutRpcPromise( + {force: false, keepSecrets: true}, + 'config:loginAsOther' + ) } } + ignorePromise(f()) } }) } @@ -201,9 +246,8 @@ export const onEngineIncoming = (action: EngineGen.Actions) => { AvatarUtil.onEngineIncoming(action) BotsUtil.onEngineIncoming(action) ChatUtil.onEngineIncoming(action) - storeRegistry.getState('config').dispatch.dynamic.onEngineIncomingDesktop?.(action) - storeRegistry.getState('config').dispatch.dynamic.onEngineIncomingNative?.(action) - storeRegistry.getState('config').dispatch.onEngineIncoming(action) + onEngineIncomingPlatform(action) + useConfigState.getState().dispatch.onEngineIncoming(action) DeepLinksUtil.onEngineIncoming(action) DevicesUtil.onEngineIncoming(action) FollowerUtil.onEngineIncoming(action) diff --git a/shared/constants/profile/index.tsx b/shared/constants/profile/index.tsx index 5e8eaa1d4cf1..d99952fa3cdb 100644 --- a/shared/constants/profile/index.tsx +++ b/shared/constants/profile/index.tsx @@ -10,7 +10,7 @@ import {fixCrop} from '@/util/crop' import {clearModals, navigateAppend, navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' import {useCurrentUserState} from '../current-user' -import {navToProfile} from '../router2' +import {navToProfile} from '../router2/util' type ProveGenericParams = { logoBlack: T.Tracker.SiteIconSet @@ -408,12 +408,13 @@ export const useProfileState = Z.createZustand((set, get) => { s.errorCode = error.code }) if (error.code === T.RPCGen.StatusCode.scgeneric && reason === 'appLink') { - storeRegistry - .getState('deeplinks') - .dispatch.setLinkError( - "We couldn't find a valid service for proofs in this link. The link might be bad, or your Keybase app might be out of date and need to be updated." - ) - navigateAppend('keybaseLinkError') + navigateAppend({ + props: { + error: + "We couldn't find a valid service for proofs in this link. The link might be bad, or your Keybase app might be out of date and need to be updated.", + }, + selected: 'keybaseLinkError', + }) } } if (genericService) { diff --git a/shared/constants/provision/index.tsx b/shared/constants/provision/index.tsx index f5d82672bde0..e948638d1e95 100644 --- a/shared/constants/provision/index.tsx +++ b/shared/constants/provision/index.tsx @@ -1,6 +1,6 @@ -import * as C from '..' import * as T from '../types' -import {ignorePromise} from '../utils' +import {ignorePromise, wrapErrors} from '../utils' +import {waitingKeyProvision, waitingKeyProvisionForgotUsername} from '../strings' import * as Z from '@/util/zustand' import {RPCError} from '@/util/errors' import {isMobile} from '../platform' @@ -9,7 +9,6 @@ import isEqual from 'lodash/isEqual' import {rpcDeviceToDevice} from '../rpc-utils' import {invalidPasswordErrorString} from '@/constants/config/util' import {clearModals, navigateAppend} from '../router2/util' -import {storeRegistry} from '../store-registry' import {useWaitingState} from '../waiting' export type Device = { @@ -83,6 +82,7 @@ type Store = T.Immutable<{ inlineError?: RPCError passphrase: string provisionStep: number + startProvisionTrigger: number username: string }> const initialStore: Store = { @@ -100,6 +100,7 @@ const initialStore: Store = { inlineError: undefined, passphrase: '', provisionStep: 0, + startProvisionTrigger: 0, username: '', } @@ -122,15 +123,15 @@ export interface State extends Store { } export const useProvisionState = Z.createZustand((set, get) => { - const _cancel = C.wrapErrors((ignoreWarning?: boolean) => { - useWaitingState.getState().dispatch.clear(C.waitingKeyProvision) + const _cancel = wrapErrors((ignoreWarning?: boolean) => { + useWaitingState.getState().dispatch.clear(waitingKeyProvision) if (!ignoreWarning) { console.log('Provision: cancel called while not overloaded') } }) // add a new value to submit and clear things behind - const _updateAutoSubmit = C.wrapErrors((step: Store['autoSubmit'][0]) => { + const _updateAutoSubmit = wrapErrors((step: Store['autoSubmit'][0]) => { set(s => { const idx = s.autoSubmit.findIndex(a => a.type === step.type) if (idx !== -1) { @@ -140,16 +141,7 @@ export const useProvisionState = Z.createZustand((set, get) => { }) }) - const _setUsername = C.wrapErrors((username: string, restart: boolean = true) => { - set(s => { - s.username = username - s.autoSubmit = [{type: 'username'}] - }) - if (restart) { - get().dispatch.restartProvisioning() - } - }) - const _setPassphrase = C.wrapErrors((passphrase: string, restart: boolean = true) => { + const _setPassphrase = wrapErrors((passphrase: string, restart: boolean = true) => { set(s => { s.passphrase = passphrase }) @@ -159,7 +151,7 @@ export const useProvisionState = Z.createZustand((set, get) => { } }) - const _setDeviceName = C.wrapErrors((name: string, restart: boolean = true) => { + const _setDeviceName = wrapErrors((name: string, restart: boolean = true) => { set(s => { s.deviceName = name }) @@ -169,7 +161,7 @@ export const useProvisionState = Z.createZustand((set, get) => { } }) - const _submitDeviceSelect = C.wrapErrors((name: string, restart: boolean = true) => { + const _submitDeviceSelect = wrapErrors((name: string, restart: boolean = true) => { const devices = get().devices const selectedDevice = devices.find(d => d.name === name) if (!selectedDevice) { @@ -184,7 +176,7 @@ export const useProvisionState = Z.createZustand((set, get) => { } }) - const _submitTextCode = C.wrapErrors((_code: string) => { + const _submitTextCode = wrapErrors((_code: string) => { console.log('Provision, unwatched submitTextCode called') get().dispatch.restartProvisioning() }) @@ -205,7 +197,7 @@ export const useProvisionState = Z.createZustand((set, get) => { let cancelled = false const setupCancel = (response: CommonResponseHandler) => { set(s => { - s.dispatch.dynamic.cancel = C.wrapErrors(() => { + s.dispatch.dynamic.cancel = wrapErrors(() => { set(s => { s.dispatch.dynamic.cancel = _cancel }) @@ -232,7 +224,7 @@ export const useProvisionState = Z.createZustand((set, get) => { set(s => { s.error = previousErr s.codePageIncomingTextCode = phrase - s.dispatch.dynamic.submitTextCode = C.wrapErrors((code: string) => { + s.dispatch.dynamic.submitTextCode = wrapErrors((code: string) => { set(s => { s.dispatch.dynamic.submitTextCode = _submitTextCode }) @@ -260,13 +252,13 @@ export const useProvisionState = Z.createZustand((set, get) => { }, incomingCallMap: { 'keybase.1.provisionUi.DisplaySecretExchanged': () => { - useWaitingState.getState().dispatch.increment(C.waitingKeyProvision) + useWaitingState.getState().dispatch.increment(waitingKeyProvision) }, 'keybase.1.provisionUi.ProvisioneeSuccess': () => {}, 'keybase.1.provisionUi.ProvisionerSuccess': () => {}, }, params: undefined, - waitingKey: C.waitingKeyProvision, + waitingKey: waitingKeyProvision, }) } catch { } finally { @@ -274,7 +266,6 @@ export const useProvisionState = Z.createZustand((set, get) => { s.dispatch.dynamic.cancel = _cancel s.dispatch.dynamic.setDeviceName = _setDeviceName s.dispatch.dynamic.setPassphrase = _setPassphrase - s.dispatch.dynamic.setUsername = _setUsername s.dispatch.dynamic.submitDeviceSelect = _submitDeviceSelect s.dispatch.dynamic.submitTextCode = _submitTextCode }) @@ -287,7 +278,15 @@ export const useProvisionState = Z.createZustand((set, get) => { cancel: _cancel, setDeviceName: _setDeviceName, setPassphrase: _setPassphrase, - setUsername: _setUsername, + setUsername: wrapErrors((username: string, restart: boolean = true) => { + set(s => { + s.username = username + s.autoSubmit = [{type: 'username'}] + }) + if (restart) { + get().dispatch.restartProvisioning() + } + }), submitDeviceSelect: _submitDeviceSelect, submitTextCode: _submitTextCode, }, @@ -297,7 +296,7 @@ export const useProvisionState = Z.createZustand((set, get) => { try { await T.RPCGen.accountRecoverUsernameWithEmailRpcPromise( {email}, - C.waitingKeyProvisionForgotUsername + waitingKeyProvisionForgotUsername ) set(s => { s.forgotUsernameResult = 'success' @@ -315,7 +314,7 @@ export const useProvisionState = Z.createZustand((set, get) => { try { await T.RPCGen.accountRecoverUsernameWithPhoneRpcPromise( {phone}, - C.waitingKeyProvisionForgotUsername + waitingKeyProvisionForgotUsername ) set(s => { s.forgotUsernameResult = 'success' @@ -367,7 +366,7 @@ export const useProvisionState = Z.createZustand((set, get) => { // Make cancel set the flag and cancel the current rpc const setupCancel = (response: CommonResponseHandler) => { set(s => { - s.dispatch.dynamic.cancel = C.wrapErrors(() => { + s.dispatch.dynamic.cancel = wrapErrors(() => { set(s => { s.dispatch.dynamic.cancel = _cancel }) @@ -398,7 +397,7 @@ export const useProvisionState = Z.createZustand((set, get) => { set(s => { s.error = previousErr s.codePageIncomingTextCode = phrase - s.dispatch.dynamic.submitTextCode = C.wrapErrors((code: string) => { + s.dispatch.dynamic.submitTextCode = wrapErrors((code: string) => { set(s => { s.dispatch.dynamic.submitTextCode = _submitTextCode }) @@ -419,7 +418,7 @@ export const useProvisionState = Z.createZustand((set, get) => { set(s => { s.error = errorMessage s.existingDevices = T.castDraft(existingDevices ?? []) - s.dispatch.dynamic.setDeviceName = C.wrapErrors((name: string) => { + s.dispatch.dynamic.setDeviceName = wrapErrors((name: string) => { set(s => { s.dispatch.dynamic.setDeviceName = _setDeviceName }) @@ -444,7 +443,7 @@ export const useProvisionState = Z.createZustand((set, get) => { set(s => { s.error = '' s.devices = devices - s.dispatch.dynamic.submitDeviceSelect = C.wrapErrors((device: string) => { + s.dispatch.dynamic.submitDeviceSelect = wrapErrors((device: string) => { set(s => { s.dispatch.dynamic.submitDeviceSelect = _submitDeviceSelect }) @@ -473,7 +472,7 @@ export const useProvisionState = Z.createZustand((set, get) => { // Service asking us again due to an error? set(s => { s.error = retryLabel === invalidPasswordErrorString ? 'Incorrect password.' : retryLabel - s.dispatch.dynamic.setPassphrase = C.wrapErrors((passphrase: string) => { + s.dispatch.dynamic.setPassphrase = wrapErrors((passphrase: string) => { set(s => { s.dispatch.dynamic.setPassphrase = _setPassphrase }) @@ -503,7 +502,7 @@ export const useProvisionState = Z.createZustand((set, get) => { incomingCallMap: { 'keybase.1.loginUi.displayPrimaryPaperKey': () => {}, 'keybase.1.provisionUi.DisplaySecretExchanged': () => { - useWaitingState.getState().dispatch.increment(C.waitingKeyProvision) + useWaitingState.getState().dispatch.increment(waitingKeyProvision) }, 'keybase.1.provisionUi.ProvisioneeSuccess': () => {}, 'keybase.1.provisionUi.ProvisionerSuccess': () => {}, @@ -516,7 +515,7 @@ export const useProvisionState = Z.createZustand((set, get) => { paperKey: '', username, }, - waitingKey: C.waitingKeyProvision, + waitingKey: waitingKeyProvision, }) get().dispatch.resetState() } catch (_finalError) { @@ -552,23 +551,11 @@ export const useProvisionState = Z.createZustand((set, get) => { }, startProvision: (name = '', fromReset = false) => { get().dispatch.dynamic.cancel?.(true) - storeRegistry.getState('config').dispatch.setLoginError() - storeRegistry.getState('config').dispatch.resetRevokedSelf() - set(s => { + s.startProvisionTrigger++ s.username = name }) - const f = async () => { - // If we're logged in, we're coming from the user switcher; log out first to prevent the service from getting out of sync with the GUI about our logged-in-ness - if (storeRegistry.getState('config').loggedIn) { - await T.RPCGen.loginLogoutRpcPromise( - {force: false, keepSecrets: true}, - C.waitingKeyConfigLoginAsOther - ) - } - navigateAppend({props: {fromReset}, selected: 'username'}) - } - ignorePromise(f()) + navigateAppend({props: {fromReset}, selected: 'username'}) }, } diff --git a/shared/constants/push.native.tsx b/shared/constants/push.native.tsx index 59272b34c86c..9e7995bfade6 100644 --- a/shared/constants/push.native.tsx +++ b/shared/constants/push.native.tsx @@ -3,6 +3,7 @@ import * as S from './strings' import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from './utils' import {navigateAppend, navUpToScreen, switchTab} from './router2/util' import {storeRegistry} from './store-registry' +import {useConfigState} from './config' import {useCurrentUserState} from './current-user' import {useLogoutState} from './logout' import {useWaitingState} from './waiting' @@ -163,7 +164,7 @@ export const usePushState = Z.createZustand((set, get) => { } break case 'settings.contacts': - if (storeRegistry.getState('config').loggedIn) { + if (useConfigState.getState().loggedIn) { switchTab(Tabs.peopleTab) navUpToScreen('peopleRoot') } @@ -222,13 +223,13 @@ export const usePushState = Z.createZustand((set, get) => { const shownPushPrompt = await askNativeIfSystemPushPromptHasBeenShown() if (shownPushPrompt) { // we've already shown the prompt, take them to settings - storeRegistry.getState('config').dispatch.dynamic.openAppSettings?.() + useConfigState.getState().dispatch.dynamic.openAppSettings?.() get().dispatch.showPermissionsPrompt({persistSkip: true, show: false}) return } } try { - storeRegistry.getState('config').dispatch.dynamic.openAppSettings?.() + useConfigState.getState().dispatch.dynamic.openAppSettings?.() const {increment} = useWaitingState.getState().dispatch increment(S.waitingKeyPushPermissionsRequesting) await requestPermissionsFromNative() @@ -295,7 +296,7 @@ export const usePushState = Z.createZustand((set, get) => { // permissions checker finishes after the routeToInitialScreen is done. if ( p.show && - storeRegistry.getState('config').loggedIn && + useConfigState.getState().loggedIn && storeRegistry.getState('daemon').handshakeState === 'done' && !get().justSignedUp && !get().hasPermissions diff --git a/shared/constants/recover-password/index.tsx b/shared/constants/recover-password/index.tsx index 47d6eec523fa..1012961c6f45 100644 --- a/shared/constants/recover-password/index.tsx +++ b/shared/constants/recover-password/index.tsx @@ -8,6 +8,7 @@ import {type Device} from '../provision' import {rpcDeviceToDevice} from '../rpc-utils' import {clearModals, navigateAppend, navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' type Store = T.Immutable<{ devices: Array @@ -230,7 +231,7 @@ export const useState = Z.createZustand((set, get) => { storeRegistry .getState('router') .dispatch.navigateAppend( - storeRegistry.getState('config').loggedIn + useConfigState.getState().loggedIn ? 'recoverPasswordErrorModal' : 'recoverPasswordError', true diff --git a/shared/constants/settings-chat/index.tsx b/shared/constants/settings-chat/index.tsx index 24b2b4a1024f..615ba7a1981f 100644 --- a/shared/constants/settings-chat/index.tsx +++ b/shared/constants/settings-chat/index.tsx @@ -2,7 +2,7 @@ import * as T from '../types' import {ignorePromise} from '../utils' import * as S from '../strings' import * as Z from '@/util/zustand' -import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' export type ChatUnfurlState = { unfurlMode?: T.RPCChat.UnfurlMode @@ -49,7 +49,7 @@ export const useSettingsChatState = Z.createZustand((set, get) => { const dispatch: State['dispatch'] = { contactSettingsRefresh: () => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } try { @@ -67,7 +67,7 @@ export const useSettingsChatState = Z.createZustand((set, get) => { }, contactSettingsSaved: (enabled, indirectFollowees, teamsEnabled, teamsList) => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } @@ -100,7 +100,7 @@ export const useSettingsChatState = Z.createZustand((set, get) => { resetState: 'default', unfurlSettingsRefresh: () => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } try { @@ -128,7 +128,7 @@ export const useSettingsChatState = Z.createZustand((set, get) => { s.unfurl = T.castDraft({unfurlError: undefined, unfurlMode, unfurlWhitelist}) }) const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } try { diff --git a/shared/constants/settings-contacts.native.tsx b/shared/constants/settings-contacts.native.tsx index 2471a0051cbb..971a5bfdfab5 100644 --- a/shared/constants/settings-contacts.native.tsx +++ b/shared/constants/settings-contacts.native.tsx @@ -1,6 +1,6 @@ -import * as C from '.' import * as Contacts from 'expo-contacts' import {ignorePromise} from './utils' +import {importContactsWaitingKey} from './strings' import * as T from './types' import * as Z from '@/util/zustand' import {addNotificationRequest} from 'react-native-kb' @@ -11,7 +11,7 @@ import {getDefaultCountryCode} from 'react-native-kb' import {getE164} from './settings-phone' import {pluralize} from '@/util/string' import {navigateAppend} from './router2/util' -import {storeRegistry} from './store-registry' +import {useConfigState} from './config' import {useCurrentUserState} from './current-user' import {useWaitingState} from './waiting' @@ -89,7 +89,7 @@ export const useSettingsContactsState = Z.createZustand((set, get) => { } await T.RPCGen.configGuiSetValueRpcPromise( {path: importContactsConfigKey(username), value: {b: enable, isNull: false}}, - C.importContactsWaitingKey + importContactsWaitingKey ) get().dispatch.loadContactImportEnabled() } @@ -102,7 +102,7 @@ export const useSettingsContactsState = Z.createZustand((set, get) => { }, loadContactImportEnabled: () => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } const username = useCurrentUserState.getState().username @@ -114,7 +114,7 @@ export const useSettingsContactsState = Z.createZustand((set, get) => { try { const value = await T.RPCGen.configGuiGetValueRpcPromise( {path: importContactsConfigKey(username)}, - C.importContactsWaitingKey + importContactsWaitingKey ) enabled = !!value.b && !value.isNull } catch (error) { @@ -244,7 +244,7 @@ export const useSettingsContactsState = Z.createZustand((set, get) => { requestPermissions: (thenToggleImportOn?: boolean, fromSettings?: boolean) => { const f = async () => { const {decrement, increment} = useWaitingState.getState().dispatch - increment(C.importContactsWaitingKey) + increment(importContactsWaitingKey) const status = (await Contacts.requestPermissionsAsync()).status if (status === Contacts.PermissionStatus.GRANTED && thenToggleImportOn) { @@ -253,7 +253,7 @@ export const useSettingsContactsState = Z.createZustand((set, get) => { set(s => { s.permissionStatus = status }) - decrement(C.importContactsWaitingKey) + decrement(importContactsWaitingKey) } ignorePromise(f()) }, diff --git a/shared/constants/settings/index.tsx b/shared/constants/settings/index.tsx index 8832c7ff5792..16ffc111cdcf 100644 --- a/shared/constants/settings/index.tsx +++ b/shared/constants/settings/index.tsx @@ -10,6 +10,7 @@ import * as Tabs from '../tabs' import logger from '@/logger' import {clearModals, navigateAppend, switchTab} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' import {useCurrentUserState} from '../current-user' import {useWaitingState} from '../waiting' import {processorProfileInProgressKey, traceInProgressKey} from './util' @@ -59,7 +60,7 @@ export const useSettingsState = Z.createZustand(set => { return } - if (maybeLoadAppLinkOnce || !storeRegistry.getState('config').startup.link.endsWith('/phone-app')) { + if (maybeLoadAppLinkOnce || !useConfigState.getState().startup.link.endsWith('/phone-app')) { return } maybeLoadAppLinkOnce = true @@ -102,7 +103,7 @@ export const useSettingsState = Z.createZustand(set => { } await T.RPCGen.loginAccountDeleteRpcPromise({passphrase}, S.waitingKeySettingsGeneric) - storeRegistry.getState('config').dispatch.setJustDeletedSelf(username) + useConfigState.getState().dispatch.setJustDeletedSelf(username) clearModals() navigateAppend(Tabs.loginTab) } @@ -110,7 +111,7 @@ export const useSettingsState = Z.createZustand(set => { }, loadLockdownMode: () => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } try { @@ -142,7 +143,7 @@ export const useSettingsState = Z.createZustand(set => { }, loadSettings: () => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } try { @@ -226,7 +227,7 @@ export const useSettingsState = Z.createZustand(set => { }, setLockdownMode: enabled => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } try { diff --git a/shared/constants/signup/index.tsx b/shared/constants/signup/index.tsx index d5526f28da51..dfa015b6319a 100644 --- a/shared/constants/signup/index.tsx +++ b/shared/constants/signup/index.tsx @@ -10,6 +10,7 @@ import {RPCError} from '@/util/errors' import {isValidEmail, isValidName, isValidUsername} from '@/util/simple-validators' import {navigateAppend, navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' type Store = T.Immutable<{ devicename: string @@ -255,7 +256,7 @@ export const useSignupState = Z.createZustand((set, get) => { }) const f = async () => { // If we're logged in, we're coming from the user switcher; log out first to prevent the service from getting out of sync with the GUI about our logged-in-ness - if (storeRegistry.getState('config').loggedIn) { + if (useConfigState.getState().loggedIn) { await T.RPCGen.loginLogoutRpcPromise({force: false, keepSecrets: true}) } try { diff --git a/shared/constants/store-registry.tsx b/shared/constants/store-registry.tsx index 354d01a3fa1b..41e7718be585 100644 --- a/shared/constants/store-registry.tsx +++ b/shared/constants/store-registry.tsx @@ -9,12 +9,8 @@ import type {State as ArchiveState, useArchiveState} from './archive' import type {State as AutoResetState, useAutoResetState} from './autoreset' import type {State as BotsState, useBotsState} from './bots' import type {State as ChatState, useChatState} from './chat2' -import type {State as ConfigState, useConfigState} from './config' -import type {State as CryptoState, useCryptoState} from './crypto' import type {State as DaemonState, useDaemonState} from './daemon' -import type {State as DeepLinksState, useDeepLinksState} from './deeplinks' import type {State as DevicesState, useDevicesState} from './devices' -import type {State as EngineState, useEngineState} from './engine' import type {State as FSState, useFSState} from './fs' import type {State as GitState, useGitState} from './git' import type {State as NotificationsState, useNotifState} from './notifications' @@ -42,12 +38,8 @@ type StoreName = | 'autoreset' | 'bots' | 'chat' - | 'config' - | 'crypto' | 'daemon' - | 'deeplinks' | 'devices' - | 'engine' | 'fs' | 'git' | 'notifications' @@ -75,12 +67,8 @@ type StoreStates = { autoreset: AutoResetState bots: BotsState chat: ChatState - config: ConfigState - crypto: CryptoState daemon: DaemonState - deeplinks: DeepLinksState devices: DevicesState - engine: EngineState fs: FSState git: GitState notifications: NotificationsState @@ -109,12 +97,8 @@ type StoreHooks = { autoreset: typeof useAutoResetState bots: typeof useBotsState chat: typeof useChatState - config: typeof useConfigState - crypto: typeof useCryptoState daemon: typeof useDaemonState - deeplinks: typeof useDeepLinksState devices: typeof useDevicesState - engine: typeof useEngineState fs: typeof useFSState git: typeof useGitState notifications: typeof useNotifState @@ -161,30 +145,14 @@ class StoreRegistry { const {useChatState} = require('./chat2') return useChatState } - case 'config': { - const {useConfigState} = require('./config') - return useConfigState - } - case 'crypto': { - const {useCryptoState} = require('./crypto') - return useCryptoState - } case 'daemon': { const {useDaemonState} = require('./daemon') return useDaemonState } - case 'deeplinks': { - const {useDeepLinksState} = require('./deeplinks') - return useDeepLinksState - } case 'devices': { const {useDevicesState} = require('./devices') return useDevicesState } - case 'engine': { - const {useEngineState} = require('./engine') - return useEngineState - } case 'fs': { const {useFSState} = require('./fs') return useFSState diff --git a/shared/constants/team-building/index.tsx b/shared/constants/team-building/index.tsx index 0d838f7c2332..ddef3357d5dc 100644 --- a/shared/constants/team-building/index.tsx +++ b/shared/constants/team-building/index.tsx @@ -14,6 +14,7 @@ import {registerDebugClear} from '@/util/debug' import {searchWaitingKey} from './utils' import {navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' +import {useCryptoState} from '../crypto' export {allServices, selfToUser, searchWaitingKey} from './utils' type Store = T.Immutable<{ @@ -360,7 +361,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const {finishedTeam, namespace} = get() switch (namespace) { case 'crypto': { - storeRegistry.getState('crypto').dispatch.onTeamBuildingFinished(finishedTeam) + useCryptoState.getState().dispatch.onTeamBuildingFinished(finishedTeam) break } case 'chat2': { diff --git a/shared/constants/teams/index.tsx b/shared/constants/teams/index.tsx index 3c99b98e7e04..748e2fc01423 100644 --- a/shared/constants/teams/index.tsx +++ b/shared/constants/teams/index.tsx @@ -20,6 +20,7 @@ import {mapGetEnsureValue} from '@/util/map' import {bodyToJSON} from '../rpc-utils' import {fixCrop} from '@/util/crop' import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' import {useCurrentUserState} from '../current-user' import * as Util from './util' import {getTab} from '../router2/util' @@ -1792,7 +1793,7 @@ export const useTeamsState = Z.createZustand((set, get) => { const f = async () => { const username = useCurrentUserState.getState().username - const loggedIn = storeRegistry.getState('config').loggedIn + const loggedIn = useConfigState.getState().loggedIn if (!username || !loggedIn) { logger.warn('getTeams while logged out') return @@ -2308,7 +2309,7 @@ export const useTeamsState = Z.createZustand((set, get) => { break case EngineGen.keybase1NotifyBadgesBadgeState: { const {badgeState} = action.payload.params - const loggedIn = storeRegistry.getState('config').loggedIn + const loggedIn = useConfigState.getState().loggedIn if (loggedIn) { const deletedTeams = badgeState.deletedTeams || [] const newTeams = new Set(badgeState.newTeams || []) @@ -2539,14 +2540,14 @@ export const useTeamsState = Z.createZustand((set, get) => { const convID = T.Chat.keyToConversationID(conversationIDKey) await T.RPCChat.localJoinConversationByIDLocalRpcPromise({convID}, waitingKey) } catch (error) { - storeRegistry.getState('config').dispatch.setGlobalError(error) + useConfigState.getState().dispatch.setGlobalError(error) } } else { try { const convID = T.Chat.keyToConversationID(conversationIDKey) await T.RPCChat.localLeaveConversationLocalRpcPromise({convID}, waitingKey) } catch (error) { - storeRegistry.getState('config').dispatch.setGlobalError(error) + useConfigState.getState().dispatch.setGlobalError(error) } } } @@ -2659,14 +2660,14 @@ export const useTeamsState = Z.createZustand((set, get) => { teamID, }) } catch (payload) { - storeRegistry.getState('config').dispatch.setGlobalError(payload) + useConfigState.getState().dispatch.setGlobalError(payload) } } if (ignoreAccessRequests !== settings.ignoreAccessRequests) { try { await T.RPCGen.teamsSetTarsDisabledRpcPromise({disabled: settings.ignoreAccessRequests, teamID}) } catch (payload) { - storeRegistry.getState('config').dispatch.setGlobalError(payload) + useConfigState.getState().dispatch.setGlobalError(payload) } } if (publicityAnyMember !== settings.publicityAnyMember) { @@ -2676,7 +2677,7 @@ export const useTeamsState = Z.createZustand((set, get) => { teamID, }) } catch (payload) { - storeRegistry.getState('config').dispatch.setGlobalError(payload) + useConfigState.getState().dispatch.setGlobalError(payload) } } if (publicityMember !== settings.publicityMember) { @@ -2686,14 +2687,14 @@ export const useTeamsState = Z.createZustand((set, get) => { teamID, }) } catch (payload) { - storeRegistry.getState('config').dispatch.setGlobalError(payload) + useConfigState.getState().dispatch.setGlobalError(payload) } } if (publicityTeam !== settings.publicityTeam) { try { await T.RPCGen.teamsSetTeamShowcaseRpcPromise({isShowcased: settings.publicityTeam, teamID}) } catch (payload) { - storeRegistry.getState('config').dispatch.setGlobalError(payload) + useConfigState.getState().dispatch.setGlobalError(payload) } } } diff --git a/shared/constants/tracker2/index.tsx b/shared/constants/tracker2/index.tsx index 4d4e32101536..82d96edd041e 100644 --- a/shared/constants/tracker2/index.tsx +++ b/shared/constants/tracker2/index.tsx @@ -291,13 +291,13 @@ export const useTrackerState = Z.createZustand((set, get) => { } else if (error.code === T.RPCGen.StatusCode.scnotfound) { // we're on the profile page for a user that does not exist. Currently the only way // to get here is with an invalid link or deeplink. - storeRegistry - .getState('deeplinks') - .dispatch.setLinkError( - `You followed a profile link for a user (${assertion}) that does not exist.` - ) navigateUp() - navigateAppend('keybaseLinkError') + navigateAppend({ + props: { + error: `You followed a profile link for a user (${assertion}) that does not exist.`, + }, + selected: 'keybaseLinkError', + }) } // hooked into reloadable logger.error(`Error loading profile: ${error.message}`) diff --git a/shared/constants/unlock-folders/index.tsx b/shared/constants/unlock-folders/index.tsx index dc4a1d43ca00..9cc11c3b8352 100644 --- a/shared/constants/unlock-folders/index.tsx +++ b/shared/constants/unlock-folders/index.tsx @@ -3,8 +3,7 @@ import * as T from '../types' import * as Z from '@/util/zustand' import logger from '@/logger' import {getEngine} from '@/engine/require' -import type {State as ConfigStore} from '../config' -import {storeRegistry} from '../store-registry' +import {useConfigState, type State as ConfigStore} from '../config' type Store = T.Immutable<{ devices: ConfigStore['unlockFoldersDevices'] @@ -39,7 +38,7 @@ export const useUnlockFoldersState = Z.createZustand((set, _get) => { case EngineGen.keybase1RekeyUIRefresh: { const {problemSetDevices} = action.payload.params logger.info('Asked for rekey') - storeRegistry.getState('config').dispatch.openUnlockFolders(problemSetDevices.devices ?? []) + useConfigState.getState().dispatch.openUnlockFolders(problemSetDevices.devices ?? []) break } case EngineGen.keybase1RekeyUIDelegateRekeyUI: { @@ -49,7 +48,7 @@ export const useUnlockFoldersState = Z.createZustand((set, _get) => { dangling: true, incomingCallMap: { 'keybase.1.rekeyUI.refresh': ({problemSetDevices}) => { - storeRegistry.getState('config').dispatch.openUnlockFolders(problemSetDevices.devices ?? []) + useConfigState.getState().dispatch.openUnlockFolders(problemSetDevices.devices ?? []) }, 'keybase.1.rekeyUI.rekeySendEvent': () => {}, // ignored debug call from daemon }, diff --git a/shared/constants/wallets/index.tsx b/shared/constants/wallets/index.tsx index b6d0b28eff96..3843d7919ea1 100644 --- a/shared/constants/wallets/index.tsx +++ b/shared/constants/wallets/index.tsx @@ -2,7 +2,7 @@ import * as T from '../types' import {ignorePromise} from '../utils' import * as Z from '@/util/zustand' import {loadAccountsWaitingKey} from './utils' -import {storeRegistry} from '../store-registry' +import {useConfigState} from '../config' export {loadAccountsWaitingKey} from './utils' @@ -33,7 +33,7 @@ export const useState = Z.createZustand((set, get) => { const dispatch: State['dispatch'] = { load: () => { const f = async () => { - if (!storeRegistry.getState('config').loggedIn) { + if (!useConfigState.getState().loggedIn) { return } const res = await T.RPCStellar.localGetWalletAccountsLocalRpcPromise(undefined, [ diff --git a/shared/deeplinks/error.tsx b/shared/deeplinks/error.tsx index ed8a9cda94c5..6450b1b88b1f 100644 --- a/shared/deeplinks/error.tsx +++ b/shared/deeplinks/error.tsx @@ -1,6 +1,5 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import {useDeepLinksState} from '@/constants/deeplinks' type KeybaseLinkErrorBodyProps = { message: string @@ -21,9 +20,9 @@ export const KeybaseLinkErrorBody = (props: KeybaseLinkErrorBodyProps) => { ) } -const KeybaseLinkError = () => { - const deepError = useDeepLinksState(s => s.keybaseLinkError) - const message = deepError +const LinkError = (props: {error?: string}) => { + const error = props.error ?? 'Invalid page! (sorry)' + const message = error const isError = true const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) const onClose = () => navigateUp() @@ -48,4 +47,6 @@ const styles = Kb.Styles.styleSheetCreate(() => ({ }), })) -export default KeybaseLinkError +type OwnProps = C.ViewPropsToPageProps +const Screen = (p: OwnProps) => +export default Screen diff --git a/shared/desktop/renderer/main2.desktop.tsx b/shared/desktop/renderer/main2.desktop.tsx index 1f5a194af580..52b136dabe68 100644 --- a/shared/desktop/renderer/main2.desktop.tsx +++ b/shared/desktop/renderer/main2.desktop.tsx @@ -17,7 +17,7 @@ import type {default as NewMainType} from '../../app/main.desktop' import {setServiceDecoration} from '@/common-adapters/markdown/react' import ServiceDecoration from '@/common-adapters/markdown/service-decoration' import {useDarkModeState} from '@/constants/darkmode' -import {initPlatformListener} from '@/constants/platform-specific' +import {initPlatformListener} from '@/constants/init' setServiceDecoration(ServiceDecoration) const {ipcRendererOn, requestWindowsStartService, appStartedUp} = KB2.functions diff --git a/shared/engine/index-impl.tsx b/shared/engine/index-impl.tsx index 14f389095d1d..ac22a8e6b371 100644 --- a/shared/engine/index-impl.tsx +++ b/shared/engine/index-impl.tsx @@ -12,7 +12,7 @@ import {printOutstandingRPCs} from '@/local-debug' import {resetClient, createClient, rpcLog, type CreateClientType, type PayloadType} from './index.platform' import {type RPCError, convertToError} from '@/util/errors' import type * as EngineGen from '../actions/engine-gen-gen' -import type * as EngineConst from '@/constants/engine' +import type * as PlatSpecType from '@/constants/platform-specific/shared' // delay incoming to stop react from queueing too many setState calls and stopping rendering // only while debugging for now @@ -47,6 +47,7 @@ class Engine { _listenersAreReady: boolean = false _emitWaiting: (changes: BatchParams) => void + _incomingTimeout: NodeJS.Timeout | undefined _queuedChanges: Array<{error?: RPCError; increment: boolean; key: WaitingKey}> = [] dispatchWaitingAction = (key: WaitingKey, waiting: boolean, error?: RPCError) => { @@ -68,8 +69,15 @@ class Engine { this._onConnectedCB = onConnected // the node engine doesn't do this and we don't want to pull in any reqs if (allowIncomingCalls) { - const {useEngineState} = require('@/constants/engine') as typeof EngineConst - this._engineConstantsIncomingCall = useEngineState.getState().dispatch.onEngineIncoming + this._engineConstantsIncomingCall = (action: EngineGen.Actions) => { + // defer a frame so its more like before + this._incomingTimeout = setTimeout(() => { + // we delegate to these utils so we don't need to load stores that we don't need yet + const {onEngineIncoming: onEngineIncomingShared} = + require('@/constants/platform-specific/shared') as typeof PlatSpecType + onEngineIncomingShared(action) + }, 0) + } } this._emitWaiting = emitWaiting this._rpcClient = createClient( diff --git a/shared/provision/username-or-email.tsx b/shared/provision/username-or-email.tsx index 0ead30e44502..abf8e1800685 100644 --- a/shared/provision/username-or-email.tsx +++ b/shared/provision/username-or-email.tsx @@ -10,7 +10,7 @@ import UserCard from '@/login/user-card' import {SignupScreen, errorBanner} from '@/signup/common' import {useProvisionState} from '@/constants/provision' -type OwnProps = {fromReset?: boolean} +type OwnProps = {fromReset?: boolean; username?: string} const decodeInlineError = (inlineRPCError: RPCError | undefined) => { let inlineError = '' @@ -59,7 +59,12 @@ const UsernameOrEmailContainer = (op: OwnProps) => { }, [_setUsername, waiting] ) - const [username, setUsername] = React.useState(_username) + const [username, setUsername] = React.useState(op.username ?? _username) + React.useEffect(() => { + if (op.username && op.username !== _username) { + _setUsername?.(op.username) + } + }, [op.username, _username, _setUsername]) const onSubmit = React.useCallback(() => { _onSubmit(username) }, [_onSubmit, username]) diff --git a/shared/router-v2/hooks.native.tsx b/shared/router-v2/hooks.native.tsx index cba0b4cfaad0..bce95fef44e4 100644 --- a/shared/router-v2/hooks.native.tsx +++ b/shared/router-v2/hooks.native.tsx @@ -3,7 +3,7 @@ import * as Chat from '@/constants/chat2' import {useConfigState} from '@/constants/config' import * as Tabs from '@/constants/tabs' import * as React from 'react' -import {useDeepLinksState} from '@/constants/deeplinks' +import {handleAppLink} from '@/constants/deeplinks' import {Linking} from 'react-native' import {useColorScheme} from 'react-native' import {usePushState} from '@/constants/push' @@ -109,7 +109,7 @@ export const useInitialState = (loggedInLoaded: boolean) => { } if (url && isValidLink(url)) { - setTimeout(() => url && useDeepLinksState.getState().dispatch.handleAppLink(url), 1) + setTimeout(() => url && handleAppLink(url), 1) } else if (startupFollowUser && !startupConversation) { url = `keybase://profile/show/${startupFollowUser}` From b76e1d1ea214c79e2182f310d5b2218659e92af8 Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:14:11 -0500 Subject: [PATCH 09/20] WIP: shift 10 (#28787) * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/app/index.native.tsx | 5 +- shared/chat/conversation/normal/container.tsx | 3 +- shared/constants/active/index.tsx | 27 --- shared/constants/chat2/common.tsx | 4 +- shared/constants/config/index.tsx | 10 +- .../constants/{init.d.ts => init/index.d.ts} | 4 +- .../index.desktop.tsx} | 49 +++-- .../index.native.tsx} | 46 ++-- .../{platform-specific => init}/shared.tsx | 16 +- .../platform-specific/index.desktop.tsx | 185 ---------------- shared/constants/store-registry.tsx | 8 - shared/desktop/app/node2.desktop.tsx | 3 +- shared/desktop/renderer/main2.desktop.tsx | 197 +++++++++++++++++- shared/desktop/webpack.config.babel.js | 22 +- shared/engine/index-impl.tsx | 16 +- shared/engine/index.d.ts | 2 +- shared/package.json | 1 - shared/yarn.lock | 5 - 18 files changed, 277 insertions(+), 326 deletions(-) delete mode 100644 shared/constants/active/index.tsx rename shared/constants/{init.d.ts => init/index.d.ts} (53%) rename shared/constants/{init.desktop.tsx => init/index.desktop.tsx} (87%) rename shared/constants/{init.native.tsx => init/index.native.tsx} (93%) rename shared/constants/{platform-specific => init}/shared.tsx (96%) diff --git a/shared/app/index.native.tsx b/shared/app/index.native.tsx index ba51cb977b5d..9fbbeae4fbbd 100644 --- a/shared/app/index.native.tsx +++ b/shared/app/index.native.tsx @@ -19,8 +19,7 @@ import {useUnmountAll} from '@/util/debug-react' import {darkModeSupported, guiConfig} from 'react-native-kb' import {install} from 'react-native-kb' import * as DarkMode from '@/constants/darkmode' -import {onEngineConnected, onEngineDisconnected} from '@/constants/platform-specific/shared' -import {initPlatformListener} from '@/constants/init' +import {initPlatformListener, onEngineConnected, onEngineDisconnected, onEngineIncoming} from '@/constants/init/index.native' enableFreeze(true) setServiceDecoration(ServiceDecoration) @@ -139,7 +138,7 @@ const useInit = () => { } else { onEngineDisconnected() } - }) + }, onEngineIncoming) initPlatformListener() eng.listenersAreReady() diff --git a/shared/chat/conversation/normal/container.tsx b/shared/chat/conversation/normal/container.tsx index fd38892d4b89..dbbb9157900a 100644 --- a/shared/chat/conversation/normal/container.tsx +++ b/shared/chat/conversation/normal/container.tsx @@ -4,7 +4,6 @@ import {useConfigState} from '@/constants/config' import * as React from 'react' import Normal from '.' import * as T from '@/constants/types' -import {useActiveState} from '@/constants/active' import {FocusProvider, ScrollProvider} from './context' import {OrangeLineContext} from '../orange-line-context' @@ -51,7 +50,7 @@ const useOrangeLine = () => { // just use the rpc for orange line if we're not active // if we are active we want to keep whatever state we had so it is maintained - const active = useActiveState(s => s.active) + const active = useConfigState(s => s.active) React.useEffect(() => { if (!active) { loadOrangeLine() diff --git a/shared/constants/active/index.tsx b/shared/constants/active/index.tsx deleted file mode 100644 index cf53cc33b318..000000000000 --- a/shared/constants/active/index.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import * as Chat from '../chat2' -import type * as T from '../types' -import * as Z from '@/util/zustand' -import {storeRegistry} from '../store-registry' - -type Store = T.Immutable<{active: boolean}> -const initialStore: Store = {active: true} - -export interface State extends Store { - dispatch: { - resetState: 'default' - setActive: (a: boolean) => void - } -} -export const useActiveState = Z.createZustand(set => { - const dispatch: State['dispatch'] = { - resetState: 'default', - setActive: a => { - set(s => { - s.active = a - }) - const cs = storeRegistry.getConvoState(Chat.getSelectedConversation()) - cs.dispatch.markThreadAsRead() - }, - } - return {...initialStore, dispatch} -}) diff --git a/shared/constants/chat2/common.tsx b/shared/constants/chat2/common.tsx index 51a74d6fba21..8c63c456b387 100644 --- a/shared/constants/chat2/common.tsx +++ b/shared/constants/chat2/common.tsx @@ -1,7 +1,6 @@ import * as T from '../types' import {isMobile, isTablet} from '../platform' import * as Router2 from '../router2' -import {storeRegistry} from '../store-registry' import {useConfigState} from '../config' export const explodingModeGregorKeyPrefix = 'exploding:' @@ -31,8 +30,7 @@ export const isUserActivelyLookingAtThisThread = (conversationIDKey: T.Chat.Conv (maybeVisibleScreen === undefined ? undefined : maybeVisibleScreen.name) === threadRouteName } - const {appFocused} = useConfigState.getState() - const {active: userActive} = storeRegistry.getState('active') + const {appFocused, active: userActive} = useConfigState.getState() return ( appFocused && // app focused? diff --git a/shared/constants/config/index.tsx b/shared/constants/config/index.tsx index f52577a959cc..9d52e0338fc9 100644 --- a/shared/constants/config/index.tsx +++ b/shared/constants/config/index.tsx @@ -15,7 +15,7 @@ import {invalidPasswordErrorString} from './util' import {navigateAppend} from '../router2/util' type Store = T.Immutable<{ - forceSmallNav: boolean + active: boolean allowAnimatedEmojis: boolean androidShare?: | {type: T.RPCGen.IncomingShareType.file; urls: Array} @@ -24,6 +24,7 @@ type Store = T.Immutable<{ badgeState?: T.RPCGen.BadgeState configuredAccounts: Array defaultUsername: string + forceSmallNav: boolean globalError?: Error | RPCError gregorReachable?: T.RPCGen.Reachable gregorPushState: Array<{md: T.RPCGregor.Metadata; item: T.RPCGregor.Item}> @@ -82,6 +83,7 @@ type Store = T.Immutable<{ }> const initialStore: Store = { + active: true, allowAnimatedEmojis: true, androidShare: undefined, appFocused: true, @@ -180,6 +182,7 @@ export interface State extends Store { revoke: (deviceName: string, wasCurrentDevice: boolean) => void refreshAccounts: () => Promise setAccounts: (a: Store['configuredAccounts']) => void + setActive: (a: boolean) => void setAndroidShare: (s: Store['androidShare']) => void setBadgeState: (b: State['badgeState']) => void setDefaultUsername: (u: string) => void @@ -665,6 +668,11 @@ export const useConfigState = Z.createZustand((set, get) => { } }) }, + setActive: a => { + set(s => { + s.active = a + }) + }, setAndroidShare: share => { set(s => { s.androidShare = T.castDraft(share) diff --git a/shared/constants/init.d.ts b/shared/constants/init/index.d.ts similarity index 53% rename from shared/constants/init.d.ts rename to shared/constants/init/index.d.ts index aa0eb1800753..f08146c34c87 100644 --- a/shared/constants/init.d.ts +++ b/shared/constants/init/index.d.ts @@ -1,5 +1,7 @@ +// links all the stores together, stores never import this import type * as EngineGen from '@/actions/engine-gen-gen' export declare function initPlatformListener(): void +export declare function onEngineConnected(): void +export declare function onEngineDisconnected(): void export declare function onEngineIncoming(action: EngineGen.Actions): void - diff --git a/shared/constants/init.desktop.tsx b/shared/constants/init/index.desktop.tsx similarity index 87% rename from shared/constants/init.desktop.tsx rename to shared/constants/init/index.desktop.tsx index 910c0f076402..90e9d5834292 100644 --- a/shared/constants/init.desktop.tsx +++ b/shared/constants/init/index.desktop.tsx @@ -1,31 +1,39 @@ -import * as Chat from './chat2' -import {ignorePromise} from './utils' -import {useActiveState} from './active' -import {useConfigState} from './config' -import * as ConfigConstants from './config' -import {useDaemonState} from './daemon' -import {useFSState} from './fs' -import {useProfileState} from './profile' -import {useRouterState} from './router2' +// links all the stores together, stores never import this +import * as Chat from '../chat2' +import {ignorePromise} from '../utils' +import {useConfigState} from '../config' +import * as ConfigConstants from '../config' +import {useDaemonState} from '../daemon' +import {useFSState} from '../fs' +import {useProfileState} from '../profile' +import {useRouterState} from '../router2' import * as EngineGen from '@/actions/engine-gen-gen' -import * as T from './types' -import InputMonitor from './platform-specific/input-monitor.desktop' +import * as T from '../types' +import InputMonitor from '../platform-specific/input-monitor.desktop' import KB2 from '@/util/electron.desktop' import logger from '@/logger' import type {RPCError} from '@/util/errors' import {getEngine} from '@/engine' -import {isLinux, isWindows} from './platform.desktop' -import {kbfsNotification} from './platform-specific/kbfs-notifications' +import {isLinux, isWindows} from '../platform.desktop' +import {kbfsNotification} from '../platform-specific/kbfs-notifications' import {skipAppFocusActions} from '@/local-debug.desktop' import NotifyPopup from '@/util/notify-popup' -import {noKBFSFailReason} from './config/util' -import {initSharedSubscriptions} from './platform-specific/shared' +import {noKBFSFailReason} from '../config/util' +import {initSharedSubscriptions, _onEngineIncoming} from './shared' import {wrapErrors} from '@/util/debug' -import {dumpLogs} from './platform-specific/index.desktop' -const {showMainWindow, activeChanged, requestWindowsStartService} = KB2.functions +const {showMainWindow, activeChanged, requestWindowsStartService, ctlQuit, dumpNodeLogger} = KB2.functions const {quitApp, exitApp, setOpenAtLogin, copyToClipboard} = KB2.functions +const dumpLogs = async (reason?: string) => { + await logger.dump() + await (dumpNodeLogger?.() ?? Promise.resolve([])) + // quit as soon as possible + if (reason === 'quitting through menu') { + ctlQuit?.() + } +} + const maybePauseVideos = () => { const {appFocused} = useConfigState.getState() const videos = document.querySelectorAll('video') @@ -51,6 +59,7 @@ const maybePauseVideos = () => { } export const onEngineIncoming = (action: EngineGen.Actions) => { + _onEngineIncoming(action) switch (action.type) { case EngineGen.keybase1LogsendPrepareLogsend: { const f = async () => { @@ -128,7 +137,6 @@ export const initPlatformListener = () => { } ignorePromise(f()) }) - }) useConfigState.subscribe((s, old) => { @@ -252,7 +260,7 @@ export const initPlatformListener = () => { if (skipAppFocusActions) { console.log('Skipping app focus actions!') } else { - useActiveState.getState().dispatch.setActive(userActive) + useConfigState.getState().dispatch.setActive(userActive) // let node thread save file activeChanged?.(Date.now(), userActive) } @@ -270,6 +278,7 @@ export const initPlatformListener = () => { }) initSharedSubscriptions() - ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) } + +export {onEngineConnected, onEngineDisconnected} from './shared' diff --git a/shared/constants/init.native.tsx b/shared/constants/init/index.native.tsx similarity index 93% rename from shared/constants/init.native.tsx rename to shared/constants/init/index.native.tsx index 31ec34f7d372..39a02773ae59 100644 --- a/shared/constants/init.native.tsx +++ b/shared/constants/init/index.native.tsx @@ -1,26 +1,27 @@ -import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from './utils' -import {useChatState} from './chat2' -import {useConfigState} from './config' -import {useCurrentUserState} from './current-user' -import {useDaemonState} from './daemon' -import {useDarkModeState} from './darkmode' -import {useFSState} from './fs' -import {useProfileState} from './profile' -import {useRouterState} from './router2' -import {useSettingsContactsState} from './settings-contacts' -import * as T from './types' +// links all the stores together, stores never import this +import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from '../utils' +import {useChatState} from '../chat2' +import {useConfigState} from '../config' +import {useCurrentUserState} from '../current-user' +import {useDaemonState} from '../daemon' +import {useDarkModeState} from '../darkmode' +import {useFSState} from '../fs' +import {useProfileState} from '../profile' +import {useRouterState} from '../router2' +import {useSettingsContactsState} from '../settings-contacts' +import * as T from '../types' import * as Clipboard from 'expo-clipboard' import * as EngineGen from '@/actions/engine-gen-gen' import * as ExpoLocation from 'expo-location' import * as ExpoTaskManager from 'expo-task-manager' -import * as Tabs from './tabs' +import * as Tabs from '../tabs' import * as NetInfo from '@react-native-community/netinfo' import NotifyPopup from '@/util/notify-popup' import logger from '@/logger' import {Alert, Linking} from 'react-native' -import {isAndroid} from './platform.native' +import {isAndroid} from '../platform.native' import {wrapErrors} from '@/util/debug' -import {getTab, getVisiblePath, logState} from './router2' +import {getTab, getVisiblePath, logState} from '../router2' import {launchImageLibraryAsync} from '@/util/expo-image-picker.native' import {setupAudioMode} from '@/util/audio.native' import { @@ -31,13 +32,13 @@ import { guiConfig, shareListenersRegistered, } from 'react-native-kb' -import {initPushListener, getStartupDetailsFromInitialPush} from './platform-specific/push.native' -import {initSharedSubscriptions} from './platform-specific/shared' +import {initPushListener, getStartupDetailsFromInitialPush} from '../platform-specific/push.native' +import {initSharedSubscriptions, _onEngineIncoming} from './shared' import type {ImageInfo} from '@/util/expo-image-picker.native' -import {noConversationIDKey} from './types/chat2/common' -import {getSelectedConversation} from './chat2/common' -import {getConvoState} from './chat2/convostate' -import {requestLocationPermission, showShareActionSheet} from './platform-specific/index.native' +import {noConversationIDKey} from '../types/chat2/common' +import {getSelectedConversation} from '../chat2/common' +import {getConvoState} from '../chat2/convostate' +import {requestLocationPermission, showShareActionSheet} from '../platform-specific/index.native' const loadStartupDetails = async () => { const [routeState, initialUrl, push] = await Promise.all([ @@ -204,6 +205,7 @@ const onChatClearWatch = async () => { } export const onEngineIncoming = (action: EngineGen.Actions) => { + _onEngineIncoming(action) switch (action.type) { case EngineGen.chat1ChatUiTriggerContactSync: useSettingsContactsState.getState().dispatch.manageContactsCache() @@ -266,7 +268,6 @@ export const initPlatformListener = () => { } ignorePromise(f()) }) - }) useConfigState.subscribe((s, old) => { @@ -484,7 +485,6 @@ export const initPlatformListener = () => { } ignorePromise(f()) }) - }) useRouterState.setState(s => { @@ -504,3 +504,5 @@ export const initPlatformListener = () => { ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) } + +export {onEngineConnected, onEngineDisconnected} from './shared' diff --git a/shared/constants/platform-specific/shared.tsx b/shared/constants/init/shared.tsx similarity index 96% rename from shared/constants/platform-specific/shared.tsx rename to shared/constants/init/shared.tsx index 417cddd4cc44..8ed40061299a 100644 --- a/shared/constants/platform-specific/shared.tsx +++ b/shared/constants/init/shared.tsx @@ -8,6 +8,7 @@ import * as AutoResetUtil from '../autoreset/util' import * as AvatarUtil from '@/common-adapters/avatar/util' import * as BotsUtil from '../bots/util' import {useChatState} from '../chat2' +import {getSelectedConversation} from '../chat2/common' import * as ChatUtil from '../chat2/util' import {useConfigState} from '../config' import {useCurrentUserState} from '../current-user' @@ -32,7 +33,6 @@ import * as TrackerUtil from '../tracker2/util' import * as UnlockFoldersUtil from '../unlock-folders/util' import * as UsersUtil from '../users/util' import {useWhatsNewState} from '../whats-new' -import {onEngineIncoming as onEngineIncomingPlatform} from '../init' let _emitStartupOnLoadDaemonConnectedOnce = false @@ -56,7 +56,6 @@ export const onEngineDisconnected = () => { } export const initSharedSubscriptions = () => { - useConfigState.subscribe((s, old) => { if (s.loadOnStartPhase !== old.loadOnStartPhase) { if (s.loadOnStartPhase === 'startupOrReloginButNotInARush') { @@ -175,6 +174,11 @@ export const initSharedSubscriptions = () => { const lastSeenItem = s.gregorPushState.find(i => i.item.category === 'whatsNewLastSeenVersion') useWhatsNewState.getState().dispatch.updateLastSeen(lastSeenItem) } + + if (s.active !== old.active) { + const cs = storeRegistry.getConvoState(getSelectedConversation()) + cs.dispatch.markThreadAsRead() + } }) useDaemonState.subscribe((s, old) => { @@ -229,10 +233,7 @@ export const initSharedSubscriptions = () => { const f = async () => { // If we're logged in, we're coming from the user switcher; log out first to prevent the service from getting out of sync with the GUI about our logged-in-ness if (useConfigState.getState().loggedIn) { - await T.RPCGen.loginLogoutRpcPromise( - {force: false, keepSecrets: true}, - 'config:loginAsOther' - ) + await T.RPCGen.loginLogoutRpcPromise({force: false, keepSecrets: true}, 'config:loginAsOther') } } ignorePromise(f()) @@ -240,13 +241,12 @@ export const initSharedSubscriptions = () => { }) } -export const onEngineIncoming = (action: EngineGen.Actions) => { +export const _onEngineIncoming = (action: EngineGen.Actions) => { ArchiveUtil.onEngineIncoming(action) AutoResetUtil.onEngineIncoming(action) AvatarUtil.onEngineIncoming(action) BotsUtil.onEngineIncoming(action) ChatUtil.onEngineIncoming(action) - onEngineIncomingPlatform(action) useConfigState.getState().dispatch.onEngineIncoming(action) DeepLinksUtil.onEngineIncoming(action) DevicesUtil.onEngineIncoming(action) diff --git a/shared/constants/platform-specific/index.desktop.tsx b/shared/constants/platform-specific/index.desktop.tsx index 72e46a605293..425732a96ab7 100644 --- a/shared/constants/platform-specific/index.desktop.tsx +++ b/shared/constants/platform-specific/index.desktop.tsx @@ -1,18 +1,3 @@ -import {ignorePromise} from '../utils' -import {useConfigState} from '../config' -import {usePinentryState} from '../pinentry' -import * as RemoteGen from '@/actions/remote-gen' -import * as T from '../types' -import KB2 from '@/util/electron.desktop' -import logger from '@/logger' -import {RPCError} from '@/util/errors' -import {switchTab} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {onEngineConnected, onEngineDisconnected} from '@/constants/platform-specific/shared' -import {handleAppLink, handleSaltPackOpen} from '../deeplinks' - -const {ctlQuit, dumpNodeLogger} = KB2.functions - export const requestPermissionsToWrite = async () => { return Promise.resolve(true) } @@ -26,173 +11,3 @@ export async function saveAttachmentToCameraRoll() { export const requestLocationPermission = async () => Promise.resolve() export const watchPositionForMap = async () => Promise.resolve(() => {}) - -export const dumpLogs = async (reason?: string) => { - await logger.dump() - await (dumpNodeLogger?.() ?? Promise.resolve([])) - // quit as soon as possible - if (reason === 'quitting through menu') { - ctlQuit?.() - } -} - -const updateApp = () => { - const f = async () => { - await T.RPCGen.configStartUpdateIfNeededRpcPromise() - } - ignorePromise(f()) - // * If user choose to update: - // We'd get killed and it doesn't matter what happens here. - // * If user hits "Ignore": - // Note that we ignore the snooze here, so the state shouldn't change, - // and we'd back to where we think we still need an update. So we could - // have just unset the "updating" flag.However, in case server has - // decided to pull out the update between last time we asked the updater - // and now, we'd be in a wrong state if we didn't check with the service. - // Since user has interacted with it, we still ask the service to make - // sure. - - useConfigState.getState().dispatch.setUpdating() -} - -export const eventFromRemoteWindows = (action: RemoteGen.Actions) => { - switch (action.type) { - case RemoteGen.resetStore: - break - case RemoteGen.openChatFromWidget: { - useConfigState.getState().dispatch.showMain() - storeRegistry.getConvoState(action.payload.conversationIDKey).dispatch.navigateToThread('inboxSmall') - break - } - case RemoteGen.inboxRefresh: { - storeRegistry.getState('chat').dispatch.inboxRefresh('widgetRefresh') - break - } - case RemoteGen.engineConnection: { - if (action.payload.connected) { - onEngineConnected() - } else { - onEngineDisconnected() - } - break - } - case RemoteGen.switchTab: { - switchTab(action.payload.tab) - break - } - case RemoteGen.setCriticalUpdate: { - storeRegistry.getState('fs').dispatch.setCriticalUpdate(action.payload.critical) - break - } - case RemoteGen.userFileEditsLoad: { - storeRegistry.getState('fs').dispatch.userFileEditsLoad() - break - } - case RemoteGen.openFilesFromWidget: { - storeRegistry.getState('fs').dispatch.dynamic.openFilesFromWidgetDesktop?.(action.payload.path) - break - } - case RemoteGen.saltpackFileOpen: { - handleSaltPackOpen(action.payload.path) - break - } - case RemoteGen.pinentryOnCancel: { - usePinentryState.getState().dispatch.dynamic.onCancel?.() - break - } - case RemoteGen.pinentryOnSubmit: { - usePinentryState.getState().dispatch.dynamic.onSubmit?.(action.payload.password) - break - } - case RemoteGen.openPathInSystemFileManager: { - storeRegistry.getState('fs').dispatch.dynamic.openPathInSystemFileManagerDesktop?.(action.payload.path) - break - } - case RemoteGen.unlockFoldersSubmitPaperKey: { - T.RPCGen.loginPaperKeySubmitRpcPromise({paperPhrase: action.payload.paperKey}, 'unlock-folders:waiting') - .then(() => { - useConfigState.getState().dispatch.openUnlockFolders([]) - }) - .catch((e: unknown) => { - if (!(e instanceof RPCError)) return - useConfigState.setState(s => { - s.unlockFoldersError = e.desc - }) - }) - break - } - case RemoteGen.closeUnlockFolders: { - T.RPCGen.rekeyRekeyStatusFinishRpcPromise() - .then(() => {}) - .catch(() => {}) - useConfigState.getState().dispatch.openUnlockFolders([]) - break - } - case RemoteGen.stop: { - storeRegistry.getState('settings').dispatch.stop(action.payload.exitCode) - break - } - case RemoteGen.trackerChangeFollow: { - storeRegistry.getState('tracker2').dispatch.changeFollow(action.payload.guiID, action.payload.follow) - break - } - case RemoteGen.trackerIgnore: { - storeRegistry.getState('tracker2').dispatch.ignore(action.payload.guiID) - break - } - case RemoteGen.trackerCloseTracker: { - storeRegistry.getState('tracker2').dispatch.closeTracker(action.payload.guiID) - break - } - case RemoteGen.trackerLoad: { - storeRegistry.getState('tracker2').dispatch.load(action.payload) - break - } - case RemoteGen.link: - { - const {link} = action.payload - handleAppLink(link) - } - break - case RemoteGen.installerRan: - useConfigState.getState().dispatch.installerRan() - break - case RemoteGen.updateNow: - updateApp() - break - case RemoteGen.powerMonitorEvent: - useConfigState.getState().dispatch.powerMonitorEvent(action.payload.event) - break - case RemoteGen.showMain: - useConfigState.getState().dispatch.showMain() - break - case RemoteGen.dumpLogs: - ignorePromise(useConfigState.getState().dispatch.dumpLogs(action.payload.reason)) - break - case RemoteGen.remoteWindowWantsProps: - useConfigState - .getState() - .dispatch.remoteWindowNeedsProps(action.payload.component, action.payload.param) - break - case RemoteGen.updateWindowMaxState: - useConfigState.setState(s => { - s.windowState.isMaximized = action.payload.max - }) - break - case RemoteGen.updateWindowState: - useConfigState.getState().dispatch.updateWindowState(action.payload.windowState) - break - case RemoteGen.updateWindowShown: { - const win = action.payload.component - useConfigState.setState(s => { - s.windowShownCount.set(win, (s.windowShownCount.get(win) ?? 0) + 1) - }) - break - } - case RemoteGen.previewConversation: - storeRegistry - .getState('chat') - .dispatch.previewConversation({participants: [action.payload.participant], reason: 'tracker'}) - break - } -} diff --git a/shared/constants/store-registry.tsx b/shared/constants/store-registry.tsx index 41e7718be585..7ec2ba533c69 100644 --- a/shared/constants/store-registry.tsx +++ b/shared/constants/store-registry.tsx @@ -4,7 +4,6 @@ import type * as T from './types' import type * as TBType from './team-building' import type * as ConvoStateType from './chat2/convostate' import type {ConvoState} from './chat2/convostate' -import type {State as ActiveState, useActiveState} from './active' import type {State as ArchiveState, useArchiveState} from './archive' import type {State as AutoResetState, useAutoResetState} from './autoreset' import type {State as BotsState, useBotsState} from './bots' @@ -33,7 +32,6 @@ import type {State as UnlockFoldersState, useUnlockFoldersState} from './unlock- import type {State as UsersState, useUsersState} from './users' type StoreName = - | 'active' | 'archive' | 'autoreset' | 'bots' @@ -62,7 +60,6 @@ type StoreName = | 'users' type StoreStates = { - active: ActiveState archive: ArchiveState autoreset: AutoResetState bots: BotsState @@ -92,7 +89,6 @@ type StoreStates = { } type StoreHooks = { - active: typeof useActiveState archive: typeof useArchiveState autoreset: typeof useAutoResetState bots: typeof useBotsState @@ -125,10 +121,6 @@ class StoreRegistry { getStore(storeName: T): StoreHooks[T] { /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return */ switch (storeName) { - case 'active': { - const {useActiveState} = require('./active') - return useActiveState - } case 'archive': { const {useArchiveState} = require('./archive') return useArchiveState diff --git a/shared/desktop/app/node2.desktop.tsx b/shared/desktop/app/node2.desktop.tsx index 7d3b6c8db307..6b65e04f06ce 100644 --- a/shared/desktop/app/node2.desktop.tsx +++ b/shared/desktop/app/node2.desktop.tsx @@ -427,8 +427,7 @@ const plumbEvents = () => { () => {}, (c: boolean) => { R.remoteDispatch(RemoteGen.createEngineConnection({connected: c})) - }, - false + } ) const timeoutPromise = async (timeMs: number) => diff --git a/shared/desktop/renderer/main2.desktop.tsx b/shared/desktop/renderer/main2.desktop.tsx index 52b136dabe68..806f02d32eae 100644 --- a/shared/desktop/renderer/main2.desktop.tsx +++ b/shared/desktop/renderer/main2.desktop.tsx @@ -4,23 +4,202 @@ import Main from '@/app/main.desktop' import * as C from '@/constants' import * as React from 'react' import * as ReactDOM from 'react-dom/client' -import type * as RemoteGen from '@/actions/remote-gen' +import * as RemoteGen from '@/actions/remote-gen' import Root from './container.desktop' import {makeEngine} from '@/engine' import {disableDragDrop} from '@/util/drag-drop.desktop' -import {dumpLogs, eventFromRemoteWindows} from '@/constants/platform-specific/index.desktop' import {initDesktopStyles} from '@/styles/index.desktop' import {isWindows} from '@/constants/platform' import KB2 from '@/util/electron.desktop' +import {ignorePromise} from '@/constants/utils' +import {useConfigState} from '@/constants/config' +import {usePinentryState} from '@/constants/pinentry' +import * as T from '@/constants/types' +import {RPCError} from '@/util/errors' +import {switchTab} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {onEngineConnected, onEngineDisconnected} from '@/constants/init/index.desktop' +import {handleAppLink, handleSaltPackOpen} from '@/constants/deeplinks' +import logger from '@/logger' import {debugWarning} from '@/util/debug-warning' import type {default as NewMainType} from '../../app/main.desktop' import {setServiceDecoration} from '@/common-adapters/markdown/react' import ServiceDecoration from '@/common-adapters/markdown/service-decoration' import {useDarkModeState} from '@/constants/darkmode' -import {initPlatformListener} from '@/constants/init' +import {initPlatformListener, onEngineIncoming} from '@/constants/init/index.desktop' setServiceDecoration(ServiceDecoration) -const {ipcRendererOn, requestWindowsStartService, appStartedUp} = KB2.functions +const {ipcRendererOn, requestWindowsStartService, appStartedUp, ctlQuit, dumpNodeLogger} = KB2.functions + +const dumpLogs = async (reason?: string) => { + await logger.dump() + await (dumpNodeLogger?.() ?? Promise.resolve([])) + // quit as soon as possible + if (reason === 'quitting through menu') { + ctlQuit?.() + } +} + +const updateApp = () => { + const f = async () => { + await T.RPCGen.configStartUpdateIfNeededRpcPromise() + } + ignorePromise(f()) + // * If user choose to update: + // We'd get killed and it doesn't matter what happens here. + // * If user hits "Ignore": + // Note that we ignore the snooze here, so the state shouldn't change, + // and we'd back to where we think we still need an update. So we could + // have just unset the "updating" flag.However, in case server has + // decided to pull out the update between last time we asked the updater + // and now, we'd be in a wrong state if we didn't check with the service. + // Since user has interacted with it, we still ask the service to make + // sure. + + useConfigState.getState().dispatch.setUpdating() +} + +const eventFromRemoteWindows = (action: RemoteGen.Actions) => { + switch (action.type) { + case RemoteGen.resetStore: + break + case RemoteGen.openChatFromWidget: { + useConfigState.getState().dispatch.showMain() + storeRegistry.getConvoState(action.payload.conversationIDKey).dispatch.navigateToThread('inboxSmall') + break + } + case RemoteGen.inboxRefresh: { + storeRegistry.getState('chat').dispatch.inboxRefresh('widgetRefresh') + break + } + case RemoteGen.engineConnection: { + if (action.payload.connected) { + onEngineConnected() + } else { + onEngineDisconnected() + } + break + } + case RemoteGen.switchTab: { + switchTab(action.payload.tab) + break + } + case RemoteGen.setCriticalUpdate: { + storeRegistry.getState('fs').dispatch.setCriticalUpdate(action.payload.critical) + break + } + case RemoteGen.userFileEditsLoad: { + storeRegistry.getState('fs').dispatch.userFileEditsLoad() + break + } + case RemoteGen.openFilesFromWidget: { + storeRegistry.getState('fs').dispatch.dynamic.openFilesFromWidgetDesktop?.(action.payload.path) + break + } + case RemoteGen.saltpackFileOpen: { + handleSaltPackOpen(action.payload.path) + break + } + case RemoteGen.pinentryOnCancel: { + usePinentryState.getState().dispatch.dynamic.onCancel?.() + break + } + case RemoteGen.pinentryOnSubmit: { + usePinentryState.getState().dispatch.dynamic.onSubmit?.(action.payload.password) + break + } + case RemoteGen.openPathInSystemFileManager: { + storeRegistry.getState('fs').dispatch.dynamic.openPathInSystemFileManagerDesktop?.(action.payload.path) + break + } + case RemoteGen.unlockFoldersSubmitPaperKey: { + T.RPCGen.loginPaperKeySubmitRpcPromise({paperPhrase: action.payload.paperKey}, 'unlock-folders:waiting') + .then(() => { + useConfigState.getState().dispatch.openUnlockFolders([]) + }) + .catch((e: unknown) => { + if (!(e instanceof RPCError)) return + useConfigState.setState(s => { + s.unlockFoldersError = e.desc + }) + }) + break + } + case RemoteGen.closeUnlockFolders: { + T.RPCGen.rekeyRekeyStatusFinishRpcPromise() + .then(() => {}) + .catch(() => {}) + useConfigState.getState().dispatch.openUnlockFolders([]) + break + } + case RemoteGen.stop: { + storeRegistry.getState('settings').dispatch.stop(action.payload.exitCode) + break + } + case RemoteGen.trackerChangeFollow: { + storeRegistry.getState('tracker2').dispatch.changeFollow(action.payload.guiID, action.payload.follow) + break + } + case RemoteGen.trackerIgnore: { + storeRegistry.getState('tracker2').dispatch.ignore(action.payload.guiID) + break + } + case RemoteGen.trackerCloseTracker: { + storeRegistry.getState('tracker2').dispatch.closeTracker(action.payload.guiID) + break + } + case RemoteGen.trackerLoad: { + storeRegistry.getState('tracker2').dispatch.load(action.payload) + break + } + case RemoteGen.link: + { + const {link} = action.payload + handleAppLink(link) + } + break + case RemoteGen.installerRan: + useConfigState.getState().dispatch.installerRan() + break + case RemoteGen.updateNow: + updateApp() + break + case RemoteGen.powerMonitorEvent: + useConfigState.getState().dispatch.powerMonitorEvent(action.payload.event) + break + case RemoteGen.showMain: + useConfigState.getState().dispatch.showMain() + break + case RemoteGen.dumpLogs: + ignorePromise(useConfigState.getState().dispatch.dumpLogs(action.payload.reason)) + break + case RemoteGen.remoteWindowWantsProps: + useConfigState + .getState() + .dispatch.remoteWindowNeedsProps(action.payload.component, action.payload.param) + break + case RemoteGen.updateWindowMaxState: + useConfigState.setState(s => { + s.windowState.isMaximized = action.payload.max + }) + break + case RemoteGen.updateWindowState: + useConfigState.getState().dispatch.updateWindowState(action.payload.windowState) + break + case RemoteGen.updateWindowShown: { + const win = action.payload.component + useConfigState.setState(s => { + s.windowShownCount.set(win, (s.windowShownCount.get(win) ?? 0) + 1) + }) + break + } + case RemoteGen.previewConversation: + storeRegistry + .getState('chat') + .dispatch.previewConversation({participants: [action.payload.participant], reason: 'tracker'}) + break + } +} // node side plumbs through initial pref so we avoid flashes const darkModeFromNode = window.location.search.match(/darkMode=(light|dark)/) @@ -48,9 +227,13 @@ const setupApp = () => { disableDragDrop() const {batch} = C.useWaitingState.getState().dispatch - const eng = makeEngine(batch, () => { - // do nothing we wait for the remote version from node - }) + const eng = makeEngine( + batch, + () => { + // do nothing we wait for the remote version from node + }, + onEngineIncoming + ) initPlatformListener() eng.listenersAreReady() diff --git a/shared/desktop/webpack.config.babel.js b/shared/desktop/webpack.config.babel.js index 061ead3748fc..b14d20a5fbf0 100644 --- a/shared/desktop/webpack.config.babel.js +++ b/shared/desktop/webpack.config.babel.js @@ -8,22 +8,19 @@ import path from 'path' import webpack from 'webpack' import HtmlWebpackPlugin from 'html-webpack-plugin' import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin' -import CircularDependencyPlugin from 'circular-dependency-plugin' const ignoredModules = require('../ignored-modules') const enableWDYR = require('../util/why-did-you-render-enabled') const elecVersion = require('../package.json').devDependencies.electron // true if you want to debug unused code. This makes single chunks so you can grep for 'unused harmony' in the output in desktop/dist const debugUnusedChunks = false -const enableCircularDepCheck = false const evalDevtools = false -if (enableWDYR || debugUnusedChunks || enableCircularDepCheck || evalDevtools) { +if (enableWDYR || debugUnusedChunks || evalDevtools) { for (let i = 0; i < 10; ++i) { console.error('Webpack debugging on!!!', { enableWDYR, debugUnusedChunks, - enableCircularDepCheck, evalDevtools, }) } @@ -188,23 +185,6 @@ const config = (_, {mode}) => { new webpack.DefinePlugin(defines), // Inject some defines new webpack.IgnorePlugin({resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/}), // Skip a bunch of crap moment pulls in ...(enableWDYR ? [] : [new webpack.IgnorePlugin({resourceRegExp: /^lodash$/})]), // Disallow entire lodash, but needed by why did - ...(isDev && enableCircularDepCheck - ? [ - new CircularDependencyPlugin({ - // exclude detection of files based on a RegExp - exclude: /node_modules/, - // include specific files based on a RegExp - // include: /dir/, - // add errors to webpack instead of warnings - failOnError: true, - // allow import cycles that include an asyncronous import, - // e.g. via import(/* webpackMode: "weak" */ './file.js') - allowAsyncCycles: false, - // set the current working directory for displaying module paths - cwd: process.cwd(), - }), - ] - : []), ], resolve: { alias, diff --git a/shared/engine/index-impl.tsx b/shared/engine/index-impl.tsx index ac22a8e6b371..14513d9c5fa5 100644 --- a/shared/engine/index-impl.tsx +++ b/shared/engine/index-impl.tsx @@ -12,7 +12,6 @@ import {printOutstandingRPCs} from '@/local-debug' import {resetClient, createClient, rpcLog, type CreateClientType, type PayloadType} from './index.platform' import {type RPCError, convertToError} from '@/util/errors' import type * as EngineGen from '../actions/engine-gen-gen' -import type * as PlatSpecType from '@/constants/platform-specific/shared' // delay incoming to stop react from queueing too many setState calls and stopping rendering // only while debugging for now @@ -48,6 +47,7 @@ class Engine { _emitWaiting: (changes: BatchParams) => void _incomingTimeout: NodeJS.Timeout | undefined + _onEngineIncoming?: (action: EngineGen.Actions) => void _queuedChanges: Array<{error?: RPCError; increment: boolean; key: WaitingKey}> = [] dispatchWaitingAction = (key: WaitingKey, waiting: boolean, error?: RPCError) => { @@ -64,18 +64,16 @@ class Engine { constructor( emitWaiting: (changes: BatchParams) => void, onConnected: (c: boolean) => void, - allowIncomingCalls = true + onEngineIncoming?: (action: EngineGen.Actions) => void ) { this._onConnectedCB = onConnected + this._onEngineIncoming = onEngineIncoming // the node engine doesn't do this and we don't want to pull in any reqs - if (allowIncomingCalls) { + if (onEngineIncoming) { this._engineConstantsIncomingCall = (action: EngineGen.Actions) => { // defer a frame so its more like before this._incomingTimeout = setTimeout(() => { - // we delegate to these utils so we don't need to load stores that we don't need yet - const {onEngineIncoming: onEngineIncomingShared} = - require('@/constants/platform-specific/shared') as typeof PlatSpecType - onEngineIncomingShared(action) + this._onEngineIncoming?.(action) }, 0) } } @@ -290,14 +288,14 @@ if (__DEV__) { const makeEngine = ( emitWaiting: (b: BatchParams) => void, onConnected: (c: boolean) => void, - allowIncomingCalls = true + onEngineIncoming?: (action: EngineGen.Actions) => void ) => { if (__DEV__ && engine) { logger.warn('makeEngine called multiple times') } if (!engine) { - engine = new Engine(emitWaiting, onConnected, allowIncomingCalls) + engine = new Engine(emitWaiting, onConnected, onEngineIncoming) initEngine(engine) initEngineListener(engineListener) } diff --git a/shared/engine/index.d.ts b/shared/engine/index.d.ts index cd74ba25e572..e352925abb33 100644 --- a/shared/engine/index.d.ts +++ b/shared/engine/index.d.ts @@ -29,7 +29,7 @@ export declare function getEngine(): Engine export declare function makeEngine( emitWaiting: (b: BatchParams) => void, onConnected: (c: boolean) => void, - allowIncomingCalls?: boolean + onEngineIncoming?: (action: EngineGen.Actions) => void ): Engine export default getEngine export type {IncomingCallMapType, CustomResponseIncomingCallMapType} diff --git a/shared/package.json b/shared/package.json index 1b4105ce3b16..6d49122c9ccc 100644 --- a/shared/package.json +++ b/shared/package.json @@ -162,7 +162,6 @@ "babel-plugin-react-compiler": "1.0.0", "babel-plugin-react-native-web": "0.21.2", "babel-preset-expo": "54.0.9", - "circular-dependency-plugin": "5.2.2", "cross-env": "7.0.3", "css-loader": "7.1.2", "electron": "39.2.7", diff --git a/shared/yarn.lock b/shared/yarn.lock index bc7751b485bd..c34c2116b814 100644 --- a/shared/yarn.lock +++ b/shared/yarn.lock @@ -4383,11 +4383,6 @@ ci-info@^3.2.0, ci-info@^3.3.0, ci-info@^3.7.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -circular-dependency-plugin@5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz#39e836079db1d3cf2f988dc48c5188a44058b600" - integrity sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ== - classnames@2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" From a9b4317be3aeb118a0b203847336fada0f013ba0 Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Fri, 9 Jan 2026 13:29:21 -0500 Subject: [PATCH 10/20] WIP shift 11 (#28788) * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/constants/archive/index.tsx | 24 +- shared/constants/archive/util.tsx | 5 +- shared/constants/autoreset/index.tsx | 4 +- shared/constants/chat2/convostate.tsx | 8 +- shared/constants/deeplinks/index.tsx | 4 +- shared/constants/fs/index.tsx | 1071 ++----------------- shared/constants/fs/util.tsx | 947 +++++++++++++++- shared/constants/git/index.tsx | 6 +- shared/constants/recover-password/index.tsx | 22 +- shared/constants/store-registry.tsx | 16 - shared/constants/teams/index.tsx | 24 +- shared/settings/archive/modal.tsx | 23 +- 12 files changed, 1059 insertions(+), 1095 deletions(-) diff --git a/shared/constants/archive/index.tsx b/shared/constants/archive/index.tsx index e9a894ee24c8..dd132f0e3133 100644 --- a/shared/constants/archive/index.tsx +++ b/shared/constants/archive/index.tsx @@ -2,12 +2,10 @@ import * as T from '../types' import * as Z from '@/util/zustand' import {ignorePromise} from '../utils' import * as EngineGen from '@/actions/engine-gen-gen' -import * as FS from '@/constants/fs' +import {pathToRPCPath} from '@/constants/fs/util' import {formatTimeForPopup} from '@/util/timestamp' import {uint8ArrayToHex} from 'uint8array-extras' -import {storeRegistry} from '../store-registry' import {isMobile} from '../platform' -import {useCurrentUserState} from '../current-user' type ChatJob = { id: string @@ -90,7 +88,6 @@ export interface State extends Store { onEngineIncomingImpl: (action: EngineGen.Actions) => void resetState: 'default' } - chatIDToDisplayname: (id: string) => string } export const useArchiveState = Z.createZustand((set, get) => { @@ -280,7 +277,7 @@ export const useArchiveState = Z.createZustand((set, get) => { await T.RPCGen.SimpleFSSimpleFSArchiveStartRpcPromise({ archiveJobStartPath: { archiveJobStartPathType: T.RPCGen.ArchiveJobStartPathType.kbfs, - kbfs: FS.pathToRPCPath(path).kbfs, + kbfs: pathToRPCPath(path).kbfs, }, outputPath: outPath, overwriteZip: true, @@ -448,23 +445,6 @@ export const useArchiveState = Z.createZustand((set, get) => { } return { ...initialStore, - chatIDToDisplayname: (conversationIDKey: string) => { - const you = useCurrentUserState.getState().username - const cs = storeRegistry.getConvoState(conversationIDKey) - const m = cs.meta - if (m.teamname) { - if (m.channelname) { - return `${m.teamname}#${m.channelname}` - } - return m.teamname - } - - const participants = cs.participants.name - if (participants.length === 1) { - return participants[0] ?? '' - } - return participants.filter(username => username !== you).join(',') - }, dispatch, } }) diff --git a/shared/constants/archive/util.tsx b/shared/constants/archive/util.tsx index e44657ebf42e..3be104f15ecb 100644 --- a/shared/constants/archive/util.tsx +++ b/shared/constants/archive/util.tsx @@ -1,5 +1,5 @@ import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' +import type * as UseArchiveStateType from '../archive' export const onEngineIncoming = (action: EngineGen.Actions) => { switch (action.type) { @@ -7,7 +7,8 @@ export const onEngineIncoming = (action: EngineGen.Actions) => { case EngineGen.chat1NotifyChatChatArchiveComplete: case EngineGen.chat1NotifyChatChatArchiveProgress: { - storeRegistry.getState('archive').dispatch.onEngineIncomingImpl(action) + const {useArchiveState} = require('../archive') as typeof UseArchiveStateType + useArchiveState.getState().dispatch.onEngineIncomingImpl(action) } break default: diff --git a/shared/constants/autoreset/index.tsx b/shared/constants/autoreset/index.tsx index b7c0910473b7..f1d7ed2efaa5 100644 --- a/shared/constants/autoreset/index.tsx +++ b/shared/constants/autoreset/index.tsx @@ -140,9 +140,7 @@ export const useAutoResetState = Z.createZustand((set, get) => { s.endTime = params.endTime * 1000 }) } - storeRegistry - .getState('router') - .dispatch.navigateAppend( + navigateAppend( {props: {pipelineStarted: !params.needVerify}, selected: 'resetWaiting'}, true ) diff --git a/shared/constants/chat2/convostate.tsx b/shared/constants/chat2/convostate.tsx index d3b5bc0b6a91..fe96a91842d7 100644 --- a/shared/constants/chat2/convostate.tsx +++ b/shared/constants/chat2/convostate.tsx @@ -2170,9 +2170,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { clearModals() } - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {conversationIDKey}, selected: Common.threadRouteName}, replace) + navigateAppend({props: {conversationIDKey}, selected: Common.threadRouteName}, replace) } } updateNav() @@ -3331,14 +3329,12 @@ export const ProviderScreen = React.memo(function ProviderScreen(p: { import type {NavigateAppendType} from '@/router-v2/route-params' export const useChatNavigateAppend = () => { - const useRouterState = storeRegistry.getStore('router') - const navigateAppend = useRouterState(s => s.dispatch.navigateAppend) const cid = useChatContext(s => s.id) return React.useCallback( (makePath: (cid: T.Chat.ConversationIDKey) => NavigateAppendType, replace?: boolean) => { navigateAppend(makePath(cid), replace) }, - [cid, navigateAppend] + [cid] ) } diff --git a/shared/constants/deeplinks/index.tsx b/shared/constants/deeplinks/index.tsx index 97d432d954eb..a81ec61f4f5f 100644 --- a/shared/constants/deeplinks/index.tsx +++ b/shared/constants/deeplinks/index.tsx @@ -168,9 +168,7 @@ export const handleKeybaseLink = (link: string) => { try { const decoded = decodeURIComponent(link) switchTab(Tabs.fsTab) - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {path: `/keybase/${decoded}`}, selected: 'fsRoot'}) + navigateAppend({props: {path: `/keybase/${decoded}`}, selected: 'fsRoot'}) return } catch { logger.warn("Coudn't decode KBFS URI") diff --git a/shared/constants/fs/index.tsx b/shared/constants/fs/index.tsx index afccb5d7f7bc..f3d94d5b13f5 100644 --- a/shared/constants/fs/index.tsx +++ b/shared/constants/fs/index.tsx @@ -8,295 +8,18 @@ import * as Z from '@/util/zustand' import NotifyPopup from '@/util/notify-popup' import {RPCError} from '@/util/errors' import logger from '@/logger' -import {isLinux, isMobile} from '../platform' import {tlfToPreferredOrder} from '@/util/kbfs' import isObject from 'lodash/isObject' import isEqual from 'lodash/isEqual' -import {settingsFsTab} from '../settings/util' import {navigateAppend, navigateUp} from '../router2/util' import {storeRegistry} from '../store-registry' import {useConfigState} from '../config' import {useCurrentUserState} from '../current-user' +import * as Util from './util' -export {makeActionForOpenPathInFilesTab} from './util' +export * from './util' const subscriptionDeduplicateIntervalSecond = 1 -export const defaultPath = T.FS.stringToPath('/keybase') - -export const rpcFolderTypeToTlfType = (rpcFolderType: T.RPCGen.FolderType) => { - switch (rpcFolderType) { - case T.RPCGen.FolderType.private: - return T.FS.TlfType.Private - case T.RPCGen.FolderType.public: - return T.FS.TlfType.Public - case T.RPCGen.FolderType.team: - return T.FS.TlfType.Team - default: - return null - } -} - -export const rpcConflictStateToConflictState = ( - rpcConflictState?: T.RPCGen.ConflictState -): T.FS.ConflictState => { - if (rpcConflictState) { - if (rpcConflictState.conflictStateType === T.RPCGen.ConflictStateType.normalview) { - const nv = rpcConflictState.normalview - return makeConflictStateNormalView({ - localViewTlfPaths: (nv.localViews || []).reduce>((arr, p) => { - p.PathType === T.RPCGen.PathType.kbfs && arr.push(rpcPathToPath(p.kbfs)) - return arr - }, []), - resolvingConflict: nv.resolvingConflict, - stuckInConflict: nv.stuckInConflict, - }) - } else { - const nv = rpcConflictState.manualresolvinglocalview.normalView - return makeConflictStateManualResolvingLocalView({ - normalViewTlfPath: nv.PathType === T.RPCGen.PathType.kbfs ? rpcPathToPath(nv.kbfs) : defaultPath, - }) - } - } else { - return tlfNormalViewWithNoConflict - } -} - -export const getSyncConfigFromRPC = ( - tlfName: string, - tlfType: T.FS.TlfType, - config?: T.RPCGen.FolderSyncConfig -): T.FS.TlfSyncConfig => { - if (!config) { - return tlfSyncDisabled - } - switch (config.mode) { - case T.RPCGen.FolderSyncMode.disabled: - return tlfSyncDisabled - case T.RPCGen.FolderSyncMode.enabled: - return tlfSyncEnabled - case T.RPCGen.FolderSyncMode.partial: - return makeTlfSyncPartial({ - enabledPaths: config.paths - ? config.paths.map(str => T.FS.getPathFromRelative(tlfName, tlfType, str)) - : [], - }) - default: - return tlfSyncDisabled - } -} - -// See Installer.m: KBExitFuseKextError -export const ExitCodeFuseKextError = 4 -// See Installer.m: KBExitFuseKextPermissionError -export const ExitCodeFuseKextPermissionError = 5 -// See Installer.m: KBExitAuthCanceledError -export const ExitCodeAuthCanceledError = 6 - -export const emptyNewFolder: T.FS.Edit = { - error: undefined, - name: 'New Folder', - originalName: 'New Folder', - parentPath: T.FS.stringToPath('/keybase'), - type: T.FS.EditType.NewFolder, -} - -export const prefetchNotStarted: T.FS.PrefetchNotStarted = { - state: T.FS.PrefetchState.NotStarted, -} - -export const prefetchComplete: T.FS.PrefetchComplete = { - state: T.FS.PrefetchState.Complete, -} - -export const emptyPrefetchInProgress: T.FS.PrefetchInProgress = { - bytesFetched: 0, - bytesTotal: 0, - endEstimate: 0, - startTime: 0, - state: T.FS.PrefetchState.InProgress, -} - -const pathItemMetadataDefault = { - lastModifiedTimestamp: 0, - lastWriter: '', - name: 'unknown', - prefetchStatus: prefetchNotStarted, - size: 0, - writable: false, -} - -export const emptyFolder: T.FS.FolderPathItem = { - ...pathItemMetadataDefault, - children: new Set(), - progress: T.FS.ProgressType.Pending, - type: T.FS.PathType.Folder, -} - -export const emptyFile: T.FS.FilePathItem = { - ...pathItemMetadataDefault, - type: T.FS.PathType.File, -} - -export const emptySymlink: T.FS.SymlinkPathItem = { - ...pathItemMetadataDefault, - linkTarget: '', - type: T.FS.PathType.Symlink, -} - -export const unknownPathItem: T.FS.UnknownPathItem = { - ...pathItemMetadataDefault, - type: T.FS.PathType.Unknown, -} - -export const tlfSyncEnabled: T.FS.TlfSyncEnabled = { - mode: T.FS.TlfSyncMode.Enabled, -} - -export const tlfSyncDisabled: T.FS.TlfSyncDisabled = { - mode: T.FS.TlfSyncMode.Disabled, -} - -export const makeTlfSyncPartial = ({ - enabledPaths, -}: { - enabledPaths?: T.FS.TlfSyncPartial['enabledPaths'] -}): T.FS.TlfSyncPartial => ({ - enabledPaths: [...(enabledPaths || [])], - mode: T.FS.TlfSyncMode.Partial, -}) - -export const makeConflictStateNormalView = ({ - localViewTlfPaths, - resolvingConflict, - stuckInConflict, -}: Partial): T.FS.ConflictStateNormalView => ({ - localViewTlfPaths: [...(localViewTlfPaths || [])], - resolvingConflict: resolvingConflict || false, - stuckInConflict: stuckInConflict || false, - type: T.FS.ConflictStateType.NormalView, -}) - -export const tlfNormalViewWithNoConflict = makeConflictStateNormalView({}) - -export const makeConflictStateManualResolvingLocalView = ({ - normalViewTlfPath, -}: Partial): T.FS.ConflictStateManualResolvingLocalView => ({ - normalViewTlfPath: normalViewTlfPath || defaultPath, - type: T.FS.ConflictStateType.ManualResolvingLocalView, -}) - -export const makeTlf = (p: Partial): T.FS.Tlf => { - const {conflictState, isFavorite, isIgnored, isNew, name, resetParticipants, syncConfig, teamId, tlfMtime} = - p - return { - conflictState: conflictState || tlfNormalViewWithNoConflict, - isFavorite: isFavorite || false, - isIgnored: isIgnored || false, - isNew: isNew || false, - name: name || '', - resetParticipants: [...(resetParticipants || [])], - syncConfig: syncConfig || tlfSyncDisabled, - teamId: teamId || '', - tlfMtime: tlfMtime || 0, - /* See comment in constants/types/fs.js - needsRekey: false, - waitingForParticipantUnlock: I.List(), - youCanUnlock: I.List(), - */ - } -} - -export const emptySyncingFoldersProgress: T.FS.SyncingFoldersProgress = { - bytesFetched: 0, - bytesTotal: 0, - endEstimate: 0, - start: 0, -} - -export const emptyOverallSyncStatus: T.FS.OverallSyncStatus = { - diskSpaceStatus: T.FS.DiskSpaceStatus.Ok, - showingBanner: false, - syncingFoldersProgress: emptySyncingFoldersProgress, -} - -export const defaultPathUserSetting: T.FS.PathUserSetting = { - sort: T.FS.SortSetting.NameAsc, -} - -export const defaultTlfListPathUserSetting: T.FS.PathUserSetting = { - sort: T.FS.SortSetting.TimeAsc, -} - -export const emptyDownloadState: T.FS.DownloadState = { - canceled: false, - done: false, - endEstimate: 0, - error: '', - localPath: '', - progress: 0, -} - -export const emptyDownloadInfo: T.FS.DownloadInfo = { - filename: '', - isRegularDownload: false, - path: defaultPath, - startTime: 0, -} - -export const emptyPathItemActionMenu: T.FS.PathItemActionMenu = { - downloadID: undefined, - downloadIntent: undefined, - previousView: T.FS.PathItemActionMenuView.Root, - view: T.FS.PathItemActionMenuView.Root, -} - -export const driverStatusUnknown: T.FS.DriverStatusUnknown = { - type: T.FS.DriverStatusType.Unknown, -} as const - -export const emptyDriverStatusEnabled: T.FS.DriverStatusEnabled = { - dokanOutdated: false, - dokanUninstallExecPath: undefined, - isDisabling: false, - type: T.FS.DriverStatusType.Enabled, -} as const - -export const emptyDriverStatusDisabled: T.FS.DriverStatusDisabled = { - isEnabling: false, - kextPermissionError: false, - type: T.FS.DriverStatusType.Disabled, -} as const - -export const defaultDriverStatus: T.FS.DriverStatus = isLinux ? emptyDriverStatusEnabled : driverStatusUnknown - -export const unknownKbfsDaemonStatus: T.FS.KbfsDaemonStatus = { - onlineStatus: T.FS.KbfsDaemonOnlineStatus.Unknown, - rpcStatus: T.FS.KbfsDaemonRpcStatus.Waiting, -} - -export const emptySettings: T.FS.Settings = { - isLoading: false, - loaded: false, - sfmiBannerDismissed: false, - spaceAvailableNotificationThreshold: 0, - syncOnCellular: false, -} - -export const emptyPathInfo: T.FS.PathInfo = { - deeplinkPath: '', - platformAfterMountPath: '', -} - -export const emptyFileContext: T.FS.FileContext = { - contentType: '', - url: '', - viewType: T.RPCGen.GUIViewType.default, -} - -export const getPathItem = ( - pathItems: T.Immutable>, - path: T.Immutable -): T.Immutable => pathItems.get(path) || (unknownPathItem as T.FS.PathItem) // RPC expects a string that's interpreted as [16]byte on Go side and it has to // be unique among all ongoing ops at any given time. uuidv1 may exceed 16 @@ -315,254 +38,11 @@ export const makeUUID = () => { } export const clientID = makeUUID() -export const pathToRPCPath = ( - path: T.FS.Path -): {PathType: T.RPCGen.PathType.kbfs; kbfs: T.RPCGen.KBFSPath} => ({ - PathType: T.RPCGen.PathType.kbfs, - kbfs: { - identifyBehavior: T.RPCGen.TLFIdentifyBehavior.fsGui, - path: T.FS.pathToString(path).substring('/keybase'.length) || '/', - }, -}) - -export const rpcPathToPath = (rpcPath: T.RPCGen.KBFSPath) => T.FS.pathConcat(defaultPath, rpcPath.path) - -export const pathTypeToTextType = (type: T.FS.PathType) => - type === T.FS.PathType.Folder ? 'BodySemibold' : 'Body' - -export const splitTlfIntoUsernames = (tlf: string): ReadonlyArray => - tlf.split(' ')[0]?.replace(/#/g, ',').split(',') ?? [] - -export const getUsernamesFromPath = (path: T.FS.Path): ReadonlyArray => { - const elems = T.FS.getPathElements(path) - return elems.length < 3 ? [] : splitTlfIntoUsernames(elems[2]!) -} - -export const humanReadableFileSize = (size: number) => { - const kib = 1024 - const mib = kib * kib - const gib = mib * kib - const tib = gib * kib - - if (!size) return '' - if (size >= tib) return `${Math.round(size / tib)} TB` - if (size >= gib) return `${Math.round(size / gib)} GB` - if (size >= mib) return `${Math.round(size / mib)} MB` - if (size >= kib) return `${Math.round(size / kib)} KB` - return `${size} B` -} - -export const downloadIsOngoing = (dlState: T.FS.DownloadState) => - dlState !== emptyDownloadState && !dlState.error && !dlState.done && !dlState.canceled - -export const getDownloadIntent = ( - path: T.FS.Path, - downloads: T.FS.Downloads, - pathItemActionMenu: T.FS.PathItemActionMenu -): T.FS.DownloadIntent | undefined => { - const found = [...downloads.info].find(([_, info]) => info.path === path) - if (!found) { - return undefined - } - const [downloadID] = found - const dlState = downloads.state.get(downloadID) || emptyDownloadState - if (!downloadIsOngoing(dlState)) { - return undefined - } - if (pathItemActionMenu.downloadID === downloadID) { - return pathItemActionMenu.downloadIntent - } - return T.FS.DownloadIntent.None -} - -export const emptyTlfUpdate: T.FS.TlfUpdate = { - history: [], - path: T.FS.stringToPath(''), - serverTime: 0, - writer: '', -} - -export const emptyTlfEdit: T.FS.TlfEdit = { - editType: T.FS.FileEditType.Unknown, - filename: '', - serverTime: 0, -} - -const fsNotificationTypeToEditType = ( - fsNotificationType: T.RPCChat.Keybase1.FSNotificationType -): T.FS.FileEditType => { - switch (fsNotificationType) { - case T.RPCGen.FSNotificationType.fileCreated: - return T.FS.FileEditType.Created - case T.RPCGen.FSNotificationType.fileModified: - return T.FS.FileEditType.Modified - case T.RPCGen.FSNotificationType.fileDeleted: - return T.FS.FileEditType.Deleted - case T.RPCGen.FSNotificationType.fileRenamed: - return T.FS.FileEditType.Renamed - default: - return T.FS.FileEditType.Unknown - } -} - -export const userTlfHistoryRPCToState = ( - history: ReadonlyArray -): T.FS.UserTlfUpdates => { - let updates: Array = [] - history.forEach(folder => { - const updateServerTime = folder.serverTime - const path = pathFromFolderRPC(folder.folder) - const tlfUpdates = folder.history - ? folder.history.map(({writerName, edits}) => ({ - history: edits - ? edits.map(({filename, notificationType, serverTime}) => ({ - editType: fsNotificationTypeToEditType(notificationType), - filename, - serverTime, - })) - : [], - path, - serverTime: updateServerTime, - writer: writerName, - })) - : [] - updates = updates.concat(tlfUpdates) - }) - return updates -} - -export const canSaveMedia = (pathItem: T.FS.PathItem, fileContext: T.FS.FileContext): boolean => { - if (pathItem.type !== T.FS.PathType.File || fileContext === emptyFileContext) { - return false - } - return ( - fileContext.viewType === T.RPCGen.GUIViewType.image || fileContext.viewType === T.RPCGen.GUIViewType.video - ) -} - -export const folderRPCFromPath = (path: T.FS.Path): T.RPCGen.FolderHandle | undefined => { - const pathElems = T.FS.getPathElements(path) - if (pathElems.length === 0) return undefined - - const visibility = T.FS.getVisibilityFromElems(pathElems) - if (visibility === undefined) return undefined - - const name = T.FS.getPathNameFromElems(pathElems) - if (name === '') return undefined - - return { - created: false, - folderType: T.FS.getRPCFolderTypeFromVisibility(visibility), - name, - } -} - -export const pathFromFolderRPC = (folder: T.RPCGen.Folder): T.FS.Path => { - const visibility = T.FS.getVisibilityFromRPCFolderType(folder.folderType) - if (!visibility) return T.FS.stringToPath('') - return T.FS.stringToPath(`/keybase/${visibility}/${folder.name}`) -} - -export const showIgnoreFolder = (path: T.FS.Path, username?: string): boolean => { - const elems = T.FS.getPathElements(path) - if (elems.length !== 3) { - return false - } - return ['public', 'private'].includes(elems[1]!) && elems[2]! !== username -} - -export const syntheticEventToTargetRect = (evt?: React.SyntheticEvent): DOMRect | undefined => - isMobile ? undefined : evt ? (evt.target as HTMLElement).getBoundingClientRect() : undefined - -export const invalidTokenError = new Error('invalid token') -export const notFoundError = new Error('not found') export const makeEditID = (): T.FS.EditID => T.FS.stringToEditID(makeUUID()) -export const getTlfListFromType = ( - tlfs: T.Immutable, - tlfType: T.Immutable -): T.Immutable => { - switch (tlfType) { - case T.FS.TlfType.Private: - return tlfs.private - case T.FS.TlfType.Public: - return tlfs.public - case T.FS.TlfType.Team: - return tlfs.team - default: - return new Map() - } -} - -export const computeBadgeNumberForTlfList = (tlfList: T.Immutable): number => - [...tlfList.values()].reduce((accumulator, tlf) => (tlfIsBadged(tlf) ? accumulator + 1 : accumulator), 0) - -export const computeBadgeNumberForAll = (tlfs: T.Immutable): number => - [T.FS.TlfType.Private, T.FS.TlfType.Public, T.FS.TlfType.Team] - .map(tlfType => computeBadgeNumberForTlfList(getTlfListFromType(tlfs, tlfType))) - .reduce((sum, count) => sum + count, 0) - -export const getTlfPath = (path: T.FS.Path): T.FS.Path => { - const elems = T.FS.getPathElements(path) - return elems.length > 2 ? T.FS.pathConcat(T.FS.pathConcat(defaultPath, elems[1]!), elems[2]!) : undefined -} - -export const getTlfListAndTypeFromPath = ( - tlfs: T.Immutable, - path: T.Immutable -): T.Immutable<{ - tlfList: T.FS.TlfList - tlfType: T.FS.TlfType -}> => { - const visibility = T.FS.getPathVisibility(path) - switch (visibility) { - case T.FS.TlfType.Private: - case T.FS.TlfType.Public: - case T.FS.TlfType.Team: { - const tlfType: T.FS.TlfType = visibility - return {tlfList: getTlfListFromType(tlfs, tlfType), tlfType} - } - default: - return {tlfList: new Map(), tlfType: T.FS.TlfType.Private} - } -} - -export const unknownTlf = makeTlf({}) -export const getTlfFromPathInFavoritesOnly = (tlfs: T.Immutable, path: T.FS.Path): T.FS.Tlf => { - const elems = T.FS.getPathElements(path) - if (elems.length < 3) { - return unknownTlf - } - const {tlfList} = getTlfListAndTypeFromPath(tlfs, path) - return tlfList.get(elems[2]!) || unknownTlf -} - -export const getTlfFromPath = (tlfs: T.Immutable, path: T.FS.Path): T.FS.Tlf => { - const fromFavorites = getTlfFromPathInFavoritesOnly(tlfs, path) - return fromFavorites !== unknownTlf - ? fromFavorites - : tlfs.additionalTlfs.get(getTlfPath(path)) || unknownTlf -} - -export const getTlfFromTlfs = (tlfs: T.FS.Tlfs, tlfType: T.FS.TlfType, name: string): T.FS.Tlf => { - switch (tlfType) { - case T.FS.TlfType.Private: - return tlfs.private.get(name) || unknownTlf - case T.FS.TlfType.Public: - return tlfs.public.get(name) || unknownTlf - case T.FS.TlfType.Team: - return tlfs.team.get(name) || unknownTlf - default: - return unknownTlf - } -} - -export const tlfTypeAndNameToPath = (tlfType: T.FS.TlfType, name: string): T.FS.Path => - T.FS.stringToPath(`/keybase/${tlfType}/${name}`) - export const resetBannerType = (s: State, path: T.FS.Path): T.FS.ResetBannerType => { - const resetParticipants = getTlfFromPath(s.tlfs, path).resetParticipants + const resetParticipants = Util.getTlfFromPath(s.tlfs, path).resetParticipants if (resetParticipants.length === 0) { return T.FS.ResetBannerNoOthersType.None } @@ -574,424 +54,11 @@ export const resetBannerType = (s: State, path: T.FS.Path): T.FS.ResetBannerType return resetParticipants.length } -export const getUploadedPath = (parentPath: T.FS.Path, localPath: string) => - T.FS.pathConcat(parentPath, T.FS.getLocalPathName(localPath)) - -export const usernameInPath = (username: string, path: T.FS.Path) => { - const elems = T.FS.getPathElements(path) - return elems.length >= 3 && elems[2]!.split(',').includes(username) -} - -export const getUsernamesFromTlfName = (tlfName: string): Array => { - const split = splitTlfIntoReadersAndWriters(tlfName) - return split.writers.concat(split.readers || []) -} - -export const isOfflineUnsynced = ( - daemonStatus: T.FS.KbfsDaemonStatus, - pathItem: T.FS.PathItem, - path: T.FS.Path -) => - daemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline && - T.FS.getPathLevel(path) > 2 && - pathItem.prefetchStatus !== prefetchComplete - -// To make sure we have consistent badging, all badging related stuff should go -// through this function. That is: -// * When calculating number of TLFs being badged, a TLF should be counted if -// and only if this function returns true. -// * When an individual TLF is shown (e.g. as a row), it should be badged if -// and only if this funciton returns true. -// -// If we add more badges, this function should be updated. -export const tlfIsBadged = (tlf: T.FS.Tlf) => !tlf.isIgnored && tlf.isNew - -export const pathsInSameTlf = (a: T.FS.Path, b: T.FS.Path): boolean => { - const elemsA = T.FS.getPathElements(a) - const elemsB = T.FS.getPathElements(b) - return elemsA.length >= 3 && elemsB.length >= 3 && elemsA[1] === elemsB[1] && elemsA[2] === elemsB[2] -} - -const slashKeybaseSlashLength = '/keybase/'.length -// TODO: move this to Go -export const escapePath = (path: T.FS.Path): string => - 'keybase://' + - encodeURIComponent(T.FS.pathToString(path).slice(slashKeybaseSlashLength)).replace( - // We need to do this because otherwise encodeURIComponent would encode - // "/"s. - /%2F/g, - '/' - ) - -export const parsedPathRoot: T.FS.ParsedPathRoot = {kind: T.FS.PathKind.Root} - -export const parsedPathPrivateList: T.FS.ParsedPathTlfList = { - kind: T.FS.PathKind.TlfList, - tlfType: T.FS.TlfType.Private, -} - -export const parsedPathPublicList: T.FS.ParsedPathTlfList = { - kind: T.FS.PathKind.TlfList, - tlfType: T.FS.TlfType.Public, -} - -export const parsedPathTeamList: T.FS.ParsedPathTlfList = { - kind: T.FS.PathKind.TlfList, - tlfType: T.FS.TlfType.Team, -} - -const splitTlfIntoReadersAndWriters = ( - tlf: string -): { - readers?: Array - writers: Array -} => { - const [w, r] = tlf.split('#') - return { - readers: r ? r.split(',').filter(i => !!i) : undefined, - writers: w?.split(',').filter(i => !!i) ?? [], - } -} - -// returns parsedPathRoot if unknown -export const parsePath = (path: T.FS.Path): T.FS.ParsedPath => { - const elems = T.FS.getPathElements(path) - if (elems.length <= 1) { - return parsedPathRoot - } - switch (elems[1]) { - case 'private': - switch (elems.length) { - case 2: - return parsedPathPrivateList - case 3: - return { - kind: T.FS.PathKind.GroupTlf, - tlfName: elems[2]!, - tlfType: T.FS.TlfType.Private, - ...splitTlfIntoReadersAndWriters(elems[2]!), - } - default: - return { - kind: T.FS.PathKind.InGroupTlf, - rest: elems.slice(3), - tlfName: elems[2] ?? '', - tlfType: T.FS.TlfType.Private, - ...splitTlfIntoReadersAndWriters(elems[2] ?? ''), - } - } - case 'public': - switch (elems.length) { - case 2: - return parsedPathPublicList - case 3: - return { - kind: T.FS.PathKind.GroupTlf, - tlfName: elems[2]!, - tlfType: T.FS.TlfType.Public, - ...splitTlfIntoReadersAndWriters(elems[2]!), - } - default: - return { - kind: T.FS.PathKind.InGroupTlf, - rest: elems.slice(3), - tlfName: elems[2] ?? '', - tlfType: T.FS.TlfType.Public, - ...splitTlfIntoReadersAndWriters(elems[2] ?? ''), - } - } - case 'team': - switch (elems.length) { - case 2: - return parsedPathTeamList - case 3: - return { - kind: T.FS.PathKind.TeamTlf, - team: elems[2]!, - tlfName: elems[2]!, - tlfType: T.FS.TlfType.Team, - } - default: - return { - kind: T.FS.PathKind.InTeamTlf, - rest: elems.slice(3), - team: elems[2] ?? '', - tlfName: elems[2] ?? '', - tlfType: T.FS.TlfType.Team, - } - } - default: - return parsedPathRoot - } -} - -export const rebasePathToDifferentTlf = (path: T.FS.Path, newTlfPath: T.FS.Path) => - T.FS.pathConcat(newTlfPath, T.FS.getPathElements(path).slice(3).join('/')) - -export const canChat = (path: T.FS.Path) => { - const parsedPath = parsePath(path) - switch (parsedPath.kind) { - case T.FS.PathKind.Root: - case T.FS.PathKind.TlfList: - return false - case T.FS.PathKind.GroupTlf: - case T.FS.PathKind.TeamTlf: - return true - case T.FS.PathKind.InGroupTlf: - case T.FS.PathKind.InTeamTlf: - return true - default: - return false - } -} - -export const isTeamPath = (path: T.FS.Path): boolean => { - const parsedPath = parsePath(path) - return parsedPath.kind !== T.FS.PathKind.Root && parsedPath.tlfType === T.FS.TlfType.Team -} - -export const getChatTarget = (path: T.FS.Path, me: string): string => { - const parsedPath = parsePath(path) - if (parsedPath.kind !== T.FS.PathKind.Root && parsedPath.tlfType === T.FS.TlfType.Team) { - return 'team conversation' - } - if (parsedPath.kind === T.FS.PathKind.GroupTlf || parsedPath.kind === T.FS.PathKind.InGroupTlf) { - if (parsedPath.writers.length === 1 && !parsedPath.readers && parsedPath.writers[0] === me) { - return 'yourself' - } - if (parsedPath.writers.length + (parsedPath.readers ? parsedPath.readers.length : 0) === 2) { - const notMe = parsedPath.writers.concat(parsedPath.readers || []).filter(u => u !== me) - if (notMe.length === 1) { - return notMe[0]! - } - } - return 'group conversation' - } - return 'conversation' -} - -export const getSharePathArrayDescription = (paths: ReadonlyArray): string => { - return !paths.length ? '' : paths.length === 1 ? T.FS.getPathName(paths[0]) : `${paths.length} items` -} - -export const getDestinationPickerPathName = (picker: T.FS.DestinationPicker): string => - picker.source.type === T.FS.DestinationPickerSource.MoveOrCopy - ? T.FS.getPathName(picker.source.path) - : picker.source.type === T.FS.DestinationPickerSource.IncomingShare - ? getSharePathArrayDescription( - picker.source.source - .map(({originalPath}) => (originalPath ? T.FS.getLocalPathName(originalPath) : '')) - .filter(Boolean) - ) - : '' - -const isPathEnabledForSync = (syncConfig: T.FS.TlfSyncConfig, path: T.FS.Path): boolean => { - switch (syncConfig.mode) { - case T.FS.TlfSyncMode.Disabled: - return false - case T.FS.TlfSyncMode.Enabled: - return true - case T.FS.TlfSyncMode.Partial: - // TODO: when we enable partial sync lookup, remember to deal with - // potential ".." traversal as well. - return syncConfig.enabledPaths.includes(path) - default: - return false - } -} - -export const getUploadIconForTlfType = ( - kbfsDaemonStatus: T.FS.KbfsDaemonStatus, - uploads: T.FS.Uploads, - tlfList: T.FS.TlfList, - tlfType: T.FS.TlfType -): T.FS.UploadIcon | undefined => { - if ( - [...tlfList].some( - ([_, tlf]) => - tlf.conflictState.type === T.FS.ConflictStateType.NormalView && tlf.conflictState.stuckInConflict - ) - ) { - return T.FS.UploadIcon.UploadingStuck - } - - const prefix = T.FS.pathToString(T.FS.getTlfTypePathFromTlfType(tlfType)) - if ( - [...uploads.syncingPaths].some(p => T.FS.pathToString(p).startsWith(prefix)) || - [...uploads.writingToJournal.keys()].some(p => T.FS.pathToString(p).startsWith(prefix)) - ) { - return kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline - ? T.FS.UploadIcon.AwaitingToUpload - : T.FS.UploadIcon.Uploading - } - - return undefined -} - -export const tlfIsStuckInConflict = (tlf: T.FS.Tlf) => - tlf.conflictState.type === T.FS.ConflictStateType.NormalView && tlf.conflictState.stuckInConflict - -export const getPathStatusIconInMergeProps = ( - kbfsDaemonStatus: T.FS.KbfsDaemonStatus, - tlf: T.Immutable, - pathItem: T.Immutable, - uploadingPaths: T.Immutable>, - path: T.Immutable -): T.FS.PathStatusIcon => { - // There's no upload or sync for local conflict view. - if (tlf.conflictState.type === T.FS.ConflictStateType.ManualResolvingLocalView) { - return T.FS.LocalConflictStatus - } - - // uploading state has higher priority - if (uploadingPaths.has(path)) { - // eslint-disable-next-line - return tlf.conflictState.type === T.FS.ConflictStateType.NormalView && tlf.conflictState.stuckInConflict - ? T.FS.UploadIcon.UploadingStuck - : kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline - ? T.FS.UploadIcon.AwaitingToUpload - : T.FS.UploadIcon.Uploading - } - if (!isPathEnabledForSync(tlf.syncConfig, path)) { - return T.FS.NonUploadStaticSyncStatus.OnlineOnly - } - - if (pathItem === unknownPathItem && tlf.syncConfig.mode !== T.FS.TlfSyncMode.Disabled) { - return T.FS.NonUploadStaticSyncStatus.Unknown - } - - // TODO: what about 'sync-error'? - - // We don't have an upload state, and sync is enabled for this path. - switch (pathItem.prefetchStatus.state) { - case T.FS.PrefetchState.NotStarted: - return T.FS.NonUploadStaticSyncStatus.AwaitingToSync - case T.FS.PrefetchState.Complete: - return T.FS.NonUploadStaticSyncStatus.Synced - case T.FS.PrefetchState.InProgress: { - if (kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline) { - return T.FS.NonUploadStaticSyncStatus.AwaitingToSync - } - const inProgress: T.FS.PrefetchInProgress = pathItem.prefetchStatus - if (inProgress.bytesTotal === 0) { - return T.FS.NonUploadStaticSyncStatus.AwaitingToSync - } - return inProgress.bytesFetched / inProgress.bytesTotal - } - default: - return T.FS.NonUploadStaticSyncStatus.Unknown - } -} - export const makeActionsForDestinationPickerOpen = (index: number, path: T.FS.Path) => { useFSState.getState().dispatch.setDestinationPickerParentPath(index, path) navigateAppend({props: {index}, selected: 'destinationPicker'}) } -export const fsRootRouteForNav1 = isMobile ? [Tabs.settingsTab, settingsFsTab] : [Tabs.fsTab] - -export const getMainBannerType = ( - kbfsDaemonStatus: T.FS.KbfsDaemonStatus, - overallSyncStatus: T.FS.OverallSyncStatus -): T.FS.MainBannerType => { - if (kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline) { - return T.FS.MainBannerType.Offline - } else if (kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Trying) { - return T.FS.MainBannerType.TryingToConnect - } else if (overallSyncStatus.diskSpaceStatus === T.FS.DiskSpaceStatus.Error) { - return T.FS.MainBannerType.OutOfSpace - } else { - return T.FS.MainBannerType.None - } -} - -export const isFolder = (path: T.FS.Path, pathItem: T.FS.PathItem) => - T.FS.getPathLevel(path) <= 3 || pathItem.type === T.FS.PathType.Folder - -export const isInTlf = (path: T.FS.Path) => T.FS.getPathLevel(path) > 2 - -export const humanizeBytes = (n: number, numDecimals: number): string => { - const kb = 1024 - const mb = kb * 1024 - const gb = mb * 1024 - - if (n < kb) { - return `${n} bytes` - } else if (n < mb) { - return `${(n / kb).toFixed(numDecimals)} KB` - } else if (n < gb) { - return `${(n / mb).toFixed(numDecimals)} MB` - } - return `${(n / gb).toFixed(numDecimals)} GB` -} - -export const humanizeBytesOfTotal = (n: number, d: number): string => { - const kb = 1024 - const mb = kb * 1024 - const gb = mb * 1024 - - if (d < kb) { - return `${n} of ${d} bytes` - } else if (d < mb) { - return `${(n / kb).toFixed(2)} of ${(d / kb).toFixed(2)} KB` - } else if (d < gb) { - return `${(n / mb).toFixed(2)} of ${(d / mb).toFixed(2)} MB` - } - return `${(n / gb).toFixed(2)} of ${(d / gb).toFixed(2)} GB` -} - -export const hasPublicTag = (path: T.FS.Path): boolean => { - const publicPrefix = '/keybase/public/' - // The slash after public in `publicPrefix` prevents /keybase/public from counting. - return T.FS.pathToString(path).startsWith(publicPrefix) -} - -export const getPathUserSetting = ( - pathUserSettings: T.Immutable>, - path: T.Immutable -): T.FS.PathUserSetting => - pathUserSettings.get(path) || - (T.FS.getPathLevel(path) < 3 ? defaultTlfListPathUserSetting : defaultPathUserSetting) - -export const showSortSetting = ( - path: T.FS.Path, - pathItem: T.FS.PathItem, - kbfsDaemonStatus: T.FS.KbfsDaemonStatus -) => - !isMobile && - path !== defaultPath && - (T.FS.getPathLevel(path) === 2 || (pathItem.type === T.FS.PathType.Folder && !!pathItem.children.size)) && - !isOfflineUnsynced(kbfsDaemonStatus, pathItem, path) - -export const getSoftError = (softErrors: T.FS.SoftErrors, path: T.FS.Path): T.FS.SoftError | undefined => { - const pathError = softErrors.pathErrors.get(path) - if (pathError) { - return pathError - } - if (!softErrors.tlfErrors.size) { - return undefined - } - const tlfPath = getTlfPath(path) - return (tlfPath && softErrors.tlfErrors.get(tlfPath)) || undefined -} - -export const hasSpecialFileElement = (path: T.FS.Path): boolean => - T.FS.getPathElements(path).some(elem => elem.startsWith('.kbfs')) - -export const sfmiInfoLoaded = (settings: T.FS.Settings, driverStatus: T.FS.DriverStatus): boolean => - settings.loaded && driverStatus !== driverStatusUnknown - -// This isn't perfect since it doesn't cover the case of multi-writer public -// TLFs or where a team TLF is readonly to the user. But to do that we'd need -// some new caching in KBFS to plumb it into the Tlfs structure without -// awful overhead. -export const hideOrDisableInDestinationPicker = ( - tlfType: T.FS.TlfType, - name: string, - username: string, - destinationPickerIndex?: number -) => typeof destinationPickerIndex === 'number' && tlfType === T.FS.TlfType.Public && name !== username - const noAccessErrorCodes: Array = [ T.RPCGen.StatusCode.scsimplefsnoaccess, T.RPCGen.StatusCode.scteamnotfound, @@ -1023,7 +90,7 @@ export const errorToActionOrThrow = (error: unknown, path?: T.FS.Path) => { return } if (path && code && noAccessErrorCodes.includes(code)) { - const tlfPath = getTlfPath(path) + const tlfPath = Util.getTlfPath(path) if (tlfPath) { useFSState.getState().dispatch.setTlfSoftError(tlfPath, T.FS.SoftError.NoAccess) return @@ -1078,17 +145,17 @@ const initialStore: Store = { errors: [], fileContext: new Map(), folderViewFilter: undefined, - kbfsDaemonStatus: unknownKbfsDaemonStatus, + kbfsDaemonStatus: Util.unknownKbfsDaemonStatus, lastPublicBannerClosedTlf: '', - overallSyncStatus: emptyOverallSyncStatus, + overallSyncStatus: Util.emptyOverallSyncStatus, pathInfos: new Map(), - pathItemActionMenu: emptyPathItemActionMenu, + pathItemActionMenu: Util.emptyPathItemActionMenu, pathItems: new Map(), pathUserSettings: new Map(), - settings: emptySettings, + settings: Util.emptySettings, sfmi: { directMountDir: '', - driverStatus: defaultDriverStatus, + driverStatus: Util.defaultDriverStatus, preferredMountDirs: [], }, softErrors: { @@ -1226,19 +293,19 @@ const getPrefetchStatusFromRPC = ( ) => { switch (prefetchStatus) { case T.RPCGen.PrefetchStatus.notStarted: - return prefetchNotStarted + return Util.prefetchNotStarted case T.RPCGen.PrefetchStatus.inProgress: return { - ...emptyPrefetchInProgress, + ...Util.emptyPrefetchInProgress, bytesFetched: prefetchProgress.bytesFetched, bytesTotal: prefetchProgress.bytesTotal, endEstimate: prefetchProgress.endEstimate, startTime: prefetchProgress.start, } case T.RPCGen.PrefetchStatus.complete: - return prefetchComplete + return Util.prefetchComplete default: - return prefetchNotStarted + return Util.prefetchNotStarted } } @@ -1255,21 +322,21 @@ const makeEntry = (d: T.RPCGen.Dirent, children?: Set): T.FS.PathItem => switch (d.direntType) { case T.RPCGen.DirentType.dir: return { - ...emptyFolder, + ...Util.emptyFolder, ...direntToMetadata(d), children: new Set(children || []), progress: children ? T.FS.ProgressType.Loaded : T.FS.ProgressType.Pending, } as T.FS.PathItem case T.RPCGen.DirentType.sym: return { - ...emptySymlink, + ...Util.emptySymlink, ...direntToMetadata(d), // TODO: plumb link target } as T.FS.PathItem case T.RPCGen.DirentType.file: case T.RPCGen.DirentType.exec: return { - ...emptyFile, + ...Util.emptyFile, ...direntToMetadata(d), } as T.FS.PathItem } @@ -1381,7 +448,7 @@ export const useFSState = Z.createZustand((set, get) => { try { await T.RPCGen.SimpleFSSimpleFSOpenRpcPromise( { - dest: pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.name)), + dest: Util.pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.name)), flags: T.RPCGen.OpenFlags.directory, opID: makeUUID(), }, @@ -1397,10 +464,10 @@ export const useFSState = Z.createZustand((set, get) => { try { const opID = makeUUID() await T.RPCGen.SimpleFSSimpleFSMoveRpcPromise({ - dest: pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.name)), + dest: Util.pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.name)), opID, overwriteExistingFiles: false, - src: pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.originalName)), + src: Util.pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.originalName)), }) await T.RPCGen.SimpleFSSimpleFSWaitRpcPromise({opID}, S.waitingKeyFSCommitEdit) get().dispatch.editSuccess(editID) @@ -1430,7 +497,7 @@ export const useFSState = Z.createZustand((set, get) => { try { await T.RPCGen.SimpleFSSimpleFSRemoveRpcPromise({ opID, - path: pathToRPCPath(path), + path: Util.pathToRPCPath(path), recursive: true, }) await T.RPCGen.SimpleFSSimpleFSWaitRpcPromise({opID}) @@ -1469,7 +536,7 @@ export const useFSState = Z.createZustand((set, get) => { await requestPermissionsToWrite() const downloadID = await T.RPCGen.SimpleFSSimpleFSStartDownloadRpcPromise({ isRegularDownload: type === 'download', - path: pathToRPCPath(path).kbfs, + path: Util.pathToRPCPath(path).kbfs, }) if (type !== 'download') { get().dispatch.setPathItemActionMenuDownload( @@ -1538,7 +605,7 @@ export const useFSState = Z.createZustand((set, get) => { }, favoriteIgnore: path => { const f = async () => { - const folder = folderRPCFromPath(path) + const folder = Util.folderRPCFromPath(path) if (!folder) { throw new Error('No folder specified') } @@ -1556,7 +623,7 @@ export const useFSState = Z.createZustand((set, get) => { s.tlfs[visibility].set( elems[2] ?? '', T.castDraft({ - ...(s.tlfs[visibility].get(elems[2] ?? '') || unknownTlf), + ...(s.tlfs[visibility].get(elems[2] ?? '') || Util.unknownTlf), isIgnored: false, }) ) @@ -1573,7 +640,7 @@ export const useFSState = Z.createZustand((set, get) => { s.tlfs[visibility].set( elems[2] ?? '', T.castDraft({ - ...(s.tlfs[visibility].get(elems[2] ?? '') || unknownTlf), + ...(s.tlfs[visibility].get(elems[2] ?? '') || Util.unknownTlf), isIgnored: true, }) ) @@ -1605,7 +672,7 @@ export const useFSState = Z.createZustand((set, get) => { ] fs.forEach(({folders, isFavorite, isIgnored, isNew}) => folders.forEach(folder => { - const tlfType = rpcFolderTypeToTlfType(folder.folderType) + const tlfType = Util.rpcFolderTypeToTlfType(folder.folderType) const tlfName = tlfType === T.FS.TlfType.Private || tlfType === T.FS.TlfType.Public ? tlfToPreferredOrder(folder.name, useCurrentUserState.getState().username) @@ -1613,14 +680,14 @@ export const useFSState = Z.createZustand((set, get) => { tlfType && payload[tlfType].set( tlfName, - makeTlf({ - conflictState: rpcConflictStateToConflictState(folder.conflictState || undefined), + Util.makeTlf({ + conflictState: Util.rpcConflictStateToConflictState(folder.conflictState || undefined), isFavorite, isIgnored, isNew, name: tlfName, resetParticipants: (folder.reset_members || []).map(({username}) => username), - syncConfig: getSyncConfigFromRPC(tlfName, tlfType, folder.syncConfig || undefined), + syncConfig: Util.getSyncConfigFromRPC(tlfName, tlfType, folder.syncConfig || undefined), teamId: folder.team_id || '', tlfMtime: folder.mtime || 0, }) @@ -1636,7 +703,7 @@ export const useFSState = Z.createZustand((set, get) => { s.tlfs.loaded = true }) const counts = new Map() - counts.set(Tabs.fsTab, computeBadgeNumberForAll(get().tlfs)) + counts.set(Tabs.fsTab, Util.computeBadgeNumberForAll(get().tlfs)) storeRegistry.getState('notifications').dispatch.setBadgeCounts(counts) } } catch (e) { @@ -1649,7 +716,7 @@ export const useFSState = Z.createZustand((set, get) => { finishManualConflictResolution: localViewTlfPath => { const f = async () => { await T.RPCGen.SimpleFSSimpleFSFinishResolvingConflictRpcPromise({ - path: pathToRPCPath(localViewTlfPath), + path: Util.pathToRPCPath(localViewTlfPath), }) get().dispatch.favoritesLoad() } @@ -1664,14 +731,14 @@ export const useFSState = Z.createZustand((set, get) => { depth: 1, filter: T.RPCGen.ListFilter.filterSystemHidden, opID, - path: pathToRPCPath(rootPath), + path: Util.pathToRPCPath(rootPath), refreshSubscription: false, }) } else { await T.RPCGen.SimpleFSSimpleFSListRpcPromise({ filter: T.RPCGen.ListFilter.filterSystemHidden, opID, - path: pathToRPCPath(rootPath), + path: Util.pathToRPCPath(rootPath), refreshSubscription: false, }) } @@ -1721,11 +788,11 @@ export const useFSState = Z.createZustand((set, get) => { // Get metadata fields of the directory that we just loaded from state to // avoid overriding them. - const rootPathItem = getPathItem(get().pathItems, rootPath) + const rootPathItem = Util.getPathItem(get().pathItems, rootPath) const rootFolder: T.FS.FolderPathItem = { ...(rootPathItem.type === T.FS.PathType.Folder ? rootPathItem - : {...emptyFolder, name: T.FS.getPathName(rootPath)}), + : {...Util.emptyFolder, name: T.FS.getPathName(rootPath)}), children: new Set(childMap.get(rootPath)), progress: T.FS.ProgressType.Loaded, } @@ -1736,7 +803,7 @@ export const useFSState = Z.createZustand((set, get) => { ] as const) set(s => { pathItems.forEach((pathItemFromAction, path) => { - const oldPathItem = getPathItem(s.pathItems, path) + const oldPathItem = Util.getPathItem(s.pathItems, path) const newPathItem = updatePathItem(oldPathItem, pathItemFromAction) oldPathItem.type === T.FS.PathType.Folder && oldPathItem.children.forEach( @@ -1753,7 +820,7 @@ export const useFSState = Z.createZustand((set, get) => { if (edit.type !== T.FS.EditType.Rename) { return true } - const parent = getPathItem(s.pathItems, edit.parentPath) + const parent = Util.getPathItem(s.pathItems, edit.parentPath) if (parent.type === T.FS.PathType.Folder && parent.children.has(edit.name)) { return true } @@ -1900,9 +967,9 @@ export const useFSState = Z.createZustand((set, get) => { } try { const {folder, isFavorite, isIgnored, isNew} = await T.RPCGen.SimpleFSSimpleFSGetFolderRpcPromise({ - path: pathToRPCPath(tlfPath).kbfs, + path: Util.pathToRPCPath(tlfPath).kbfs, }) - const tlfType = rpcFolderTypeToTlfType(folder.folderType) + const tlfType = Util.rpcFolderTypeToTlfType(folder.folderType) const tlfName = tlfType === T.FS.TlfType.Private || tlfType === T.FS.TlfType.Public ? tlfToPreferredOrder(folder.name, useCurrentUserState.getState().username) @@ -1913,14 +980,14 @@ export const useFSState = Z.createZustand((set, get) => { s.tlfs.additionalTlfs.set( tlfPath, T.castDraft( - makeTlf({ - conflictState: rpcConflictStateToConflictState(folder.conflictState || undefined), + Util.makeTlf({ + conflictState: Util.rpcConflictStateToConflictState(folder.conflictState || undefined), isFavorite, isIgnored, isNew, name: tlfName, resetParticipants: (folder.reset_members || []).map(({username}) => username), - syncConfig: getSyncConfigFromRPC(tlfName, tlfType, folder.syncConfig || undefined), + syncConfig: Util.getSyncConfigFromRPC(tlfName, tlfType, folder.syncConfig || undefined), teamId: folder.team_id || '', tlfMtime: folder.mtime || 0, }) @@ -2007,7 +1074,7 @@ export const useFSState = Z.createZustand((set, get) => { const f = async () => { try { const res = await T.RPCGen.SimpleFSSimpleFSGetGUIFileContextRpcPromise({ - path: pathToRPCPath(path).kbfs, + path: Util.pathToRPCPath(path).kbfs, }) set(s => { @@ -2060,7 +1127,7 @@ export const useFSState = Z.createZustand((set, get) => { try { const dirent = await T.RPCGen.SimpleFSSimpleFSStatRpcPromise( { - path: pathToRPCPath(path), + path: Util.pathToRPCPath(path), refreshSubscription: false, }, S.waitingKeyFSStat @@ -2068,7 +1135,7 @@ export const useFSState = Z.createZustand((set, get) => { const pathItem = makeEntry(dirent) set(s => { - const oldPathItem = getPathItem(s.pathItems, path) + const oldPathItem = Util.getPathItem(s.pathItems, path) s.pathItems.set(path, T.castDraft(updatePathItem(oldPathItem, pathItem))) s.softErrors.pathErrors.delete(path) s.softErrors.tlfErrors.delete(path) @@ -2105,31 +1172,31 @@ export const useFSState = Z.createZustand((set, get) => { }, loadTlfSyncConfig: tlfPath => { const f = async () => { - const parsedPath = parsePath(tlfPath) + const parsedPath = Util.parsePath(tlfPath) if (parsedPath.kind !== T.FS.PathKind.GroupTlf && parsedPath.kind !== T.FS.PathKind.TeamTlf) { return } try { const result = await T.RPCGen.SimpleFSSimpleFSFolderSyncConfigAndStatusRpcPromise({ - path: pathToRPCPath(tlfPath), + path: Util.pathToRPCPath(tlfPath), }) - const syncConfig = getSyncConfigFromRPC(parsedPath.tlfName, parsedPath.tlfType, result.config) + const syncConfig = Util.getSyncConfigFromRPC(parsedPath.tlfName, parsedPath.tlfType, result.config) const tlfName = parsedPath.tlfName const tlfType = parsedPath.tlfType set(s => { const oldTlfList = s.tlfs[tlfType] - const oldTlfFromFavorites = oldTlfList.get(tlfName) || unknownTlf - if (oldTlfFromFavorites !== unknownTlf) { + const oldTlfFromFavorites = oldTlfList.get(tlfName) || Util.unknownTlf + if (oldTlfFromFavorites !== Util.unknownTlf) { s.tlfs[tlfType] = T.castDraft( new Map([...oldTlfList, [tlfName, {...oldTlfFromFavorites, syncConfig}]]) ) return } - const tlfPath = T.FS.pathConcat(T.FS.pathConcat(defaultPath, tlfType), tlfName) - const oldTlfFromAdditional = s.tlfs.additionalTlfs.get(tlfPath) || unknownTlf - if (oldTlfFromAdditional !== unknownTlf) { + const tlfPath = T.FS.pathConcat(T.FS.pathConcat(Util.defaultPath, tlfType), tlfName) + const oldTlfFromAdditional = s.tlfs.additionalTlfs.get(tlfPath) || Util.unknownTlf + if (oldTlfFromAdditional !== Util.unknownTlf) { s.tlfs.additionalTlfs = T.castDraft( new Map([...s.tlfs.additionalTlfs, [tlfPath, {...oldTlfFromAdditional, syncConfig}]]) ) @@ -2152,7 +1219,7 @@ export const useFSState = Z.createZustand((set, get) => { const writingToJournal = new Map( uploadStates?.map(uploadState => { - const path = rpcPathToPath(uploadState.targetPath) + const path = Util.rpcPathToPath(uploadState.targetPath) const oldUploadState = s.uploads.writingToJournal.get(path) return [ path, @@ -2191,7 +1258,7 @@ export const useFSState = Z.createZustand((set, get) => { zState.destinationPicker.source.type === T.FS.DestinationPickerSource.MoveOrCopy ? [ { - dest: pathToRPCPath( + dest: Util.pathToRPCPath( T.FS.pathConcat( destinationParentPath, T.FS.getPathName(zState.destinationPicker.source.path) @@ -2199,14 +1266,14 @@ export const useFSState = Z.createZustand((set, get) => { ), opID: makeUUID(), overwriteExistingFiles: false, - src: pathToRPCPath(zState.destinationPicker.source.path), + src: Util.pathToRPCPath(zState.destinationPicker.source.path), }, ] : zState.destinationPicker.source.source .map(item => ({originalPath: item.originalPath ?? '', scaledPath: item.scaledPath})) .filter(({originalPath}) => !!originalPath) .map(({originalPath, scaledPath}) => ({ - dest: pathToRPCPath( + dest: Util.pathToRPCPath( T.FS.pathConcat( destinationParentPath, T.FS.getLocalPathName(originalPath) @@ -2243,7 +1310,7 @@ export const useFSState = Z.createZustand((set, get) => { ignorePromise(f()) }, newFolderRow: parentPath => { - const parentPathItem = getPathItem(get().pathItems, parentPath) + const parentPathItem = Util.getPathItem(get().pathItems, parentPath) if (parentPathItem.type !== T.FS.PathType.Folder) { console.warn(`bad parentPath: ${parentPathItem.type}`) return @@ -2260,7 +1327,7 @@ export const useFSState = Z.createZustand((set, get) => { set(s => { s.edits.set(makeEditID(), { - ...emptyNewFolder, + ...Util.emptyNewFolder, name: newFolderName, originalName: newFolderName, parentPath, @@ -2490,7 +1557,7 @@ export const useFSState = Z.createZustand((set, get) => { if (old) { old.sort = sortSetting } else { - s.pathUserSettings.set(path, {...defaultPathUserSetting, sort: sortSetting}) + s.pathUserSettings.set(path, {...Util.defaultPathUserSetting, sort: sortSetting}) } }) }, @@ -2517,7 +1584,7 @@ export const useFSState = Z.createZustand((set, get) => { await T.RPCGen.SimpleFSSimpleFSSetFolderSyncConfigRpcPromise( { config: {mode: enabled ? T.RPCGen.FolderSyncMode.enabled : T.RPCGen.FolderSyncMode.disabled}, - path: pathToRPCPath(tlfPath), + path: Util.pathToRPCPath(tlfPath), }, S.waitingKeyFSSyncToggle ) @@ -2541,9 +1608,7 @@ export const useFSState = Z.createZustand((set, get) => { } s.destinationPicker.destinationParentPath = [initialDestinationParentPath] }) - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {index: 0}, selected: 'destinationPicker'}) + navigateAppend({props: {index: 0}, selected: 'destinationPicker'}) }, showMoveOrCopy: initialDestinationParentPath => { set(s => { @@ -2551,21 +1616,19 @@ export const useFSState = Z.createZustand((set, get) => { s.destinationPicker.source.type === T.FS.DestinationPickerSource.MoveOrCopy ? s.destinationPicker.source : { - path: defaultPath, + path: Util.defaultPath, type: T.FS.DestinationPickerSource.MoveOrCopy, } s.destinationPicker.destinationParentPath = [initialDestinationParentPath] }) - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {index: 0}, selected: 'destinationPicker'}) + navigateAppend({props: {index: 0}, selected: 'destinationPicker'}) }, startManualConflictResolution: tlfPath => { const f = async () => { await T.RPCGen.SimpleFSSimpleFSClearConflictStateRpcPromise({ - path: pathToRPCPath(tlfPath), + path: Util.pathToRPCPath(tlfPath), }) get().dispatch.favoritesLoad() } @@ -2648,7 +1711,7 @@ export const useFSState = Z.createZustand((set, get) => { } case T.FS.DiskSpaceStatus.Warning: { - const threshold = humanizeBytes(get().settings.spaceAvailableNotificationThreshold, 0) + const threshold = Util.humanizeBytes(get().settings.spaceAvailableNotificationThreshold, 0) NotifyPopup('Disk Space Low', { body: `You have less than ${threshold} of storage space left.`, }) @@ -2684,7 +1747,7 @@ export const useFSState = Z.createZustand((set, get) => { try { await T.RPCGen.SimpleFSSimpleFSStartUploadRpcPromise({ sourceLocalPath: T.FS.getNormalizedLocalPath(localPath), - targetParentPath: pathToRPCPath(parentPath).kbfs, + targetParentPath: Util.pathToRPCPath(parentPath).kbfs, }) } catch (err) { errorToActionOrThrow(err) @@ -2697,7 +1760,7 @@ export const useFSState = Z.createZustand((set, get) => { try { const writerEdits = await T.RPCGen.SimpleFSSimpleFSUserEditHistoryRpcPromise() set(s => { - s.tlfUpdates = T.castDraft(userTlfHistoryRPCToState(writerEdits || [])) + s.tlfUpdates = T.castDraft(Util.userTlfHistoryRPCToState(writerEdits || [])) }) } catch (error) { errorToActionOrThrow(error) diff --git a/shared/constants/fs/util.tsx b/shared/constants/fs/util.tsx index 0ecea95b7a97..e680702022f8 100644 --- a/shared/constants/fs/util.tsx +++ b/shared/constants/fs/util.tsx @@ -1,5 +1,9 @@ import * as EngineGen from '@/actions/engine-gen-gen' -import type * as T from '../types' +import type * as React from 'react' +import * as Tabs from '../tabs' +import * as T from '../types' +import {isLinux, isMobile} from '../platform' +import {settingsFsTab} from '../settings/util' import {navigateAppend} from '../router2/util' import {storeRegistry} from '../store-registry' @@ -22,3 +26,944 @@ export const makeActionForOpenPathInFilesTab = ( ) => { navigateAppend({props: {path}, selected: 'fsRoot'}) } + +// Exit Codes +export const ExitCodeFuseKextError = 4 +export const ExitCodeFuseKextPermissionError = 5 +export const ExitCodeAuthCanceledError = 6 + +// Path Constants +export const defaultPath = T.FS.stringToPath('/keybase') + +// Prefetch Constants +export const prefetchNotStarted: T.FS.PrefetchNotStarted = { + state: T.FS.PrefetchState.NotStarted, +} + +export const prefetchComplete: T.FS.PrefetchComplete = { + state: T.FS.PrefetchState.Complete, +} + +export const emptyPrefetchInProgress: T.FS.PrefetchInProgress = { + bytesFetched: 0, + bytesTotal: 0, + endEstimate: 0, + startTime: 0, + state: T.FS.PrefetchState.InProgress, +} + +// PathItem Constants +const pathItemMetadataDefault = { + lastModifiedTimestamp: 0, + lastWriter: '', + name: 'unknown', + prefetchStatus: prefetchNotStarted, + size: 0, + writable: false, +} + +export const emptyFolder: T.FS.FolderPathItem = { + ...pathItemMetadataDefault, + children: new Set(), + progress: T.FS.ProgressType.Pending, + type: T.FS.PathType.Folder, +} + +export const emptyFile: T.FS.FilePathItem = { + ...pathItemMetadataDefault, + type: T.FS.PathType.File, +} + +export const emptySymlink: T.FS.SymlinkPathItem = { + ...pathItemMetadataDefault, + linkTarget: '', + type: T.FS.PathType.Symlink, +} + +export const unknownPathItem: T.FS.UnknownPathItem = { + ...pathItemMetadataDefault, + type: T.FS.PathType.Unknown, +} + +// Sync Config Constants +export const tlfSyncEnabled: T.FS.TlfSyncEnabled = { + mode: T.FS.TlfSyncMode.Enabled, +} + +export const tlfSyncDisabled: T.FS.TlfSyncDisabled = { + mode: T.FS.TlfSyncMode.Disabled, +} + +export const makeTlfSyncPartial = ({ + enabledPaths, +}: { + enabledPaths?: T.FS.TlfSyncPartial['enabledPaths'] +}): T.FS.TlfSyncPartial => ({ + enabledPaths: [...(enabledPaths || [])], + mode: T.FS.TlfSyncMode.Partial, +}) + +// Conflict State Constants +export const makeConflictStateNormalView = ({ + localViewTlfPaths, + resolvingConflict, + stuckInConflict, +}: Partial): T.FS.ConflictStateNormalView => ({ + localViewTlfPaths: [...(localViewTlfPaths || [])], + resolvingConflict: resolvingConflict || false, + stuckInConflict: stuckInConflict || false, + type: T.FS.ConflictStateType.NormalView, +}) + +export const tlfNormalViewWithNoConflict = makeConflictStateNormalView({}) + +export const makeConflictStateManualResolvingLocalView = ({ + normalViewTlfPath, +}: Partial): T.FS.ConflictStateManualResolvingLocalView => ({ + normalViewTlfPath: normalViewTlfPath || defaultPath, + type: T.FS.ConflictStateType.ManualResolvingLocalView, +}) + +// Factory Functions +export const makeTlf = (p: Partial): T.FS.Tlf => { + const {conflictState, isFavorite, isIgnored, isNew, name, resetParticipants, syncConfig, teamId, tlfMtime} = + p + return { + conflictState: conflictState || tlfNormalViewWithNoConflict, + isFavorite: isFavorite || false, + isIgnored: isIgnored || false, + isNew: isNew || false, + name: name || '', + resetParticipants: [...(resetParticipants || [])], + syncConfig: syncConfig || tlfSyncDisabled, + teamId: teamId || '', + tlfMtime: tlfMtime || 0, + /* See comment in constants/types/fs.js + needsRekey: false, + waitingForParticipantUnlock: I.List(), + youCanUnlock: I.List(), + */ + } +} + +export const unknownTlf = makeTlf({}) + +// Empty/Default Objects +export const emptyNewFolder: T.FS.Edit = { + error: undefined, + name: 'New Folder', + originalName: 'New Folder', + parentPath: T.FS.stringToPath('/keybase'), + type: T.FS.EditType.NewFolder, +} + +export const emptySyncingFoldersProgress: T.FS.SyncingFoldersProgress = { + bytesFetched: 0, + bytesTotal: 0, + endEstimate: 0, + start: 0, +} + +export const emptyOverallSyncStatus: T.FS.OverallSyncStatus = { + diskSpaceStatus: T.FS.DiskSpaceStatus.Ok, + showingBanner: false, + syncingFoldersProgress: emptySyncingFoldersProgress, +} + +export const defaultPathUserSetting: T.FS.PathUserSetting = { + sort: T.FS.SortSetting.NameAsc, +} + +export const defaultTlfListPathUserSetting: T.FS.PathUserSetting = { + sort: T.FS.SortSetting.TimeAsc, +} + +export const emptyDownloadState: T.FS.DownloadState = { + canceled: false, + done: false, + endEstimate: 0, + error: '', + localPath: '', + progress: 0, +} + +export const emptyDownloadInfo: T.FS.DownloadInfo = { + filename: '', + isRegularDownload: false, + path: defaultPath, + startTime: 0, +} + +export const emptyPathItemActionMenu: T.FS.PathItemActionMenu = { + downloadID: undefined, + downloadIntent: undefined, + previousView: T.FS.PathItemActionMenuView.Root, + view: T.FS.PathItemActionMenuView.Root, +} + +export const emptySettings: T.FS.Settings = { + isLoading: false, + loaded: false, + sfmiBannerDismissed: false, + spaceAvailableNotificationThreshold: 0, + syncOnCellular: false, +} + +export const emptyPathInfo: T.FS.PathInfo = { + deeplinkPath: '', + platformAfterMountPath: '', +} + +export const emptyFileContext: T.FS.FileContext = { + contentType: '', + url: '', + viewType: T.RPCGen.GUIViewType.default, +} + +export const emptyTlfUpdate: T.FS.TlfUpdate = { + history: [], + path: T.FS.stringToPath(''), + serverTime: 0, + writer: '', +} + +export const emptyTlfEdit: T.FS.TlfEdit = { + editType: T.FS.FileEditType.Unknown, + filename: '', + serverTime: 0, +} + +// Driver Status Constants +export const driverStatusUnknown: T.FS.DriverStatusUnknown = { + type: T.FS.DriverStatusType.Unknown, +} as const + +export const emptyDriverStatusEnabled: T.FS.DriverStatusEnabled = { + dokanOutdated: false, + dokanUninstallExecPath: undefined, + isDisabling: false, + type: T.FS.DriverStatusType.Enabled, +} as const + +export const emptyDriverStatusDisabled: T.FS.DriverStatusDisabled = { + isEnabling: false, + kextPermissionError: false, + type: T.FS.DriverStatusType.Disabled, +} as const + +export const defaultDriverStatus: T.FS.DriverStatus = isLinux ? emptyDriverStatusEnabled : driverStatusUnknown + +export const unknownKbfsDaemonStatus: T.FS.KbfsDaemonStatus = { + onlineStatus: T.FS.KbfsDaemonOnlineStatus.Unknown, + rpcStatus: T.FS.KbfsDaemonRpcStatus.Waiting, +} + +// Route Constants +export const fsRootRouteForNav1 = isMobile ? [Tabs.settingsTab, settingsFsTab] : [Tabs.fsTab] + +// Error Constants +export const invalidTokenError = new Error('invalid token') +export const notFoundError = new Error('not found') + +// Parsed Path Constants +export const parsedPathRoot: T.FS.ParsedPathRoot = {kind: T.FS.PathKind.Root} + +export const parsedPathPrivateList: T.FS.ParsedPathTlfList = { + kind: T.FS.PathKind.TlfList, + tlfType: T.FS.TlfType.Private, +} + +export const parsedPathPublicList: T.FS.ParsedPathTlfList = { + kind: T.FS.PathKind.TlfList, + tlfType: T.FS.TlfType.Public, +} + +export const parsedPathTeamList: T.FS.ParsedPathTlfList = { + kind: T.FS.PathKind.TlfList, + tlfType: T.FS.TlfType.Team, +} + +// Conversion Functions +export const rpcFolderTypeToTlfType = (rpcFolderType: T.RPCGen.FolderType) => { + switch (rpcFolderType) { + case T.RPCGen.FolderType.private: + return T.FS.TlfType.Private + case T.RPCGen.FolderType.public: + return T.FS.TlfType.Public + case T.RPCGen.FolderType.team: + return T.FS.TlfType.Team + default: + return null + } +} + +export const pathToRPCPath = ( + path: T.FS.Path +): {PathType: T.RPCGen.PathType.kbfs; kbfs: T.RPCGen.KBFSPath} => ({ + PathType: T.RPCGen.PathType.kbfs, + kbfs: { + identifyBehavior: T.RPCGen.TLFIdentifyBehavior.fsGui, + path: T.FS.pathToString(path).substring('/keybase'.length) || '/', + }, +}) + +export const rpcPathToPath = (rpcPath: T.RPCGen.KBFSPath) => T.FS.pathConcat(defaultPath, rpcPath.path) + +export const pathFromFolderRPC = (folder: T.RPCGen.Folder): T.FS.Path => { + const visibility = T.FS.getVisibilityFromRPCFolderType(folder.folderType) + if (!visibility) return T.FS.stringToPath('') + return T.FS.stringToPath(`/keybase/${visibility}/${folder.name}`) +} + +export const folderRPCFromPath = (path: T.FS.Path): T.RPCGen.FolderHandle | undefined => { + const pathElems = T.FS.getPathElements(path) + if (pathElems.length === 0) return undefined + + const visibility = T.FS.getVisibilityFromElems(pathElems) + if (visibility === undefined) return undefined + + const name = T.FS.getPathNameFromElems(pathElems) + if (name === '') return undefined + + return { + created: false, + folderType: T.FS.getRPCFolderTypeFromVisibility(visibility), + name, + } +} + +export const rpcConflictStateToConflictState = ( + rpcConflictState?: T.RPCGen.ConflictState +): T.FS.ConflictState => { + if (rpcConflictState) { + if (rpcConflictState.conflictStateType === T.RPCGen.ConflictStateType.normalview) { + const nv = rpcConflictState.normalview + return makeConflictStateNormalView({ + localViewTlfPaths: (nv.localViews || []).reduce>((arr, p) => { + p.PathType === T.RPCGen.PathType.kbfs && arr.push(rpcPathToPath(p.kbfs)) + return arr + }, []), + resolvingConflict: nv.resolvingConflict, + stuckInConflict: nv.stuckInConflict, + }) + } else { + const nv = rpcConflictState.manualresolvinglocalview.normalView + return makeConflictStateManualResolvingLocalView({ + normalViewTlfPath: nv.PathType === T.RPCGen.PathType.kbfs ? rpcPathToPath(nv.kbfs) : defaultPath, + }) + } + } else { + return tlfNormalViewWithNoConflict + } +} + +export const getSyncConfigFromRPC = ( + tlfName: string, + tlfType: T.FS.TlfType, + config?: T.RPCGen.FolderSyncConfig +): T.FS.TlfSyncConfig => { + if (!config) { + return tlfSyncDisabled + } + switch (config.mode) { + case T.RPCGen.FolderSyncMode.disabled: + return tlfSyncDisabled + case T.RPCGen.FolderSyncMode.enabled: + return tlfSyncEnabled + case T.RPCGen.FolderSyncMode.partial: + return makeTlfSyncPartial({ + enabledPaths: config.paths + ? config.paths.map(str => T.FS.getPathFromRelative(tlfName, tlfType, str)) + : [], + }) + default: + return tlfSyncDisabled + } +} + +// Path/PathItem Utilities +export const pathTypeToTextType = (type: T.FS.PathType) => + type === T.FS.PathType.Folder ? 'BodySemibold' : 'Body' + +export const getPathItem = ( + pathItems: T.Immutable>, + path: T.Immutable +): T.Immutable => pathItems.get(path) || (unknownPathItem as T.FS.PathItem) + +export const getTlfPath = (path: T.FS.Path): T.FS.Path => { + const elems = T.FS.getPathElements(path) + return elems.length > 2 ? T.FS.pathConcat(T.FS.pathConcat(defaultPath, elems[1]!), elems[2]!) : undefined +} + +export const getTlfListFromType = ( + tlfs: T.Immutable, + tlfType: T.Immutable +): T.Immutable => { + switch (tlfType) { + case T.FS.TlfType.Private: + return tlfs.private + case T.FS.TlfType.Public: + return tlfs.public + case T.FS.TlfType.Team: + return tlfs.team + default: + return new Map() + } +} + +export const getTlfListAndTypeFromPath = ( + tlfs: T.Immutable, + path: T.Immutable +): T.Immutable<{ + tlfList: T.FS.TlfList + tlfType: T.FS.TlfType +}> => { + const visibility = T.FS.getPathVisibility(path) + switch (visibility) { + case T.FS.TlfType.Private: + case T.FS.TlfType.Public: + case T.FS.TlfType.Team: { + const tlfType: T.FS.TlfType = visibility + return {tlfList: getTlfListFromType(tlfs, tlfType), tlfType} + } + default: + return {tlfList: new Map(), tlfType: T.FS.TlfType.Private} + } +} + +export const getTlfFromPathInFavoritesOnly = (tlfs: T.Immutable, path: T.FS.Path): T.FS.Tlf => { + const elems = T.FS.getPathElements(path) + if (elems.length < 3) { + return unknownTlf + } + const {tlfList} = getTlfListAndTypeFromPath(tlfs, path) + return tlfList.get(elems[2]!) || unknownTlf +} + +export const getTlfFromPath = (tlfs: T.Immutable, path: T.FS.Path): T.FS.Tlf => { + const fromFavorites = getTlfFromPathInFavoritesOnly(tlfs, path) + return fromFavorites !== unknownTlf + ? fromFavorites + : tlfs.additionalTlfs.get(getTlfPath(path)) || unknownTlf +} + +export const getTlfFromTlfs = (tlfs: T.FS.Tlfs, tlfType: T.FS.TlfType, name: string): T.FS.Tlf => { + switch (tlfType) { + case T.FS.TlfType.Private: + return tlfs.private.get(name) || unknownTlf + case T.FS.TlfType.Public: + return tlfs.public.get(name) || unknownTlf + case T.FS.TlfType.Team: + return tlfs.team.get(name) || unknownTlf + default: + return unknownTlf + } +} + +export const tlfTypeAndNameToPath = (tlfType: T.FS.TlfType, name: string): T.FS.Path => + T.FS.stringToPath(`/keybase/${tlfType}/${name}`) + +export const getUploadedPath = (parentPath: T.FS.Path, localPath: string) => + T.FS.pathConcat(parentPath, T.FS.getLocalPathName(localPath)) + +export const pathsInSameTlf = (a: T.FS.Path, b: T.FS.Path): boolean => { + const elemsA = T.FS.getPathElements(a) + const elemsB = T.FS.getPathElements(b) + return elemsA.length >= 3 && elemsB.length >= 3 && elemsA[1] === elemsB[1] && elemsA[2] === elemsB[2] +} + +const slashKeybaseSlashLength = '/keybase/'.length +export const escapePath = (path: T.FS.Path): string => + 'keybase://' + + encodeURIComponent(T.FS.pathToString(path).slice(slashKeybaseSlashLength)).replace( + // We need to do this because otherwise encodeURIComponent would encode + // "/"s. + /%2F/g, + '/' + ) + +export const rebasePathToDifferentTlf = (path: T.FS.Path, newTlfPath: T.FS.Path) => + T.FS.pathConcat(newTlfPath, T.FS.getPathElements(path).slice(3).join('/')) + +export const isFolder = (path: T.FS.Path, pathItem: T.FS.PathItem) => + T.FS.getPathLevel(path) <= 3 || pathItem.type === T.FS.PathType.Folder + +export const isInTlf = (path: T.FS.Path) => T.FS.getPathLevel(path) > 2 + +export const hasPublicTag = (path: T.FS.Path): boolean => { + const publicPrefix = '/keybase/public/' + // The slash after public in `publicPrefix` prevents /keybase/public from counting. + return T.FS.pathToString(path).startsWith(publicPrefix) +} + +export const hasSpecialFileElement = (path: T.FS.Path): boolean => + T.FS.getPathElements(path).some(elem => elem.startsWith('.kbfs')) + +// Username/User Utilities +export const splitTlfIntoUsernames = (tlf: string): ReadonlyArray => + tlf.split(' ')[0]?.replace(/#/g, ',').split(',') ?? [] + +export const getUsernamesFromPath = (path: T.FS.Path): ReadonlyArray => { + const elems = T.FS.getPathElements(path) + return elems.length < 3 ? [] : splitTlfIntoUsernames(elems[2]!) +} + +export const usernameInPath = (username: string, path: T.FS.Path) => { + const elems = T.FS.getPathElements(path) + return elems.length >= 3 && elems[2]!.split(',').includes(username) +} + +export const splitTlfIntoReadersAndWriters = ( + tlf: string +): { + readers?: Array + writers: Array +} => { + const [w, r] = tlf.split('#') + return { + readers: r ? r.split(',').filter(i => !!i) : undefined, + writers: w?.split(',').filter(i => !!i) ?? [], + } +} + +export const getUsernamesFromTlfName = (tlfName: string): Array => { + const split = splitTlfIntoReadersAndWriters(tlfName) + return split.writers.concat(split.readers || []) +} + +// TLF/List Utilities +export const computeBadgeNumberForTlfList = (tlfList: T.Immutable): number => + [...tlfList.values()].reduce((accumulator, tlf) => (tlfIsBadged(tlf) ? accumulator + 1 : accumulator), 0) + +export const computeBadgeNumberForAll = (tlfs: T.Immutable): number => + [T.FS.TlfType.Private, T.FS.TlfType.Public, T.FS.TlfType.Team] + .map(tlfType => computeBadgeNumberForTlfList(getTlfListFromType(tlfs, tlfType))) + .reduce((sum, count) => sum + count, 0) + +export const tlfIsBadged = (tlf: T.FS.Tlf) => !tlf.isIgnored && tlf.isNew + +export const tlfIsStuckInConflict = (tlf: T.FS.Tlf) => + tlf.conflictState.type === T.FS.ConflictStateType.NormalView && tlf.conflictState.stuckInConflict + +// Path Parsing +export const parsePath = (path: T.FS.Path): T.FS.ParsedPath => { + const elems = T.FS.getPathElements(path) + if (elems.length <= 1) { + return parsedPathRoot + } + switch (elems[1]) { + case 'private': + switch (elems.length) { + case 2: + return parsedPathPrivateList + case 3: + return { + kind: T.FS.PathKind.GroupTlf, + tlfName: elems[2]!, + tlfType: T.FS.TlfType.Private, + ...splitTlfIntoReadersAndWriters(elems[2]!), + } + default: + return { + kind: T.FS.PathKind.InGroupTlf, + rest: elems.slice(3), + tlfName: elems[2] ?? '', + tlfType: T.FS.TlfType.Private, + ...splitTlfIntoReadersAndWriters(elems[2] ?? ''), + } + } + case 'public': + switch (elems.length) { + case 2: + return parsedPathPublicList + case 3: + return { + kind: T.FS.PathKind.GroupTlf, + tlfName: elems[2]!, + tlfType: T.FS.TlfType.Public, + ...splitTlfIntoReadersAndWriters(elems[2]!), + } + default: + return { + kind: T.FS.PathKind.InGroupTlf, + rest: elems.slice(3), + tlfName: elems[2] ?? '', + tlfType: T.FS.TlfType.Public, + ...splitTlfIntoReadersAndWriters(elems[2] ?? ''), + } + } + case 'team': + switch (elems.length) { + case 2: + return parsedPathTeamList + case 3: + return { + kind: T.FS.PathKind.TeamTlf, + team: elems[2]!, + tlfName: elems[2]!, + tlfType: T.FS.TlfType.Team, + } + default: + return { + kind: T.FS.PathKind.InTeamTlf, + rest: elems.slice(3), + team: elems[2] ?? '', + tlfName: elems[2] ?? '', + tlfType: T.FS.TlfType.Team, + } + } + default: + return parsedPathRoot + } +} + +// Chat/Share Utilities +export const canChat = (path: T.FS.Path) => { + const parsedPath = parsePath(path) + switch (parsedPath.kind) { + case T.FS.PathKind.Root: + case T.FS.PathKind.TlfList: + return false + case T.FS.PathKind.GroupTlf: + case T.FS.PathKind.TeamTlf: + return true + case T.FS.PathKind.InGroupTlf: + case T.FS.PathKind.InTeamTlf: + return true + default: + return false + } +} + +export const isTeamPath = (path: T.FS.Path): boolean => { + const parsedPath = parsePath(path) + return parsedPath.kind !== T.FS.PathKind.Root && parsedPath.tlfType === T.FS.TlfType.Team +} + +export const getChatTarget = (path: T.FS.Path, me: string): string => { + const parsedPath = parsePath(path) + if (parsedPath.kind !== T.FS.PathKind.Root && parsedPath.tlfType === T.FS.TlfType.Team) { + return 'team conversation' + } + if (parsedPath.kind === T.FS.PathKind.GroupTlf || parsedPath.kind === T.FS.PathKind.InGroupTlf) { + if (parsedPath.writers.length === 1 && !parsedPath.readers && parsedPath.writers[0] === me) { + return 'yourself' + } + if (parsedPath.writers.length + (parsedPath.readers ? parsedPath.readers.length : 0) === 2) { + const notMe = parsedPath.writers.concat(parsedPath.readers || []).filter(u => u !== me) + if (notMe.length === 1) { + return notMe[0]! + } + } + return 'group conversation' + } + return 'conversation' +} + +export const getSharePathArrayDescription = (paths: ReadonlyArray): string => { + return !paths.length ? '' : paths.length === 1 ? T.FS.getPathName(paths[0]) : `${paths.length} items` +} + +export const getDestinationPickerPathName = (picker: T.FS.DestinationPicker): string => + picker.source.type === T.FS.DestinationPickerSource.MoveOrCopy + ? T.FS.getPathName(picker.source.path) + : picker.source.type === T.FS.DestinationPickerSource.IncomingShare + ? getSharePathArrayDescription( + picker.source.source + .map(({originalPath}) => (originalPath ? T.FS.getLocalPathName(originalPath) : '')) + .filter(Boolean) + ) + : '' + +// File/Download Utilities +export const humanReadableFileSize = (size: number) => { + const kib = 1024 + const mib = kib * kib + const gib = mib * kib + const tib = gib * kib + + if (!size) return '' + if (size >= tib) return `${Math.round(size / tib)} TB` + if (size >= gib) return `${Math.round(size / gib)} GB` + if (size >= mib) return `${Math.round(size / mib)} MB` + if (size >= kib) return `${Math.round(size / kib)} KB` + return `${size} B` +} + +export const humanizeBytes = (n: number, numDecimals: number): string => { + const kb = 1024 + const mb = kb * 1024 + const gb = mb * 1024 + + if (n < kb) { + return `${n} bytes` + } else if (n < mb) { + return `${(n / kb).toFixed(numDecimals)} KB` + } else if (n < gb) { + return `${(n / mb).toFixed(numDecimals)} MB` + } + return `${(n / gb).toFixed(numDecimals)} GB` +} + +export const humanizeBytesOfTotal = (n: number, d: number): string => { + const kb = 1024 + const mb = kb * 1024 + const gb = mb * 1024 + + if (d < kb) { + return `${n} of ${d} bytes` + } else if (d < mb) { + return `${(n / kb).toFixed(2)} of ${(d / kb).toFixed(2)} KB` + } else if (d < gb) { + return `${(n / mb).toFixed(2)} of ${(d / mb).toFixed(2)} MB` + } + return `${(n / gb).toFixed(2)} of ${(d / gb).toFixed(2)} GB` +} + +export const downloadIsOngoing = (dlState: T.FS.DownloadState) => + dlState !== emptyDownloadState && !dlState.error && !dlState.done && !dlState.canceled + +export const getDownloadIntent = ( + path: T.FS.Path, + downloads: T.FS.Downloads, + pathItemActionMenu: T.FS.PathItemActionMenu +): T.FS.DownloadIntent | undefined => { + const found = [...downloads.info].find(([_, info]) => info.path === path) + if (!found) { + return undefined + } + const [downloadID] = found + const dlState = downloads.state.get(downloadID) || emptyDownloadState + if (!downloadIsOngoing(dlState)) { + return undefined + } + if (pathItemActionMenu.downloadID === downloadID) { + return pathItemActionMenu.downloadIntent + } + return T.FS.DownloadIntent.None +} + +export const canSaveMedia = (pathItem: T.FS.PathItem, fileContext: T.FS.FileContext): boolean => { + if (pathItem.type !== T.FS.PathType.File || fileContext === emptyFileContext) { + return false + } + return ( + fileContext.viewType === T.RPCGen.GUIViewType.image || fileContext.viewType === T.RPCGen.GUIViewType.video + ) +} + +export const isOfflineUnsynced = ( + daemonStatus: T.FS.KbfsDaemonStatus, + pathItem: T.FS.PathItem, + path: T.FS.Path +) => + daemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline && + T.FS.getPathLevel(path) > 2 && + pathItem.prefetchStatus !== prefetchComplete + +// Status/Icon Utilities +export const getUploadIconForTlfType = ( + kbfsDaemonStatus: T.FS.KbfsDaemonStatus, + uploads: T.FS.Uploads, + tlfList: T.FS.TlfList, + tlfType: T.FS.TlfType +): T.FS.UploadIcon | undefined => { + if ( + [...tlfList].some( + ([_, tlf]) => + tlf.conflictState.type === T.FS.ConflictStateType.NormalView && tlf.conflictState.stuckInConflict + ) + ) { + return T.FS.UploadIcon.UploadingStuck + } + + const prefix = T.FS.pathToString(T.FS.getTlfTypePathFromTlfType(tlfType)) + if ( + [...uploads.syncingPaths].some(p => T.FS.pathToString(p).startsWith(prefix)) || + [...uploads.writingToJournal.keys()].some(p => T.FS.pathToString(p).startsWith(prefix)) + ) { + return kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline + ? T.FS.UploadIcon.AwaitingToUpload + : T.FS.UploadIcon.Uploading + } + + return undefined +} + +export const isPathEnabledForSync = (syncConfig: T.FS.TlfSyncConfig, path: T.FS.Path): boolean => { + switch (syncConfig.mode) { + case T.FS.TlfSyncMode.Disabled: + return false + case T.FS.TlfSyncMode.Enabled: + return true + case T.FS.TlfSyncMode.Partial: + // TODO: when we enable partial sync lookup, remember to deal with + // potential ".." traversal as well. + return syncConfig.enabledPaths.includes(path) + default: + return false + } +} + +export const getPathStatusIconInMergeProps = ( + kbfsDaemonStatus: T.FS.KbfsDaemonStatus, + tlf: T.Immutable, + pathItem: T.Immutable, + uploadingPaths: T.Immutable>, + path: T.Immutable +): T.FS.PathStatusIcon => { + // There's no upload or sync for local conflict view. + if (tlf.conflictState.type === T.FS.ConflictStateType.ManualResolvingLocalView) { + return T.FS.LocalConflictStatus + } + + // uploading state has higher priority + if (uploadingPaths.has(path)) { + // eslint-disable-next-line + return tlf.conflictState.type === T.FS.ConflictStateType.NormalView && tlf.conflictState.stuckInConflict + ? T.FS.UploadIcon.UploadingStuck + : kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline + ? T.FS.UploadIcon.AwaitingToUpload + : T.FS.UploadIcon.Uploading + } + if (!isPathEnabledForSync(tlf.syncConfig, path)) { + return T.FS.NonUploadStaticSyncStatus.OnlineOnly + } + + if (pathItem === unknownPathItem && tlf.syncConfig.mode !== T.FS.TlfSyncMode.Disabled) { + return T.FS.NonUploadStaticSyncStatus.Unknown + } + + // TODO: what about 'sync-error'? + + // We don't have an upload state, and sync is enabled for this path. + switch (pathItem.prefetchStatus.state) { + case T.FS.PrefetchState.NotStarted: + return T.FS.NonUploadStaticSyncStatus.AwaitingToSync + case T.FS.PrefetchState.Complete: + return T.FS.NonUploadStaticSyncStatus.Synced + case T.FS.PrefetchState.InProgress: { + if (kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline) { + return T.FS.NonUploadStaticSyncStatus.AwaitingToSync + } + const inProgress: T.FS.PrefetchInProgress = pathItem.prefetchStatus + if (inProgress.bytesTotal === 0) { + return T.FS.NonUploadStaticSyncStatus.AwaitingToSync + } + return inProgress.bytesFetched / inProgress.bytesTotal + } + default: + return T.FS.NonUploadStaticSyncStatus.Unknown + } +} + +export const getMainBannerType = ( + kbfsDaemonStatus: T.FS.KbfsDaemonStatus, + overallSyncStatus: T.FS.OverallSyncStatus +): T.FS.MainBannerType => { + if (kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Offline) { + return T.FS.MainBannerType.Offline + } else if (kbfsDaemonStatus.onlineStatus === T.FS.KbfsDaemonOnlineStatus.Trying) { + return T.FS.MainBannerType.TryingToConnect + } else if (overallSyncStatus.diskSpaceStatus === T.FS.DiskSpaceStatus.Error) { + return T.FS.MainBannerType.OutOfSpace + } else { + return T.FS.MainBannerType.None + } +} + +// Settings/Configuration Utilities +export const getPathUserSetting = ( + pathUserSettings: T.Immutable>, + path: T.Immutable +): T.FS.PathUserSetting => + pathUserSettings.get(path) || + (T.FS.getPathLevel(path) < 3 ? defaultTlfListPathUserSetting : defaultPathUserSetting) + +export const showSortSetting = ( + path: T.FS.Path, + pathItem: T.FS.PathItem, + kbfsDaemonStatus: T.FS.KbfsDaemonStatus +) => + !isMobile && + path !== defaultPath && + (T.FS.getPathLevel(path) === 2 || (pathItem.type === T.FS.PathType.Folder && !!pathItem.children.size)) && + !isOfflineUnsynced(kbfsDaemonStatus, pathItem, path) + +export const getSoftError = (softErrors: T.FS.SoftErrors, path: T.FS.Path): T.FS.SoftError | undefined => { + const pathError = softErrors.pathErrors.get(path) + if (pathError) { + return pathError + } + if (!softErrors.tlfErrors.size) { + return undefined + } + const tlfPath = getTlfPath(path) + return (tlfPath && softErrors.tlfErrors.get(tlfPath)) || undefined +} + +export const sfmiInfoLoaded = (settings: T.FS.Settings, driverStatus: T.FS.DriverStatus): boolean => + settings.loaded && driverStatus !== driverStatusUnknown + +export const hideOrDisableInDestinationPicker = ( + tlfType: T.FS.TlfType, + name: string, + username: string, + destinationPickerIndex?: number +) => typeof destinationPickerIndex === 'number' && tlfType === T.FS.TlfType.Public && name !== username + +// Other Utilities +export const syntheticEventToTargetRect = (evt?: React.SyntheticEvent): DOMRect | undefined => + isMobile ? undefined : evt ? (evt.target as HTMLElement).getBoundingClientRect() : undefined + +export const showIgnoreFolder = (path: T.FS.Path, username?: string): boolean => { + const elems = T.FS.getPathElements(path) + if (elems.length !== 3) { + return false + } + return ['public', 'private'].includes(elems[1]!) && elems[2]! !== username +} + +// RPC to State Conversion +export const fsNotificationTypeToEditType = ( + fsNotificationType: T.RPCChat.Keybase1.FSNotificationType +): T.FS.FileEditType => { + switch (fsNotificationType) { + case T.RPCGen.FSNotificationType.fileCreated: + return T.FS.FileEditType.Created + case T.RPCGen.FSNotificationType.fileModified: + return T.FS.FileEditType.Modified + case T.RPCGen.FSNotificationType.fileDeleted: + return T.FS.FileEditType.Deleted + case T.RPCGen.FSNotificationType.fileRenamed: + return T.FS.FileEditType.Renamed + default: + return T.FS.FileEditType.Unknown + } +} + +export const userTlfHistoryRPCToState = ( + history: ReadonlyArray +): T.FS.UserTlfUpdates => { + let updates: Array = [] + history.forEach(folder => { + const updateServerTime = folder.serverTime + const path = pathFromFolderRPC(folder.folder) + const tlfUpdates = folder.history + ? folder.history.map(({writerName, edits}) => ({ + history: edits + ? edits.map(({filename, notificationType, serverTime}) => ({ + editType: fsNotificationTypeToEditType(notificationType), + filename, + serverTime, + })) + : [], + path, + serverTime: updateServerTime, + writer: writerName, + })) + : [] + updates = updates.concat(tlfUpdates) + }) + return updates +} diff --git a/shared/constants/git/index.tsx b/shared/constants/git/index.tsx index 497136984873..297dc32a67f4 100644 --- a/shared/constants/git/index.tsx +++ b/shared/constants/git/index.tsx @@ -5,7 +5,7 @@ import * as EngineGen from '@/actions/engine-gen-gen' import * as dateFns from 'date-fns' import * as Z from '@/util/zustand' import debounce from 'lodash/debounce' -import {storeRegistry} from '../store-registry' +import {navigateAppend} from '../router2/util' import {useConfigState} from '../config' const parseRepos = (results: ReadonlyArray) => { @@ -152,9 +152,7 @@ export const useGitState = Z.createZustand((set, get) => { await _load() for (const [, info] of get().idToInfo) { if (info.repoID === repoID && info.teamname === teamname) { - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {expanded: info.id}, selected: 'gitRoot'}) + navigateAppend({props: {expanded: info.id}, selected: 'gitRoot'}) break } } diff --git a/shared/constants/recover-password/index.tsx b/shared/constants/recover-password/index.tsx index 1012961c6f45..8a642f8b9487 100644 --- a/shared/constants/recover-password/index.tsx +++ b/shared/constants/recover-password/index.tsx @@ -108,17 +108,13 @@ export const useState = Z.createZustand((set, get) => { } }) }) - storeRegistry - .getState('router') - .dispatch.navigateAppend('recoverPasswordDeviceSelector', !!replaceRoute) + navigateAppend('recoverPasswordDeviceSelector', !!replaceRoute) }, 'keybase.1.loginUi.promptPassphraseRecovery': () => {}, // This same RPC is called at the beginning and end of the 7-day wait by the service. 'keybase.1.loginUi.promptResetAccount': (params, response) => { if (params.prompt.t === T.RPCGen.ResetPromptType.enterResetPw) { - storeRegistry - .getState('router') - .dispatch.navigateAppend('recoverPasswordPromptResetPassword') + navigateAppend('recoverPasswordPromptResetPassword') const clear = () => { set(s => { s.dispatch.dynamic.submitResetPassword = undefined @@ -228,14 +224,12 @@ export const useState = Z.createZustand((set, get) => { set(s => { s.error = msg }) - storeRegistry - .getState('router') - .dispatch.navigateAppend( - useConfigState.getState().loggedIn - ? 'recoverPasswordErrorModal' - : 'recoverPasswordError', - true - ) + navigateAppend( + useConfigState.getState().loggedIn + ? 'recoverPasswordErrorModal' + : 'recoverPasswordError', + true + ) } } finally { set(s => { diff --git a/shared/constants/store-registry.tsx b/shared/constants/store-registry.tsx index 7ec2ba533c69..1d04affa5e76 100644 --- a/shared/constants/store-registry.tsx +++ b/shared/constants/store-registry.tsx @@ -4,7 +4,6 @@ import type * as T from './types' import type * as TBType from './team-building' import type * as ConvoStateType from './chat2/convostate' import type {ConvoState} from './chat2/convostate' -import type {State as ArchiveState, useArchiveState} from './archive' import type {State as AutoResetState, useAutoResetState} from './autoreset' import type {State as BotsState, useBotsState} from './bots' import type {State as ChatState, useChatState} from './chat2' @@ -18,7 +17,6 @@ import type {State as ProfileState, useProfileState} from './profile' import type {State as ProvisionState, useProvisionState} from './provision' import type {State as PushState, usePushState} from './push' import type {State as RecoverPasswordState, useState as useRecoverPasswordState} from './recover-password' -import type {State as RouterState, useRouterState} from './router2' import type {State as SettingsState, useSettingsState} from './settings' import type {State as SettingsChatState, useSettingsChatState} from './settings-chat' import type {State as SettingsContactsState, useSettingsContactsState} from './settings-contacts' @@ -32,7 +30,6 @@ import type {State as UnlockFoldersState, useUnlockFoldersState} from './unlock- import type {State as UsersState, useUsersState} from './users' type StoreName = - | 'archive' | 'autoreset' | 'bots' | 'chat' @@ -46,7 +43,6 @@ type StoreName = | 'provision' | 'push' | 'recover-password' - | 'router' | 'settings' | 'settings-chat' | 'settings-contacts' @@ -60,7 +56,6 @@ type StoreName = | 'users' type StoreStates = { - archive: ArchiveState autoreset: AutoResetState bots: BotsState chat: ChatState @@ -74,7 +69,6 @@ type StoreStates = { provision: ProvisionState push: PushState 'recover-password': RecoverPasswordState - router: RouterState settings: SettingsState 'settings-chat': SettingsChatState 'settings-contacts': SettingsContactsState @@ -89,7 +83,6 @@ type StoreStates = { } type StoreHooks = { - archive: typeof useArchiveState autoreset: typeof useAutoResetState bots: typeof useBotsState chat: typeof useChatState @@ -103,7 +96,6 @@ type StoreHooks = { provision: typeof useProvisionState push: typeof usePushState 'recover-password': typeof useRecoverPasswordState - router: typeof useRouterState settings: typeof useSettingsState 'settings-chat': typeof useSettingsChatState 'settings-contacts': typeof useSettingsContactsState @@ -121,10 +113,6 @@ class StoreRegistry { getStore(storeName: T): StoreHooks[T] { /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return */ switch (storeName) { - case 'archive': { - const {useArchiveState} = require('./archive') - return useArchiveState - } case 'autoreset': { const {useAutoResetState} = require('./autoreset') return useAutoResetState @@ -177,10 +165,6 @@ class StoreRegistry { const {useState} = require('./recover-password') return useState } - case 'router': { - const {useRouterState} = require('./router2') - return useRouterState - } case 'settings': { const {useSettingsState} = require('./settings') return useSettingsState diff --git a/shared/constants/teams/index.tsx b/shared/constants/teams/index.tsx index 748e2fc01423..30ffecf7f3a7 100644 --- a/shared/constants/teams/index.tsx +++ b/shared/constants/teams/index.tsx @@ -1502,9 +1502,7 @@ export const useTeamsState = Z.createZustand((set, get) => { clearModals() navigateAppend({props: {teamID}, selected: 'team'}) if (isMobile) { - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {createdTeam: true, teamID}, selected: 'profileEditAvatar'}) + navigateAppend({props: {createdTeam: true, teamID}, selected: 'profileEditAvatar'}) } } } catch (error) { @@ -2031,9 +2029,7 @@ export const useTeamsState = Z.createZustand((set, get) => { ) logger.info(`leaveTeam: left ${teamname} successfully`) clearModals() - storeRegistry - .getState('router') - .dispatch.navUpToScreen(context === 'chat' ? 'chatRoot' : 'teamsRoot') + navUpToScreen(context === 'chat' ? 'chatRoot' : 'teamsRoot') get().dispatch.getTeams() } catch (error) { if (error instanceof RPCError) { @@ -2165,9 +2161,7 @@ export const useTeamsState = Z.createZustand((set, get) => { }) }, manageChatChannels: teamID => { - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {teamID}, selected: 'teamAddToChannels'}) + navigateAppend({props: {teamID}, selected: 'teamAddToChannels'}) }, notifyTeamTeamRoleMapChanged: (newVersion: number) => { const loadedVersion = get().teamRoleMap.loadedVersion @@ -2873,13 +2867,9 @@ export const useTeamsState = Z.createZustand((set, get) => { logger.info(`team="${teamname}" cannot be loaded:`, err) // navigate to team page for team we're not in logger.info(`showing external team page, join=${join}`) - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {teamname}, selected: 'teamExternalTeam'}) + navigateAppend({props: {teamname}, selected: 'teamExternalTeam'}) if (join) { - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {initialTeamname: teamname}, selected: 'teamJoinTeamDialog'}) + navigateAppend({props: {initialTeamname: teamname}, selected: 'teamJoinTeamDialog'}) } return } @@ -2901,9 +2891,7 @@ export const useTeamsState = Z.createZustand((set, get) => { return } } - storeRegistry - .getState('router') - .dispatch.navigateAppend({props: {initialTab, teamID}, selected: 'team'}) + navigateAppend({props: {initialTab, teamID}, selected: 'team'}) if (addMembers) { navigateAppend({ props: {namespace: 'teams', teamID, title: ''}, diff --git a/shared/settings/archive/modal.tsx b/shared/settings/archive/modal.tsx index ff13598e2693..d74739fcb969 100644 --- a/shared/settings/archive/modal.tsx +++ b/shared/settings/archive/modal.tsx @@ -6,6 +6,8 @@ import {pickSave} from '@/util/pick-files' import * as FsCommon from '@/fs/common' import {useArchiveState} from '@/constants/archive' import {settingsArchiveTab} from '@/constants/settings' +import {useCurrentUserState} from '@/constants/current-user' +import {getConvoState} from '@/constants/chat2/convostate' type Props = | {type: 'chatID'; conversationIDKey: T.Chat.ConversationIDKey} @@ -16,12 +18,29 @@ type Props = | {type: 'fsPath'; path: string} | {type: 'git'; gitURL: string} +const chatIDToDisplayname = (conversationIDKey: string) => { + const you = useCurrentUserState.getState().username + const cs = getConvoState(conversationIDKey) + const m = cs.meta + if (m.teamname) { + if (m.channelname) { + return `${m.teamname}#${m.channelname}` + } + return m.teamname + } + + const participants = cs.participants.name + if (participants.length === 1) { + return participants[0] ?? '' + } + return participants.filter(username => username !== you).join(',') +} + const ArchiveModal = (p: Props) => { const {type} = p - const chatIDToDisplayname = useArchiveState(s => s.chatIDToDisplayname) const displayname = React.useMemo(() => { return p.type === 'chatID' ? chatIDToDisplayname(p.conversationIDKey) : '' - }, [p, chatIDToDisplayname]) + }, [p]) let defaultPath = '' if (C.isElectron) { From 17f1fccbbe6ba601e28e8842fe8e0c149485d164 Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Mon, 12 Jan 2026 09:32:40 -0500 Subject: [PATCH 11/20] WIP: shift 12 (#28794) * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/app/global-errors/hook.tsx | 4 +- shared/app/index.native.tsx | 4 +- shared/app/main.desktop.tsx | 2 +- shared/app/out-of-date.tsx | 2 +- shared/app/runtime-stats.tsx | 2 +- shared/chat/audio/audio-recorder.native.tsx | 2 +- shared/chat/blocking/block-modal.tsx | 6 +- shared/chat/blocking/invitation-to-block.tsx | 6 +- shared/chat/chat-button.tsx | 4 +- .../attachment-fullscreen/hooks.tsx | 4 +- .../conversation/attachment-get-titles.tsx | 2 +- shared/chat/conversation/bot/confirm.tsx | 2 +- shared/chat/conversation/bot/install.tsx | 6 +- shared/chat/conversation/bot/search.tsx | 4 +- shared/chat/conversation/bot/team-picker.tsx | 2 +- shared/chat/conversation/bottom-banner.tsx | 6 +- shared/chat/conversation/command-markdown.tsx | 2 +- shared/chat/conversation/command-status.tsx | 4 +- shared/chat/conversation/container.tsx | 2 +- shared/chat/conversation/error.tsx | 2 +- shared/chat/conversation/fwd-msg.tsx | 2 +- shared/chat/conversation/giphy/hooks.tsx | 2 +- .../conversation/header-area/index.native.tsx | 8 +- .../conversation/info-panel/add-people.tsx | 4 +- .../info-panel/add-to-channel.tsx | 4 +- .../conversation/info-panel/attachments.tsx | 4 +- shared/chat/conversation/info-panel/bot.tsx | 8 +- .../chat/conversation/info-panel/common.tsx | 4 +- .../chat/conversation/info-panel/header.tsx | 4 +- shared/chat/conversation/info-panel/index.tsx | 4 +- .../chat/conversation/info-panel/members.tsx | 8 +- shared/chat/conversation/info-panel/menu.tsx | 8 +- .../info-panel/settings/index.tsx | 6 +- .../info-panel/settings/min-writer-role.tsx | 4 +- .../info-panel/settings/notifications.tsx | 2 +- .../conversation/input-area/container.tsx | 2 +- .../input-area/location-popup.native.tsx | 6 +- .../conversation/input-area/normal2/index.tsx | 4 +- .../normal2/moremenu-popup.native.tsx | 2 +- .../normal2/platform-input.desktop.tsx | 2 +- .../normal2/platform-input.native.tsx | 4 +- .../normal2/set-explode-popup/hooks.tsx | 2 +- .../input-area/normal2/typing.tsx | 2 +- .../chat/conversation/input-area/preview.tsx | 2 +- .../input-area/suggestors/channels.tsx | 4 +- .../input-area/suggestors/commands.tsx | 2 +- .../input-area/suggestors/emoji.tsx | 2 +- .../input-area/suggestors/index.tsx | 2 +- .../input-area/suggestors/users.tsx | 6 +- shared/chat/conversation/list-area/hooks.tsx | 2 +- .../conversation/list-area/index.desktop.tsx | 4 +- .../conversation/list-area/index.native.tsx | 2 +- shared/chat/conversation/load-status.tsx | 2 +- .../messages/account-payment/container.tsx | 4 +- .../messages/account-payment/wrapper.tsx | 2 +- .../messages/attachment/audio.tsx | 4 +- .../conversation/messages/attachment/file.tsx | 6 +- .../messages/attachment/image2/use-state.tsx | 2 +- .../messages/attachment/shared.tsx | 4 +- .../messages/attachment/video/use-state.tsx | 2 +- .../conversation/messages/cards/make-team.tsx | 2 +- .../messages/cards/team-journey/container.tsx | 4 +- .../chat/conversation/messages/emoji-row.tsx | 2 +- .../messages/message-popup/attachment.tsx | 4 +- .../message-popup/exploding-header.tsx | 2 +- .../messages/message-popup/header.tsx | 2 +- .../messages/message-popup/hooks.tsx | 10 +- .../messages/message-popup/index.tsx | 2 +- .../messages/message-popup/journeycard.tsx | 2 +- .../messages/message-popup/reactionitem.tsx | 2 +- .../messages/message-popup/text.tsx | 6 +- .../chat/conversation/messages/pin/index.tsx | 2 +- .../conversation/messages/pin/wrapper.tsx | 2 +- .../messages/placeholder/wrapper.tsx | 2 +- .../conversation/messages/react-button.tsx | 4 +- .../messages/reaction-tooltip.tsx | 4 +- .../conversation/messages/reactions-rows.tsx | 2 +- .../chat/conversation/messages/reset-user.tsx | 4 +- .../messages/retention-notice.tsx | 4 +- .../chat/conversation/messages/separator.tsx | 10 +- .../messages/set-channelname/wrapper.tsx | 2 +- .../messages/set-description/wrapper.tsx | 2 +- .../messages/special-bottom-message.tsx | 2 +- .../messages/special-top-message.tsx | 6 +- .../system-added-to-team/container.tsx | 6 +- .../messages/system-added-to-team/wrapper.tsx | 2 +- .../messages/system-change-avatar/index.tsx | 2 +- .../messages/system-change-avatar/wrapper.tsx | 2 +- .../system-change-retention/container.tsx | 6 +- .../system-change-retention/wrapper.tsx | 2 +- .../messages/system-create-team/container.tsx | 6 +- .../messages/system-create-team/wrapper.tsx | 2 +- .../messages/system-git-push/container.tsx | 8 +- .../messages/system-git-push/wrapper.tsx | 2 +- .../system-invite-accepted/container.tsx | 6 +- .../system-invite-accepted/wrapper.tsx | 2 +- .../messages/system-joined/container.tsx | 2 +- .../messages/system-joined/wrapper.tsx | 2 +- .../messages/system-left/container.tsx | 2 +- .../messages/system-left/wrapper.tsx | 2 +- .../messages/system-new-channel/container.tsx | 4 +- .../messages/system-new-channel/wrapper.tsx | 2 +- .../container.tsx | 2 +- .../messages/system-profile-reset-notice.tsx | 2 +- .../messages/system-sbs-resolve/container.tsx | 2 +- .../messages/system-sbs-resolve/wrapper.tsx | 4 +- .../system-simple-to-complex/container.tsx | 6 +- .../system-simple-to-complex/wrapper.tsx | 2 +- .../messages/system-text/wrapper.tsx | 2 +- .../system-users-added-to-conv/container.tsx | 4 +- .../system-users-added-to-conv/wrapper.tsx | 2 +- .../conversation/messages/text/bottom.tsx | 2 +- .../messages/text/coinflip/index.tsx | 2 +- .../chat/conversation/messages/text/reply.tsx | 2 +- .../text/unfurl/prompt-list/container.tsx | 2 +- .../text/unfurl/unfurl-list/generic.tsx | 2 +- .../text/unfurl/unfurl-list/giphy.tsx | 2 +- .../text/unfurl/unfurl-list/image/index.tsx | 2 +- .../text/unfurl/unfurl-list/index.tsx | 2 +- .../text/unfurl/unfurl-list/map-popup.tsx | 4 +- .../messages/text/unfurl/unfurl-list/map.tsx | 2 +- .../text/unfurl/unfurl-list/use-state.tsx | 4 +- .../conversation/messages/text/wrapper.tsx | 2 +- .../conversation/messages/wrapper/edited.tsx | 2 +- .../exploding-height-retainer/container.tsx | 2 +- .../messages/wrapper/exploding-meta.tsx | 2 +- .../wrapper/long-pressable/index.native.tsx | 2 +- .../messages/wrapper/send-indicator.tsx | 2 +- .../conversation/messages/wrapper/wrapper.tsx | 4 +- shared/chat/conversation/normal/container.tsx | 4 +- .../conversation/normal/index.desktop.tsx | 2 +- .../chat/conversation/normal/index.native.tsx | 2 +- shared/chat/conversation/pinned-message.tsx | 6 +- shared/chat/conversation/rekey/container.tsx | 6 +- shared/chat/conversation/reply-preview.tsx | 2 +- shared/chat/conversation/search.tsx | 2 +- shared/chat/create-channel/hooks.tsx | 2 +- shared/chat/delete-history-warning.tsx | 2 +- shared/chat/emoji-picker/container.tsx | 4 +- shared/chat/inbox-and-conversation-2.tsx | 2 +- shared/chat/inbox-and-conversation-header.tsx | 8 +- shared/chat/inbox-search/index.tsx | 4 +- shared/chat/inbox/container.tsx | 2 +- shared/chat/inbox/filter-row.tsx | 2 +- shared/chat/inbox/index.native.tsx | 2 +- shared/chat/inbox/new-chat-button.tsx | 2 +- shared/chat/inbox/row/big-team-channel.tsx | 2 +- shared/chat/inbox/row/big-team-header.tsx | 4 +- shared/chat/inbox/row/big-teams-divider.tsx | 2 +- shared/chat/inbox/row/build-team.tsx | 2 +- shared/chat/inbox/row/opened-row-state.tsx | 2 +- .../chat/inbox/row/small-team/bottom-line.tsx | 4 +- shared/chat/inbox/row/small-team/index.tsx | 4 +- .../swipe-conv-actions/index.native.tsx | 2 +- shared/chat/inbox/row/small-team/top-line.tsx | 2 +- shared/chat/inbox/row/teams-divider.tsx | 2 +- shared/chat/inbox/search-row.tsx | 2 +- shared/chat/new-team-dialog-container.tsx | 4 +- shared/chat/payments/status/index.tsx | 4 +- shared/chat/pdf/index.desktop.tsx | 4 +- shared/chat/pdf/index.native.tsx | 4 +- shared/chat/routes.tsx | 2 +- .../selectable-big-team-channel-container.tsx | 2 +- .../chat/selectable-small-team-container.tsx | 4 +- shared/chat/send-to-chat/index.tsx | 8 +- shared/common-adapters/avatar/hooks.tsx | 8 +- shared/common-adapters/avatar/util.tsx | 14 - shared/common-adapters/copy-text.tsx | 2 +- shared/common-adapters/markdown/channel.tsx | 2 +- .../markdown/maybe-mention/index.tsx | 2 +- .../markdown/maybe-mention/team.tsx | 4 +- shared/common-adapters/mention-container.tsx | 10 +- shared/common-adapters/mention.tsx | 2 +- shared/common-adapters/name-with-icon.tsx | 6 +- shared/common-adapters/profile-card.tsx | 10 +- .../common-adapters/proof-broken-banner.tsx | 4 +- shared/common-adapters/reload.tsx | 2 +- shared/common-adapters/team-with-popup.tsx | 2 +- shared/common-adapters/usernames.tsx | 10 +- shared/common-adapters/wave-button.tsx | 2 +- shared/constants/archive/util.tsx | 16 - shared/constants/autoreset/util.tsx | 13 - shared/constants/bots/util.tsx | 30 -- shared/constants/chat2/common.tsx | 4 +- shared/constants/chat2/convostate.tsx | 4 +- shared/constants/chat2/debug.tsx | 2 +- shared/constants/chat2/meta.tsx | 10 +- shared/constants/chat2/util.tsx | 61 --- shared/constants/deeplinks/index.tsx | 151 ++++---- shared/constants/deeplinks/util.tsx | 13 - shared/constants/devices/util.tsx | 21 -- shared/constants/followers/util.tsx | 29 -- shared/constants/fs/common.native.tsx | 4 +- .../fs/platform-specific.android.tsx | 70 ++-- .../fs/platform-specific.desktop.tsx | 7 +- shared/constants/fs/util.tsx | 16 - shared/constants/git/util.tsx | 20 - shared/constants/index.tsx | 8 +- shared/constants/init/index.desktop.tsx | 26 +- shared/constants/init/index.native.tsx | 26 +- shared/constants/init/shared.tsx | 348 +++++++++++++++--- shared/constants/notifications/util.tsx | 69 ---- shared/constants/people/util.tsx | 28 -- shared/constants/pinentry/util.tsx | 28 -- .../platform-specific/kbfs-notifications.tsx | 2 +- .../platform-specific/push.native.tsx | 4 +- shared/constants/push.native.tsx | 24 +- shared/constants/rpc-utils.tsx | 9 +- shared/constants/settings/util.tsx | 17 - shared/constants/signup/util.tsx | 13 - shared/constants/store-registry.tsx | 111 +++--- shared/constants/teams/util.tsx | 23 -- shared/constants/tracker2/util.tsx | 36 -- shared/constants/unlock-folders/util.tsx | 30 -- shared/constants/users/util.tsx | 14 - shared/crypto/input.tsx | 4 +- shared/crypto/operations/decrypt.tsx | 2 +- shared/crypto/operations/encrypt.tsx | 2 +- shared/crypto/operations/sign.tsx | 2 +- shared/crypto/operations/verify.tsx | 2 +- shared/crypto/output.tsx | 10 +- shared/crypto/recipients.tsx | 2 +- shared/crypto/sub-nav/index.desktop.tsx | 2 +- shared/crypto/sub-nav/index.native.tsx | 2 +- shared/crypto/sub-nav/left-nav.desktop.tsx | 2 +- shared/desktop/app/menu-bar.desktop.tsx | 2 +- .../remote/use-serialize-props.desktop.tsx | 2 +- shared/desktop/renderer/main.desktop.tsx | 2 +- shared/desktop/renderer/main2.desktop.tsx | 6 +- shared/devices/add-device.tsx | 4 +- shared/devices/device-icon.tsx | 4 +- shared/devices/device-page.tsx | 2 +- shared/devices/device-revoke.tsx | 8 +- shared/devices/index.tsx | 2 +- shared/devices/nav-header.tsx | 4 +- shared/devices/row.tsx | 2 +- shared/fs/banner/conflict-banner.tsx | 4 +- shared/fs/banner/public-reminder.tsx | 4 +- shared/fs/banner/reset-banner.tsx | 8 +- .../container.tsx | 4 +- .../kext-permission-popup.tsx | 2 +- shared/fs/browser/destination-picker.tsx | 4 +- shared/fs/browser/index.tsx | 4 +- shared/fs/browser/offline.tsx | 4 +- shared/fs/browser/root.tsx | 6 +- shared/fs/browser/rows/editing.tsx | 4 +- shared/fs/browser/rows/rows-container.tsx | 6 +- shared/fs/browser/rows/still.tsx | 4 +- shared/fs/browser/rows/tlf-type.tsx | 2 +- shared/fs/browser/rows/tlf.tsx | 6 +- shared/fs/common/errs-container.tsx | 2 +- shared/fs/common/folder-view-filter-icon.tsx | 4 +- shared/fs/common/folder-view-filter.tsx | 4 +- shared/fs/common/hooks.tsx | 4 +- shared/fs/common/item-icon.tsx | 4 +- shared/fs/common/kbfs-path.tsx | 2 +- shared/fs/common/last-modified-line.tsx | 4 +- .../fs/common/open-in-system-file-manager.tsx | 2 +- shared/fs/common/path-info.tsx | 4 +- .../common/path-item-action/choose-view.tsx | 2 +- .../path-item-action/confirm-delete.tsx | 4 +- shared/fs/common/path-item-action/confirm.tsx | 4 +- shared/fs/common/path-item-action/index.tsx | 4 +- shared/fs/common/path-item-action/layout.tsx | 2 +- .../path-item-action/menu-container.tsx | 8 +- shared/fs/common/path-item-info.tsx | 4 +- .../fs/common/path-status-icon-container.tsx | 4 +- .../common/refresh-driver-status-on-mount.tsx | 2 +- shared/fs/common/sfmi-popup.tsx | 2 +- shared/fs/common/tlf-info-line-container.tsx | 6 +- shared/fs/common/upload-button.tsx | 4 +- shared/fs/common/use-open.tsx | 4 +- shared/fs/filepreview/bare-preview.tsx | 2 +- shared/fs/filepreview/default-view.tsx | 4 +- shared/fs/filepreview/view.tsx | 6 +- shared/fs/footer/download.tsx | 4 +- shared/fs/footer/downloads.tsx | 2 +- shared/fs/footer/proof-broken.tsx | 4 +- shared/fs/footer/upload-container.tsx | 4 +- shared/fs/index.tsx | 4 +- shared/fs/nav-header/actions.tsx | 4 +- shared/fs/nav-header/main-banner.tsx | 6 +- shared/fs/nav-header/mobile-header.tsx | 4 +- shared/fs/nav-header/title.tsx | 2 +- shared/fs/routes.tsx | 2 +- shared/fs/top-bar/loading.tsx | 4 +- shared/fs/top-bar/sort.tsx | 4 +- shared/fs/top-bar/sync-toggle.tsx | 4 +- shared/git/delete-repo.tsx | 2 +- shared/git/index.tsx | 2 +- shared/git/nav-header.tsx | 2 +- shared/git/new-repo.tsx | 4 +- shared/git/row.tsx | 10 +- shared/git/select-channel.tsx | 4 +- shared/incoming-share/index.tsx | 8 +- shared/login/index.tsx | 4 +- shared/login/join-or-login.tsx | 6 +- shared/login/loading.tsx | 2 +- .../recover-password/device-selector.tsx | 2 +- shared/login/recover-password/error-modal.tsx | 4 +- shared/login/recover-password/error.tsx | 4 +- .../login/recover-password/explain-device.tsx | 2 +- shared/login/recover-password/paper-key.tsx | 2 +- shared/login/recover-password/password.tsx | 2 +- .../recover-password/prompt-reset-shared.tsx | 4 +- shared/login/relogin/container.tsx | 8 +- shared/login/reset/confirm.tsx | 4 +- shared/login/reset/modal.tsx | 2 +- shared/login/reset/password-enter.tsx | 2 +- shared/login/reset/password-known.tsx | 2 +- shared/login/reset/waiting.tsx | 2 +- shared/login/signup/error.tsx | 2 +- shared/menubar/chat-container.desktop.tsx | 2 +- shared/menubar/files-container.desktop.tsx | 4 +- shared/menubar/remote-container.desktop.tsx | 14 +- shared/menubar/remote-proxy.desktop.tsx | 22 +- shared/people/announcement.tsx | 4 +- shared/people/container.tsx | 8 +- shared/people/index.shared.tsx | 4 +- shared/people/routes.tsx | 2 +- shared/people/todo.tsx | 14 +- shared/pinentry/remote-container.desktop.tsx | 2 +- shared/pinentry/remote-proxy.desktop.tsx | 2 +- shared/pinentry/remote-serializer.desktop.tsx | 2 +- shared/profile/add-to-team.tsx | 2 +- shared/profile/confirm-or-pending.tsx | 2 +- shared/profile/edit-avatar/hooks.tsx | 4 +- shared/profile/edit-profile.tsx | 6 +- shared/profile/generic/enter-username.tsx | 2 +- shared/profile/generic/proofs-list.tsx | 4 +- shared/profile/generic/result.tsx | 2 +- shared/profile/pgp/finished/index.desktop.tsx | 2 +- shared/profile/pgp/generate/index.desktop.tsx | 2 +- shared/profile/pgp/info/index.desktop.tsx | 2 +- shared/profile/post-proof.tsx | 4 +- shared/profile/prove-enter-username.tsx | 2 +- shared/profile/prove-website-choice.tsx | 2 +- shared/profile/revoke.tsx | 2 +- shared/profile/showcase-team-offer.tsx | 6 +- shared/profile/user/actions/index.tsx | 10 +- shared/profile/user/friend.tsx | 4 +- shared/profile/user/hooks.tsx | 8 +- shared/profile/user/teams/index.tsx | 6 +- shared/provision/code-page/container.tsx | 6 +- shared/provision/code-page/qr-scan/hooks.tsx | 2 +- .../code-page/qr-scan/not-authorized.tsx | 2 +- shared/provision/error.tsx | 4 +- shared/provision/forgot-username.tsx | 4 +- shared/provision/paper-key.tsx | 2 +- shared/provision/password.tsx | 4 +- .../select-other-device-connected.tsx | 4 +- shared/provision/select-other-device.tsx | 2 +- shared/provision/set-public-name.tsx | 4 +- shared/provision/troubleshooting.tsx | 4 +- shared/provision/username-or-email.tsx | 6 +- shared/router-v2/account-switcher/index.tsx | 12 +- shared/router-v2/common.native.tsx | 2 +- shared/router-v2/header/index.desktop.tsx | 2 +- shared/router-v2/header/syncing-folders.tsx | 4 +- shared/router-v2/hooks.native.tsx | 4 +- shared/router-v2/router.desktop.tsx | 6 +- shared/router-v2/router.native.tsx | 8 +- shared/router-v2/router.shared.tsx | 4 +- shared/router-v2/tab-bar.desktop.tsx | 14 +- shared/router-v2/tab-bar.native.tsx | 2 +- shared/settings/account/add-modals.tsx | 4 +- shared/settings/account/confirm-delete.tsx | 4 +- shared/settings/account/email-phone-row.tsx | 4 +- shared/settings/account/index.tsx | 8 +- shared/settings/advanced.tsx | 8 +- shared/settings/archive/index.tsx | 6 +- shared/settings/archive/modal.tsx | 6 +- shared/settings/chat.tsx | 10 +- shared/settings/contacts-joined.tsx | 6 +- shared/settings/db-nuke.confirm.tsx | 2 +- .../check-passphrase.native.tsx | 2 +- shared/settings/delete-confirm/index.tsx | 6 +- .../settings/disable-cert-pinning-modal.tsx | 2 +- shared/settings/display.tsx | 4 +- .../settings/feedback/container.desktop.tsx | 2 +- shared/settings/feedback/container.native.tsx | 4 +- shared/settings/files/hooks.tsx | 2 +- shared/settings/files/index.desktop.tsx | 4 +- shared/settings/files/index.native.tsx | 4 +- shared/settings/files/refresh-settings.tsx | 2 +- shared/settings/group.tsx | 2 +- shared/settings/invites/index.desktop.tsx | 6 +- shared/settings/logout.tsx | 6 +- shared/settings/manage-contacts.tsx | 6 +- shared/settings/notifications/hooks.tsx | 6 +- .../settings/notifications/index.desktop.tsx | 4 +- .../settings/notifications/index.native.tsx | 4 +- shared/settings/password.tsx | 2 +- shared/settings/proxy.tsx | 2 +- shared/settings/root-desktop-tablet.tsx | 2 +- shared/settings/root-phone.tsx | 10 +- shared/settings/sub-nav/left-nav.tsx | 6 +- shared/signup/common.tsx | 2 +- shared/signup/device-name.tsx | 4 +- shared/signup/email.tsx | 4 +- shared/signup/feedback.tsx | 2 +- shared/signup/phone-number/index.tsx | 2 +- shared/signup/phone-number/verify.tsx | 2 +- shared/signup/username.tsx | 4 +- .../archive/index.tsx => stores/archive.tsx} | 6 +- .../index.tsx => stores/autoreset.tsx} | 15 +- .../bots/index.tsx => stores/bots.tsx} | 21 +- .../chat2/index.tsx => stores/chat2.tsx} | 48 +-- .../config/index.tsx => stores/config.tsx} | 16 +- .../crypto/index.tsx => stores/crypto.tsx} | 16 +- .../index.tsx => stores/current-user.tsx} | 2 +- .../daemon/index.tsx => stores/daemon.tsx} | 6 +- .../index.tsx => stores/darkmode.tsx} | 4 +- .../devices/index.tsx => stores/devices.tsx} | 6 +- .../index.tsx => stores/followers.tsx} | 1 - .../{constants/fs/index.tsx => stores/fs.tsx} | 24 +- .../git/index.tsx => stores/git.tsx} | 10 +- .../logout/index.tsx => stores/logout.tsx} | 10 +- .../index.tsx => stores/notifications.tsx} | 12 +- .../people/index.tsx => stores/people.tsx} | 12 +- .../index.tsx => stores/pinentry.tsx} | 4 +- .../profile/index.tsx => stores/profile.tsx} | 22 +- .../index.tsx => stores/provision.tsx} | 14 +- .../index.tsx => stores/recover-password.tsx} | 20 +- .../router2/index.tsx => stores/router2.tsx} | 12 +- .../index.tsx => stores/settings-chat.tsx} | 8 +- .../settings-contacts.d.ts | 2 +- .../settings-contacts.desktop.tsx | 0 .../settings-contacts.native.tsx | 16 +- .../index.tsx => stores/settings-email.tsx} | 6 +- .../index.tsx => stores/settings-invites.tsx} | 8 +- .../settings-notifications.tsx} | 8 +- .../settings-password.tsx} | 10 +- .../index.tsx => stores/settings-phone.tsx} | 32 +- .../index.tsx => stores/settings.tsx} | 54 +-- .../signup/index.tsx => stores/signup.tsx} | 14 +- .../index.tsx => stores/team-building.tsx} | 16 +- .../teams/index.tsx => stores/teams.tsx} | 24 +- .../index.tsx => stores/tracker2.tsx} | 12 +- .../index.tsx => stores/unlock-folders.tsx} | 4 +- .../users/index.tsx => stores/users.tsx} | 8 +- .../waiting/index.tsx => stores/waiting.tsx} | 2 +- .../wallets/index.tsx => stores/wallets.tsx} | 10 +- .../index.tsx => stores/whats-new.tsx} | 6 +- shared/styles/colors.tsx | 2 +- shared/styles/index.native.tsx | 2 +- shared/styles/style-sheet-proxy.tsx | 2 +- shared/team-building/contacts.tsx | 4 +- shared/team-building/email-search.tsx | 2 +- .../filtered-service-tab-bar.tsx | 2 +- shared/team-building/index.tsx | 4 +- shared/team-building/list-body.tsx | 10 +- shared/team-building/page.tsx | 2 +- shared/team-building/phone-search.tsx | 4 +- .../search-result/hellobot-result.tsx | 4 +- .../search-result/people-result.tsx | 8 +- .../search-result/you-result.tsx | 4 +- shared/team-building/shared.tsx | 2 +- .../add-contacts.native.tsx | 2 +- shared/teams/add-members-wizard/add-email.tsx | 2 +- .../add-members-wizard/add-from-where.tsx | 2 +- shared/teams/add-members-wizard/add-phone.tsx | 4 +- shared/teams/add-members-wizard/confirm.tsx | 6 +- shared/teams/channel/create-channels.tsx | 2 +- shared/teams/channel/header.tsx | 6 +- shared/teams/channel/index.tsx | 8 +- shared/teams/channel/rows.tsx | 10 +- shared/teams/channel/tabs.tsx | 2 +- shared/teams/common/activity.tsx | 4 +- shared/teams/common/channel-hooks.tsx | 4 +- shared/teams/common/enable-contacts.tsx | 2 +- shared/teams/common/selection-popup.tsx | 6 +- shared/teams/common/use-contacts.native.tsx | 4 +- .../teams/confirm-modals/confirm-kick-out.tsx | 4 +- .../confirm-remove-from-channel.tsx | 4 +- .../teams/confirm-modals/delete-channel.tsx | 2 +- .../really-leave-team/index.tsx | 4 +- shared/teams/container.tsx | 6 +- shared/teams/delete-team.tsx | 4 +- shared/teams/edit-team-description.tsx | 2 +- shared/teams/emojis/add-alias.tsx | 2 +- shared/teams/emojis/add-emoji.tsx | 2 +- shared/teams/external-team.tsx | 6 +- shared/teams/get-options.tsx | 2 +- .../team-invite-by-contacts.native.tsx | 4 +- shared/teams/invite-by-email.tsx | 2 +- shared/teams/join-team/container.tsx | 2 +- shared/teams/join-team/join-from-invite.tsx | 2 +- shared/teams/main/index.tsx | 2 +- shared/teams/main/team-row.tsx | 6 +- shared/teams/new-team/index.tsx | 2 +- .../new-team/wizard/add-subteam-members.tsx | 4 +- .../teams/new-team/wizard/create-channels.tsx | 2 +- .../teams/new-team/wizard/create-subteams.tsx | 2 +- .../teams/new-team/wizard/make-big-team.tsx | 2 +- .../teams/new-team/wizard/new-team-info.tsx | 4 +- shared/teams/new-team/wizard/team-purpose.tsx | 2 +- shared/teams/rename-team.tsx | 2 +- shared/teams/routes.tsx | 2 +- shared/teams/subscriber.tsx | 2 +- shared/teams/team/index.tsx | 4 +- shared/teams/team/member/add-to-channels.tsx | 6 +- shared/teams/team/member/edit-channel.tsx | 2 +- shared/teams/team/member/index.new.tsx | 8 +- shared/teams/team/menu-container.tsx | 2 +- shared/teams/team/new-header.tsx | 8 +- shared/teams/team/rows/bot-row/bot.tsx | 8 +- .../teams/team/rows/channel-row/channel.tsx | 4 +- shared/teams/team/rows/emoji-row/add.tsx | 4 +- shared/teams/team/rows/emoji-row/item.tsx | 4 +- shared/teams/team/rows/empty-row.tsx | 6 +- shared/teams/team/rows/index.tsx | 6 +- shared/teams/team/rows/invite-row/invite.tsx | 4 +- shared/teams/team/rows/invite-row/request.tsx | 6 +- shared/teams/team/rows/member-row.tsx | 12 +- shared/teams/team/rows/subteam-row/add.tsx | 2 +- .../team/settings-tab/default-channels.tsx | 4 +- shared/teams/team/settings-tab/index.tsx | 4 +- .../team/settings-tab/retention/index.tsx | 6 +- shared/teams/team/tabs.tsx | 4 +- shared/teams/team/team-info.tsx | 2 +- shared/tracker2/assertion.tsx | 10 +- shared/tracker2/bio.tsx | 4 +- shared/tracker2/remote-container.desktop.tsx | 12 +- shared/tracker2/remote-proxy.desktop.tsx | 10 +- shared/unlock-folders/device-list.desktop.tsx | 2 +- shared/unlock-folders/index.desktop.tsx | 4 +- .../remote-container.desktop.tsx | 4 +- .../unlock-folders/remote-proxy.desktop.tsx | 2 +- .../remote-serializer.desktop.tsx | 2 +- shared/util/phone-numbers/index.tsx | 20 +- shared/wallets/index.tsx | 4 +- shared/wallets/really-remove-account.tsx | 6 +- shared/wallets/remove-account.tsx | 2 +- shared/whats-new/container.tsx | 6 +- shared/whats-new/icon/index.tsx | 4 +- shared/whats-new/index.tsx | 2 +- shared/whats-new/versions.tsx | 2 +- 538 files changed, 1651 insertions(+), 1953 deletions(-) delete mode 100644 shared/common-adapters/avatar/util.tsx delete mode 100644 shared/constants/archive/util.tsx delete mode 100644 shared/constants/autoreset/util.tsx delete mode 100644 shared/constants/bots/util.tsx delete mode 100644 shared/constants/deeplinks/util.tsx delete mode 100644 shared/constants/devices/util.tsx delete mode 100644 shared/constants/followers/util.tsx delete mode 100644 shared/constants/git/util.tsx delete mode 100644 shared/constants/pinentry/util.tsx delete mode 100644 shared/constants/signup/util.tsx rename shared/{constants/archive/index.tsx => stores/archive.tsx} (98%) rename shared/{constants/autoreset/index.tsx => stores/autoreset.tsx} (92%) rename shared/{constants/bots/index.tsx => stores/bots.tsx} (91%) rename shared/{constants/chat2/index.tsx => stores/chat2.tsx} (98%) rename shared/{constants/config/index.tsx => stores/config.tsx} (98%) rename shared/{constants/crypto/index.tsx => stores/crypto.tsx} (98%) rename shared/{constants/current-user/index.tsx => stores/current-user.tsx} (96%) rename shared/{constants/daemon/index.tsx => stores/daemon.tsx} (98%) rename shared/{constants/darkmode/index.tsx => stores/darkmode.tsx} (97%) rename shared/{constants/devices/index.tsx => stores/devices.tsx} (96%) rename shared/{constants/followers/index.tsx => stores/followers.tsx} (99%) rename shared/{constants/fs/index.tsx => stores/fs.tsx} (98%) rename shared/{constants/git/index.tsx => stores/git.tsx} (96%) rename shared/{constants/logout/index.tsx => stores/logout.tsx} (91%) rename shared/{constants/notifications/index.tsx => stores/notifications.tsx} (95%) rename shared/{constants/people/index.tsx => stores/people.tsx} (98%) rename shared/{constants/pinentry/index.tsx => stores/pinentry.tsx} (97%) rename shared/{constants/profile/index.tsx => stores/profile.tsx} (97%) rename shared/{constants/provision/index.tsx => stores/provision.tsx} (98%) rename shared/{constants/recover-password/index.tsx => stores/recover-password.tsx} (94%) rename shared/{constants/router2/index.tsx => stores/router2.tsx} (94%) rename shared/{constants/settings-chat/index.tsx => stores/settings-chat.tsx} (95%) rename shared/{constants => stores}/settings-contacts.d.ts (95%) rename shared/{constants => stores}/settings-contacts.desktop.tsx (100%) rename shared/{constants => stores}/settings-contacts.native.tsx (95%) rename shared/{constants/settings-email/index.tsx => stores/settings-email.tsx} (97%) rename shared/{constants/settings-invites/index.tsx => stores/settings-invites.tsx} (95%) rename shared/{constants/settings-notifications/index.tsx => stores/settings-notifications.tsx} (97%) rename shared/{constants/settings-password/index.tsx => stores/settings-password.tsx} (94%) rename shared/{constants/settings-phone/index.tsx => stores/settings-phone.tsx} (88%) rename shared/{constants/settings/index.tsx => stores/settings.tsx} (79%) rename shared/{constants/signup/index.tsx => stores/signup.tsx} (96%) rename shared/{constants/team-building/index.tsx => stores/team-building.tsx} (97%) rename shared/{constants/teams/index.tsx => stores/teams.tsx} (99%) rename shared/{constants/tracker2/index.tsx => stores/tracker2.tsx} (98%) rename shared/{constants/unlock-folders/index.tsx => stores/unlock-folders.tsx} (95%) rename shared/{constants/users/index.tsx => stores/users.tsx} (96%) rename shared/{constants/waiting/index.tsx => stores/waiting.tsx} (98%) rename shared/{constants/wallets/index.tsx => stores/wallets.tsx} (86%) rename shared/{constants/whats-new/index.tsx => stores/whats-new.tsx} (92%) diff --git a/shared/app/global-errors/hook.tsx b/shared/app/global-errors/hook.tsx index 646d872c8f90..f35ad7056a9c 100644 --- a/shared/app/global-errors/hook.tsx +++ b/shared/app/global-errors/hook.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' import * as React from 'react' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import type {RPCError} from '@/util/errors' import {settingsFeedbackTab} from '@/constants/settings/util' -import {useDaemonState} from '@/constants/daemon' +import {useDaemonState} from '@/stores/daemon' export type Size = 'Closed' | 'Small' | 'Big' diff --git a/shared/app/index.native.tsx b/shared/app/index.native.tsx index 9fbbeae4fbbd..2a1c1337b56d 100644 --- a/shared/app/index.native.tsx +++ b/shared/app/index.native.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import * as Kb from '@/common-adapters' import * as React from 'react' import {handleAppLink} from '@/constants/deeplinks' @@ -18,7 +18,7 @@ import ServiceDecoration from '@/common-adapters/markdown/service-decoration' import {useUnmountAll} from '@/util/debug-react' import {darkModeSupported, guiConfig} from 'react-native-kb' import {install} from 'react-native-kb' -import * as DarkMode from '@/constants/darkmode' +import * as DarkMode from '@/stores/darkmode' import {initPlatformListener, onEngineConnected, onEngineDisconnected, onEngineIncoming} from '@/constants/init/index.native' enableFreeze(true) diff --git a/shared/app/main.desktop.tsx b/shared/app/main.desktop.tsx index 16ef0670516d..12bd8e36da36 100644 --- a/shared/app/main.desktop.tsx +++ b/shared/app/main.desktop.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import Router from '@/router-v2/router' -import {useDarkModeState} from '@/constants/darkmode' +import {useDarkModeState} from '@/stores/darkmode' import ResetModal from '../login/reset/modal' import GlobalError from './global-errors' import OutOfDate from './out-of-date' diff --git a/shared/app/out-of-date.tsx b/shared/app/out-of-date.tsx index 3287a86e87d1..d77926f918bc 100644 --- a/shared/app/out-of-date.tsx +++ b/shared/app/out-of-date.tsx @@ -3,7 +3,7 @@ import * as Kb from '@/common-adapters' import * as React from 'react' import * as T from '@/constants/types' import logger from '@/logger' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const styles = Kb.Styles.styleSheetCreate(() => ({ container: { diff --git a/shared/app/runtime-stats.tsx b/shared/app/runtime-stats.tsx index 55e94eee4a96..2ea975b665cc 100644 --- a/shared/app/runtime-stats.tsx +++ b/shared/app/runtime-stats.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const isIPhoneX = false as boolean // import lagRadar from 'lag-radar' diff --git a/shared/chat/audio/audio-recorder.native.tsx b/shared/chat/audio/audio-recorder.native.tsx index b68e7f68ade6..8c3a2d197c98 100644 --- a/shared/chat/audio/audio-recorder.native.tsx +++ b/shared/chat/audio/audio-recorder.native.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {Portal} from '@/common-adapters/portal.native' diff --git a/shared/chat/blocking/block-modal.tsx b/shared/chat/blocking/block-modal.tsx index e0c695937385..0a9dfdd64d03 100644 --- a/shared/chat/blocking/block-modal.tsx +++ b/shared/chat/blocking/block-modal.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' -import * as Chat from '@/constants/chat2' -import {useTeamsState} from '@/constants/teams' -import {useUsersState} from '@/constants/users' +import * as Chat from '@/stores/chat2' +import {useTeamsState} from '@/stores/teams' +import {useUsersState} from '@/stores/users' // Type for extra RouteProp passed to block modal sometimes when launching the // modal from specific places from the app. diff --git a/shared/chat/blocking/invitation-to-block.tsx b/shared/chat/blocking/invitation-to-block.tsx index e7ba0b2f0950..9e124e37d688 100644 --- a/shared/chat/blocking/invitation-to-block.tsx +++ b/shared/chat/blocking/invitation-to-block.tsx @@ -1,8 +1,8 @@ -import * as Chat from '@/constants/chat2' -import {useProfileState} from '@/constants/profile' +import * as Chat from '@/stores/chat2' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' import {useSafeNavigation} from '@/util/safe-navigation' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' const BlockButtons = () => { const nav = useSafeNavigation() diff --git a/shared/chat/chat-button.tsx b/shared/chat/chat-button.tsx index 1524bf4e37a2..d565cffd15b4 100644 --- a/shared/chat/chat-button.tsx +++ b/shared/chat/chat-button.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Styles from '@/styles' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import WaitingButton from '@/common-adapters/waiting-button' import Icon from '@/common-adapters/icon' diff --git a/shared/chat/conversation/attachment-fullscreen/hooks.tsx b/shared/chat/conversation/attachment-fullscreen/hooks.tsx index 584d3cdeacc9..cd16b218c638 100644 --- a/shared/chat/conversation/attachment-fullscreen/hooks.tsx +++ b/shared/chat/conversation/attachment-fullscreen/hooks.tsx @@ -1,9 +1,9 @@ import * as React from 'react' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import type * as T from '@/constants/types' import {maxWidth, maxHeight} from '../messages/attachment/shared' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' const blankMessage = Chat.makeMessageAttachment({}) export const useData = (initialOrdinal: T.Chat.Ordinal) => { diff --git a/shared/chat/conversation/attachment-get-titles.tsx b/shared/chat/conversation/attachment-get-titles.tsx index 317df4f73246..ee2da9c58036 100644 --- a/shared/chat/conversation/attachment-get-titles.tsx +++ b/shared/chat/conversation/attachment-get-titles.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/bot/confirm.tsx b/shared/chat/conversation/bot/confirm.tsx index 4f0c8230ebbc..6d7c001fb176 100644 --- a/shared/chat/conversation/bot/confirm.tsx +++ b/shared/chat/conversation/bot/confirm.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import type * as T from '@/constants/types' import {useBotConversationIDKey} from './install' diff --git a/shared/chat/conversation/bot/install.tsx b/shared/chat/conversation/bot/install.tsx index c1e24c343beb..88c1f3a90369 100644 --- a/shared/chat/conversation/bot/install.tsx +++ b/shared/chat/conversation/bot/install.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import ChannelPicker from './channel-picker' import openURL from '@/util/open-url' import * as T from '@/constants/types' -import {useBotsState} from '@/constants/bots' +import {useBotsState} from '@/stores/bots' import {useAllChannelMetas} from '@/teams/common/channel-hooks' const RestrictedItem = '---RESTRICTED---' diff --git a/shared/chat/conversation/bot/search.tsx b/shared/chat/conversation/bot/search.tsx index 3a3dd2ab36f3..ec1309ad25f6 100644 --- a/shared/chat/conversation/bot/search.tsx +++ b/shared/chat/conversation/bot/search.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import debounce from 'lodash/debounce' import type * as T from '@/constants/types' import {Bot} from '../info-panel/bot' -import {getFeaturedSorted, useBotsState} from '@/constants/bots' +import {getFeaturedSorted, useBotsState} from '@/stores/bots' type Props = {teamID?: T.Teams.TeamID} diff --git a/shared/chat/conversation/bot/team-picker.tsx b/shared/chat/conversation/bot/team-picker.tsx index 23c869eeff54..b62b38be91c9 100644 --- a/shared/chat/conversation/bot/team-picker.tsx +++ b/shared/chat/conversation/bot/team-picker.tsx @@ -5,7 +5,7 @@ import * as T from '@/constants/types' import {Avatars, TeamAvatar} from '@/chat/avatars' import debounce from 'lodash/debounce' import logger from '@/logger' -import {useBotsState} from '@/constants/bots' +import {useBotsState} from '@/stores/bots' type Props = {botUsername: string} diff --git a/shared/chat/conversation/bottom-banner.tsx b/shared/chat/conversation/bottom-banner.tsx index 3b845cd09e92..6d5fa9af7d4e 100644 --- a/shared/chat/conversation/bottom-banner.tsx +++ b/shared/chat/conversation/bottom-banner.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import _openSMS from '@/util/sms' import {assertionToDisplay} from '@/common-adapters/usernames' import type {Props as TextProps} from '@/common-adapters/text' -import {useUsersState} from '@/constants/users' -import {useFollowerState} from '@/constants/followers' +import {useUsersState} from '@/stores/users' +import {useFollowerState} from '@/stores/followers' const installMessage = `I sent you encrypted messages on Keybase. You can install it here: https://keybase.io/phone-app` diff --git a/shared/chat/conversation/command-markdown.tsx b/shared/chat/conversation/command-markdown.tsx index 1f434bc4d280..10c20f1c5509 100644 --- a/shared/chat/conversation/command-markdown.tsx +++ b/shared/chat/conversation/command-markdown.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' const CommandMarkdown = () => { diff --git a/shared/chat/conversation/command-status.tsx b/shared/chat/conversation/command-status.tsx index 9a005c52a13c..d27ab60a9bf3 100644 --- a/shared/chat/conversation/command-status.tsx +++ b/shared/chat/conversation/command-status.tsx @@ -1,7 +1,7 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const empty = { actions: [], diff --git a/shared/chat/conversation/container.tsx b/shared/chat/conversation/container.tsx index 0cb2f2d21908..d892d3f39949 100644 --- a/shared/chat/conversation/container.tsx +++ b/shared/chat/conversation/container.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import Normal from './normal/container' import NoConversation from './no-conversation' import Error from './error' diff --git a/shared/chat/conversation/error.tsx b/shared/chat/conversation/error.tsx index c4762dc4f87a..0c9266bb235c 100644 --- a/shared/chat/conversation/error.tsx +++ b/shared/chat/conversation/error.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' const ConversationError = () => { diff --git a/shared/chat/conversation/fwd-msg.tsx b/shared/chat/conversation/fwd-msg.tsx index 53ec16deb001..265d9e69c756 100644 --- a/shared/chat/conversation/fwd-msg.tsx +++ b/shared/chat/conversation/fwd-msg.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' diff --git a/shared/chat/conversation/giphy/hooks.tsx b/shared/chat/conversation/giphy/hooks.tsx index bad968dd56aa..b2aea6c79b09 100644 --- a/shared/chat/conversation/giphy/hooks.tsx +++ b/shared/chat/conversation/giphy/hooks.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' export const useHooks = () => { const giphy = Chat.useChatContext(s => s.giphyResult) diff --git a/shared/chat/conversation/header-area/index.native.tsx b/shared/chat/conversation/header-area/index.native.tsx index c2b82732a4aa..ceaaff316fdd 100644 --- a/shared/chat/conversation/header-area/index.native.tsx +++ b/shared/chat/conversation/header-area/index.native.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useProfileState} from '@/constants/profile' +import * as Chat from '@/stores/chat2' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' import * as React from 'react' import type {HeaderBackButtonProps} from '@react-navigation/elements' @@ -9,8 +9,8 @@ import {Keyboard} from 'react-native' // import {DebugChatDumpContext} from '@/constants/chat2/debug' import {assertionToDisplay} from '@/common-adapters/usernames' import {useSafeAreaFrame} from 'react-native-safe-area-context' -import {useUsersState} from '@/constants/users' -import {useCurrentUserState} from '@/constants/current-user' +import {useUsersState} from '@/stores/users' +import {useCurrentUserState} from '@/stores/current-user' export const HeaderAreaRight = () => { const conversationIDKey = Chat.useChatContext(s => s.id) diff --git a/shared/chat/conversation/info-panel/add-people.tsx b/shared/chat/conversation/info-panel/add-people.tsx index 9e7492a91f92..724cd29ec1c1 100644 --- a/shared/chat/conversation/info-panel/add-people.tsx +++ b/shared/chat/conversation/info-panel/add-people.tsx @@ -1,5 +1,5 @@ -import * as Chat from '@/constants/chat2' -import {useTeamsState} from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import {useTeamsState} from '@/stores/teams' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/info-panel/add-to-channel.tsx b/shared/chat/conversation/info-panel/add-to-channel.tsx index 59bfd1d8e9ca..2109aaae2717 100644 --- a/shared/chat/conversation/info-panel/add-to-channel.tsx +++ b/shared/chat/conversation/info-panel/add-to-channel.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import {useSafeNavigation} from '@/util/safe-navigation' import * as T from '@/constants/types' diff --git a/shared/chat/conversation/info-panel/attachments.tsx b/shared/chat/conversation/info-panel/attachments.tsx index 451fa0a9bf98..1deea243bb7d 100644 --- a/shared/chat/conversation/info-panel/attachments.tsx +++ b/shared/chat/conversation/info-panel/attachments.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import type {StylesTextCrossPlatform} from '@/common-adapters/text' import * as T from '@/constants/types' @@ -8,7 +8,7 @@ import chunk from 'lodash/chunk' import {formatAudioRecordDuration, formatTimeForMessages} from '@/util/timestamp' import {infoPanelWidth} from './common' import {useMessagePopup} from '../messages/message-popup' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' type Props = { commonSections: ReadonlyArray
diff --git a/shared/chat/conversation/info-panel/bot.tsx b/shared/chat/conversation/info-panel/bot.tsx index 9acfef03a51a..1152170c6d5d 100644 --- a/shared/chat/conversation/info-panel/bot.tsx +++ b/shared/chat/conversation/info-panel/bot.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import * as Teams from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as React from 'react' import type * as T from '@/constants/types' -import {getFeaturedSorted, useBotsState} from '@/constants/bots' -import {useUsersState} from '@/constants/users' +import {getFeaturedSorted, useBotsState} from '@/stores/bots' +import {useUsersState} from '@/stores/users' type AddToChannelProps = { conversationIDKey: T.Chat.ConversationIDKey diff --git a/shared/chat/conversation/info-panel/common.tsx b/shared/chat/conversation/info-panel/common.tsx index 1de1bb893716..d01c196b8579 100644 --- a/shared/chat/conversation/info-panel/common.tsx +++ b/shared/chat/conversation/info-panel/common.tsx @@ -1,5 +1,5 @@ -import type * as Chat from '@/constants/chat2' -import {useTeamsState} from '@/constants/teams' +import type * as Chat from '@/stores/chat2' +import {useTeamsState} from '@/stores/teams' import * as React from 'react' import * as Styles from '@/styles' import type * as T from '@/constants/types' diff --git a/shared/chat/conversation/info-panel/header.tsx b/shared/chat/conversation/info-panel/header.tsx index 121f86d02404..6d45cc0ca533 100644 --- a/shared/chat/conversation/info-panel/header.tsx +++ b/shared/chat/conversation/info-panel/header.tsx @@ -1,6 +1,6 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import InfoPanelMenu from './menu' import * as InfoPanelCommon from './common' diff --git a/shared/chat/conversation/info-panel/index.tsx b/shared/chat/conversation/info-panel/index.tsx index f2bcd79a3346..0bf1adf3fad2 100644 --- a/shared/chat/conversation/info-panel/index.tsx +++ b/shared/chat/conversation/info-panel/index.tsx @@ -1,6 +1,6 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import {AdhocHeader, TeamHeader} from './header' import SettingsList from './settings' diff --git a/shared/chat/conversation/info-panel/members.tsx b/shared/chat/conversation/info-panel/members.tsx index 5c1242ee02d7..72b3a4405985 100644 --- a/shared/chat/conversation/info-panel/members.tsx +++ b/shared/chat/conversation/info-panel/members.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useProfileState} from '@/constants/profile' -import * as Teams from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import {useProfileState} from '@/stores/profile' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import Participant from './participant' -import {useUsersState} from '@/constants/users' +import {useUsersState} from '@/stores/users' type Props = { commonSections: ReadonlyArray
diff --git a/shared/chat/conversation/info-panel/menu.tsx b/shared/chat/conversation/info-panel/menu.tsx index eac5285c62f0..0d1bd8e20c50 100644 --- a/shared/chat/conversation/info-panel/menu.tsx +++ b/shared/chat/conversation/info-panel/menu.tsx @@ -1,14 +1,14 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as T from '@/constants/types' import * as InfoPanelCommon from './common' import {Avatars, TeamAvatar} from '@/chat/avatars' import {TeamsSubscriberMountOnly} from '@/teams/subscriber' -import {useUsersState} from '@/constants/users' -import {useCurrentUserState} from '@/constants/current-user' +import {useUsersState} from '@/stores/users' +import {useCurrentUserState} from '@/stores/current-user' export type OwnProps = { attachTo?: React.RefObject diff --git a/shared/chat/conversation/info-panel/settings/index.tsx b/shared/chat/conversation/info-panel/settings/index.tsx index 6535768ef672..7656d2a941d9 100644 --- a/shared/chat/conversation/info-panel/settings/index.tsx +++ b/shared/chat/conversation/info-panel/settings/index.tsx @@ -1,13 +1,13 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as T from '@/constants/types' import * as React from 'react' import MinWriterRole from './min-writer-role' import Notifications from './notifications' import RetentionPicker from '@/teams/team/settings-tab/retention' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type EntityType = 'adhoc' | 'small team' | 'channel' type SettingsPanelProps = {isPreview: boolean} diff --git a/shared/chat/conversation/info-panel/settings/min-writer-role.tsx b/shared/chat/conversation/info-panel/settings/min-writer-role.tsx index a25934607682..56c8a09e4566 100644 --- a/shared/chat/conversation/info-panel/settings/min-writer-role.tsx +++ b/shared/chat/conversation/info-panel/settings/min-writer-role.tsx @@ -1,6 +1,6 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as Style from '@/styles' import type * as T from '@/constants/types' diff --git a/shared/chat/conversation/info-panel/settings/notifications.tsx b/shared/chat/conversation/info-panel/settings/notifications.tsx index 53bbf518206f..fdfcb3a0bc94 100644 --- a/shared/chat/conversation/info-panel/settings/notifications.tsx +++ b/shared/chat/conversation/info-panel/settings/notifications.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' diff --git a/shared/chat/conversation/input-area/container.tsx b/shared/chat/conversation/input-area/container.tsx index 7ce09e75c96b..e318566ef103 100644 --- a/shared/chat/conversation/input-area/container.tsx +++ b/shared/chat/conversation/input-area/container.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import Normal from './normal2' import Preview from './preview' import ThreadSearch from '../search' diff --git a/shared/chat/conversation/input-area/location-popup.native.tsx b/shared/chat/conversation/input-area/location-popup.native.tsx index 1225ddfcd0eb..1df813f11cf2 100644 --- a/shared/chat/conversation/input-area/location-popup.native.tsx +++ b/shared/chat/conversation/input-area/location-popup.native.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import logger from '@/logger' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import LocationMap from '@/chat/location-map' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' import {requestLocationPermission} from '@/constants/platform-specific' import * as ExpoLocation from 'expo-location' diff --git a/shared/chat/conversation/input-area/normal2/index.tsx b/shared/chat/conversation/input-area/normal2/index.tsx index 8ceea809bb21..248c3e9db0bd 100644 --- a/shared/chat/conversation/input-area/normal2/index.tsx +++ b/shared/chat/conversation/input-area/normal2/index.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import CommandMarkdown from '../../command-markdown' @@ -13,7 +13,7 @@ import {infoPanelWidthTablet} from '../../info-panel/common' import {assertionToDisplay} from '@/common-adapters/usernames' import {FocusContext, ScrollContext} from '@/chat/conversation/normal/context' import type {RefType as Input2Ref} from '@/common-adapters/input2' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' const useHintText = (p: { isExploding: boolean diff --git a/shared/chat/conversation/input-area/normal2/moremenu-popup.native.tsx b/shared/chat/conversation/input-area/normal2/moremenu-popup.native.tsx index fc790cc73f5a..e75a2301b57f 100644 --- a/shared/chat/conversation/input-area/normal2/moremenu-popup.native.tsx +++ b/shared/chat/conversation/input-area/normal2/moremenu-popup.native.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' type Props = { diff --git a/shared/chat/conversation/input-area/normal2/platform-input.desktop.tsx b/shared/chat/conversation/input-area/normal2/platform-input.desktop.tsx index d56a9ef8bba8..5533d8515bec 100644 --- a/shared/chat/conversation/input-area/normal2/platform-input.desktop.tsx +++ b/shared/chat/conversation/input-area/normal2/platform-input.desktop.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import * as React from 'react' diff --git a/shared/chat/conversation/input-area/normal2/platform-input.native.tsx b/shared/chat/conversation/input-area/normal2/platform-input.native.tsx index 134412c3846e..496f7ebb8c5a 100644 --- a/shared/chat/conversation/input-area/normal2/platform-input.native.tsx +++ b/shared/chat/conversation/input-area/normal2/platform-input.native.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import AudioRecorder from '@/chat/audio/audio-recorder.native' @@ -28,7 +28,7 @@ import logger from '@/logger' import {AudioSendWrapper} from '@/chat/audio/audio-send.native' import {usePickerState} from '@/chat/emoji-picker/use-picker' import type {RefType as Input2Ref, Props as Input2Props} from '@/common-adapters/input2' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const singleLineHeight = 36 const threeLineHeight = 78 diff --git a/shared/chat/conversation/input-area/normal2/set-explode-popup/hooks.tsx b/shared/chat/conversation/input-area/normal2/set-explode-popup/hooks.tsx index 1552f0f23d43..64ae5aca987a 100644 --- a/shared/chat/conversation/input-area/normal2/set-explode-popup/hooks.tsx +++ b/shared/chat/conversation/input-area/normal2/set-explode-popup/hooks.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import type * as T from '@/constants/types' import type {Props} from '.' diff --git a/shared/chat/conversation/input-area/normal2/typing.tsx b/shared/chat/conversation/input-area/normal2/typing.tsx index b9a42ecff2ee..c274f4396aae 100644 --- a/shared/chat/conversation/input-area/normal2/typing.tsx +++ b/shared/chat/conversation/input-area/normal2/typing.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/input-area/preview.tsx b/shared/chat/conversation/input-area/preview.tsx index 3f118f4469ac..64e25419c5f8 100644 --- a/shared/chat/conversation/input-area/preview.tsx +++ b/shared/chat/conversation/input-area/preview.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/input-area/suggestors/channels.tsx b/shared/chat/conversation/input-area/suggestors/channels.tsx index 0fcf0b2bb3ba..4e0bc22ec650 100644 --- a/shared/chat/conversation/input-area/suggestors/channels.tsx +++ b/shared/chat/conversation/input-area/suggestors/channels.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Common from './common' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/input-area/suggestors/commands.tsx b/shared/chat/conversation/input-area/suggestors/commands.tsx index 80f9f7753c81..4cfa2041c692 100644 --- a/shared/chat/conversation/input-area/suggestors/commands.tsx +++ b/shared/chat/conversation/input-area/suggestors/commands.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import * as Common from './common' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/input-area/suggestors/emoji.tsx b/shared/chat/conversation/input-area/suggestors/emoji.tsx index 2af8b5366e0e..df285c3eb4d2 100644 --- a/shared/chat/conversation/input-area/suggestors/emoji.tsx +++ b/shared/chat/conversation/input-area/suggestors/emoji.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Common from './common' import * as Kb from '@/common-adapters' import * as React from 'react' diff --git a/shared/chat/conversation/input-area/suggestors/index.tsx b/shared/chat/conversation/input-area/suggestors/index.tsx index d82cd92e2019..a075d4262c9c 100644 --- a/shared/chat/conversation/input-area/suggestors/index.tsx +++ b/shared/chat/conversation/input-area/suggestors/index.tsx @@ -1,5 +1,5 @@ import * as Channels from './channels' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Commands from './commands' import * as Emoji from './emoji' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/input-area/suggestors/users.tsx b/shared/chat/conversation/input-area/suggestors/users.tsx index 841ea76922fd..f951b0e3536a 100644 --- a/shared/chat/conversation/input-area/suggestors/users.tsx +++ b/shared/chat/conversation/input-area/suggestors/users.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useTeamsState} from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import {useTeamsState} from '@/stores/teams' import * as T from '@/constants/types' import * as Common from './common' import * as Kb from '@/common-adapters' import * as React from 'react' -import {useUsersState} from '@/constants/users' +import {useUsersState} from '@/stores/users' export const transformer = ( input: { diff --git a/shared/chat/conversation/list-area/hooks.tsx b/shared/chat/conversation/list-area/hooks.tsx index 6208ee8417e4..0570ca7ed8fd 100644 --- a/shared/chat/conversation/list-area/hooks.tsx +++ b/shared/chat/conversation/list-area/hooks.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import JumpToRecent from './jump-to-recent' import type * as T from '@/constants/types' diff --git a/shared/chat/conversation/list-area/index.desktop.tsx b/shared/chat/conversation/list-area/index.desktop.tsx index f26f84b9ca4d..2dd8fc5f700a 100644 --- a/shared/chat/conversation/list-area/index.desktop.tsx +++ b/shared/chat/conversation/list-area/index.desktop.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as Hooks from './hooks' import * as React from 'react' @@ -17,7 +17,7 @@ import logger from '@/logger' import shallowEqual from 'shallowequal' import useResizeObserver from '@/util/use-resize-observer.desktop' import useIntersectionObserver from '@/util/use-intersection-observer' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' // Infinite scrolling list. // We group messages into a series of Waypoints. When the waypoint exits the screen we replace it with a single div instead diff --git a/shared/chat/conversation/list-area/index.native.tsx b/shared/chat/conversation/list-area/index.native.tsx index 8cfc247601a6..099c5b69734e 100644 --- a/shared/chat/conversation/list-area/index.native.tsx +++ b/shared/chat/conversation/list-area/index.native.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import * as Hooks from './hooks' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/load-status.tsx b/shared/chat/conversation/load-status.tsx index e992dd920145..786061c50ab9 100644 --- a/shared/chat/conversation/load-status.tsx +++ b/shared/chat/conversation/load-status.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' diff --git a/shared/chat/conversation/messages/account-payment/container.tsx b/shared/chat/conversation/messages/account-payment/container.tsx index 7aec89fb2655..e728ab2606eb 100644 --- a/shared/chat/conversation/messages/account-payment/container.tsx +++ b/shared/chat/conversation/messages/account-payment/container.tsx @@ -1,8 +1,8 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import MarkdownMemo from '@/wallets/markdown-memo' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' // Props for rendering the loading indicator const loadingProps = { diff --git a/shared/chat/conversation/messages/account-payment/wrapper.tsx b/shared/chat/conversation/messages/account-payment/wrapper.tsx index 7e2bd8bf7b79..619ed8222849 100644 --- a/shared/chat/conversation/messages/account-payment/wrapper.tsx +++ b/shared/chat/conversation/messages/account-payment/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type PaymentMessageType from './container' diff --git a/shared/chat/conversation/messages/attachment/audio.tsx b/shared/chat/conversation/messages/attachment/audio.tsx index eb299725bc45..1de12a908a91 100644 --- a/shared/chat/conversation/messages/attachment/audio.tsx +++ b/shared/chat/conversation/messages/attachment/audio.tsx @@ -1,9 +1,9 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {useOrdinal} from '../ids-context' import AudioPlayer from '@/chat/audio/audio-player' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' const missingMessage = Chat.makeMessageAttachment() diff --git a/shared/chat/conversation/messages/attachment/file.tsx b/shared/chat/conversation/messages/attachment/file.tsx index 948f66f32a0d..9ec116c82f1c 100644 --- a/shared/chat/conversation/messages/attachment/file.tsx +++ b/shared/chat/conversation/messages/attachment/file.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import * as Crypto from '@/constants/crypto' +import * as Chat from '@/stores/chat2' +import * as Crypto from '@/stores/crypto' import * as React from 'react' import {isPathSaltpack, isPathSaltpackEncrypted, isPathSaltpackSigned} from '@/util/path' import type * as T from '@/constants/types' @@ -9,7 +9,7 @@ import captialize from 'lodash/capitalize' import * as Kb from '@/common-adapters' import type {StyleOverride} from '@/common-adapters/markdown' import {getEditStyle, ShowToastAfterSaving} from './shared' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' type OwnProps = {showPopup: () => void} diff --git a/shared/chat/conversation/messages/attachment/image2/use-state.tsx b/shared/chat/conversation/messages/attachment/image2/use-state.tsx index da4c4093b538..2399086be164 100644 --- a/shared/chat/conversation/messages/attachment/image2/use-state.tsx +++ b/shared/chat/conversation/messages/attachment/image2/use-state.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import {useOrdinal} from '@/chat/conversation/messages/ids-context' import {maxWidth, maxHeight} from '../shared' diff --git a/shared/chat/conversation/messages/attachment/shared.tsx b/shared/chat/conversation/messages/attachment/shared.tsx index 379a85ae8374..d0937dde1167 100644 --- a/shared/chat/conversation/messages/attachment/shared.tsx +++ b/shared/chat/conversation/messages/attachment/shared.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import * as T from '@/constants/types' import {useOrdinal} from '../ids-context' import {sharedStyles} from '../shared-styles' import {Keyboard} from 'react-native' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' type Props = { transferState: T.Chat.MessageAttachmentTransferState diff --git a/shared/chat/conversation/messages/attachment/video/use-state.tsx b/shared/chat/conversation/messages/attachment/video/use-state.tsx index b02adc6d8a21..5fc3c9eaa684 100644 --- a/shared/chat/conversation/messages/attachment/video/use-state.tsx +++ b/shared/chat/conversation/messages/attachment/video/use-state.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import {useOrdinal} from '@/chat/conversation/messages/ids-context' import {missingMessage, maxWidth, maxHeight} from '../shared' diff --git a/shared/chat/conversation/messages/cards/make-team.tsx b/shared/chat/conversation/messages/cards/make-team.tsx index ce3ca6ea16b3..d01d46e8e954 100644 --- a/shared/chat/conversation/messages/cards/make-team.tsx +++ b/shared/chat/conversation/messages/cards/make-team.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' const MakeTeam = () => { diff --git a/shared/chat/conversation/messages/cards/team-journey/container.tsx b/shared/chat/conversation/messages/cards/team-journey/container.tsx index 249383bf41a7..19d47a2be434 100644 --- a/shared/chat/conversation/messages/cards/team-journey/container.tsx +++ b/shared/chat/conversation/messages/cards/team-journey/container.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import {renderWelcomeMessage} from './util' import {useAllChannelMetas} from '@/teams/common/channel-hooks' diff --git a/shared/chat/conversation/messages/emoji-row.tsx b/shared/chat/conversation/messages/emoji-row.tsx index 43e13a7f324c..ffbb461d8082 100644 --- a/shared/chat/conversation/messages/emoji-row.tsx +++ b/shared/chat/conversation/messages/emoji-row.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {useOrdinal} from './ids-context' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/messages/message-popup/attachment.tsx b/shared/chat/conversation/messages/message-popup/attachment.tsx index 0cf6fdb9efb9..19227db84c07 100644 --- a/shared/chat/conversation/messages/message-popup/attachment.tsx +++ b/shared/chat/conversation/messages/message-popup/attachment.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import type * as T from '@/constants/types' import {type Position, fileUIName, type StylesCrossPlatform} from '@/styles' import {useItems, useHeader} from './hooks' import * as Kb from '@/common-adapters' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' type OwnProps = { attachTo?: React.RefObject diff --git a/shared/chat/conversation/messages/message-popup/exploding-header.tsx b/shared/chat/conversation/messages/message-popup/exploding-header.tsx index e390b96f7879..7d691f4b30b8 100644 --- a/shared/chat/conversation/messages/message-popup/exploding-header.tsx +++ b/shared/chat/conversation/messages/message-popup/exploding-header.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' import {formatTimeForPopup, formatTimeForRevoked, msToDHMS} from '@/util/timestamp' import {addTicker, removeTicker} from '@/util/second-timer' diff --git a/shared/chat/conversation/messages/message-popup/header.tsx b/shared/chat/conversation/messages/message-popup/header.tsx index d0221144273a..d57e76ad84f5 100644 --- a/shared/chat/conversation/messages/message-popup/header.tsx +++ b/shared/chat/conversation/messages/message-popup/header.tsx @@ -1,6 +1,6 @@ import * as Kb from '@/common-adapters' import * as React from 'react' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import {formatTimeForPopup, formatTimeForRevoked} from '@/util/timestamp' import type * as T from '@/constants/types' diff --git a/shared/chat/conversation/messages/message-popup/hooks.tsx b/shared/chat/conversation/messages/message-popup/hooks.tsx index 6a8a35db164b..5a55ddf164ab 100644 --- a/shared/chat/conversation/messages/message-popup/hooks.tsx +++ b/shared/chat/conversation/messages/message-popup/hooks.tsx @@ -1,11 +1,11 @@ import * as React from 'react' import type * as T from '@/constants/types' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import * as Teams from '@/constants/teams' -import {useConfigState} from '@/constants/config' -import {useProfileState} from '@/constants/profile' -import {useCurrentUserState} from '@/constants/current-user' +import * as Chat from '@/stores/chat2' +import * as Teams from '@/stores/teams' +import {useConfigState} from '@/stores/config' +import {useProfileState} from '@/stores/profile' +import {useCurrentUserState} from '@/stores/current-user' import {linkFromConvAndMessage} from '@/constants/deeplinks' import ReactionItem from './reactionitem' import MessagePopupHeader from './header' diff --git a/shared/chat/conversation/messages/message-popup/index.tsx b/shared/chat/conversation/messages/message-popup/index.tsx index 111c936d3678..3736bfdc3587 100644 --- a/shared/chat/conversation/messages/message-popup/index.tsx +++ b/shared/chat/conversation/messages/message-popup/index.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import AttachmentMessage from './attachment' diff --git a/shared/chat/conversation/messages/message-popup/journeycard.tsx b/shared/chat/conversation/messages/message-popup/journeycard.tsx index 560590fd8ce3..f631f84246f6 100644 --- a/shared/chat/conversation/messages/message-popup/journeycard.tsx +++ b/shared/chat/conversation/messages/message-popup/journeycard.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import * as React from 'react' diff --git a/shared/chat/conversation/messages/message-popup/reactionitem.tsx b/shared/chat/conversation/messages/message-popup/reactionitem.tsx index 051dce87b10c..9c734e3f529c 100644 --- a/shared/chat/conversation/messages/message-popup/reactionitem.tsx +++ b/shared/chat/conversation/messages/message-popup/reactionitem.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' type Props = { diff --git a/shared/chat/conversation/messages/message-popup/text.tsx b/shared/chat/conversation/messages/message-popup/text.tsx index 3a8c7f28077d..ac05c2730cce 100644 --- a/shared/chat/conversation/messages/message-popup/text.tsx +++ b/shared/chat/conversation/messages/message-popup/text.tsx @@ -1,13 +1,13 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useConfigState} from '@/constants/config' +import * as Chat from '@/stores/chat2' +import {useConfigState} from '@/stores/config' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import type {Position, StylesCrossPlatform} from '@/styles' import {useItems, useHeader} from './hooks' import openURL from '@/util/open-url' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = { attachTo?: React.RefObject diff --git a/shared/chat/conversation/messages/pin/index.tsx b/shared/chat/conversation/messages/pin/index.tsx index 937d4cb6fb2c..7618510b7557 100644 --- a/shared/chat/conversation/messages/pin/index.tsx +++ b/shared/chat/conversation/messages/pin/index.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' diff --git a/shared/chat/conversation/messages/pin/wrapper.tsx b/shared/chat/conversation/messages/pin/wrapper.tsx index 5cfd3cb7c7f2..67125e1e8575 100644 --- a/shared/chat/conversation/messages/pin/wrapper.tsx +++ b/shared/chat/conversation/messages/pin/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type PinType from '.' diff --git a/shared/chat/conversation/messages/placeholder/wrapper.tsx b/shared/chat/conversation/messages/placeholder/wrapper.tsx index 5cc050f9d681..45c196e3be7a 100644 --- a/shared/chat/conversation/messages/placeholder/wrapper.tsx +++ b/shared/chat/conversation/messages/placeholder/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import * as T from '@/constants/types' diff --git a/shared/chat/conversation/messages/react-button.tsx b/shared/chat/conversation/messages/react-button.tsx index 4d9e009c7c5f..289f1870748c 100644 --- a/shared/chat/conversation/messages/react-button.tsx +++ b/shared/chat/conversation/messages/react-button.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import type {StylesCrossPlatform} from '@/styles' import {useOrdinal} from './ids-context' @@ -7,7 +7,7 @@ import * as Kb from '@/common-adapters' import type {StyleOverride} from '@/common-adapters/markdown' import {colors, darkColors} from '@/styles/colors' import {useColorScheme} from 'react-native' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' export type OwnProps = { className?: string diff --git a/shared/chat/conversation/messages/reaction-tooltip.tsx b/shared/chat/conversation/messages/reaction-tooltip.tsx index 985f3edacb4f..d196fa1180f1 100644 --- a/shared/chat/conversation/messages/reaction-tooltip.tsx +++ b/shared/chat/conversation/messages/reaction-tooltip.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import ReactButton from './react-button' import type * as T from '@/constants/types' import {MessageContext} from './ids-context' -import {useUsersState} from '@/constants/users' +import {useUsersState} from '@/stores/users' const positionFallbacks = ['bottom center', 'left center'] as const diff --git a/shared/chat/conversation/messages/reactions-rows.tsx b/shared/chat/conversation/messages/reactions-rows.tsx index cde5d850f470..21d1eef42325 100644 --- a/shared/chat/conversation/messages/reactions-rows.tsx +++ b/shared/chat/conversation/messages/reactions-rows.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import EmojiRow from './emoji-row' diff --git a/shared/chat/conversation/messages/reset-user.tsx b/shared/chat/conversation/messages/reset-user.tsx index 08ae473cf8ff..5ef6bde4ba85 100644 --- a/shared/chat/conversation/messages/reset-user.tsx +++ b/shared/chat/conversation/messages/reset-user.tsx @@ -1,5 +1,5 @@ -import * as Chat from '@/constants/chat2' -import {useProfileState} from '@/constants/profile' +import * as Chat from '@/stores/chat2' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' const ResetUser = () => { diff --git a/shared/chat/conversation/messages/retention-notice.tsx b/shared/chat/conversation/messages/retention-notice.tsx index add6faf305ea..77327c4f58ed 100644 --- a/shared/chat/conversation/messages/retention-notice.tsx +++ b/shared/chat/conversation/messages/retention-notice.tsx @@ -1,6 +1,6 @@ import type * as T from '@/constants/types' -import * as Chat from '@/constants/chat2' -import * as Teams from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as React from 'react' diff --git a/shared/chat/conversation/messages/separator.tsx b/shared/chat/conversation/messages/separator.tsx index d2a640007553..877beff3ad3a 100644 --- a/shared/chat/conversation/messages/separator.tsx +++ b/shared/chat/conversation/messages/separator.tsx @@ -1,15 +1,15 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useTeamsState} from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import * as React from 'react' import * as T from '@/constants/types' import {formatTimeForConversationList, formatTimeForChat} from '@/util/timestamp' import {OrangeLineContext} from '../orange-line-context' import logger from '@/logger' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' +import {useCurrentUserState} from '@/stores/current-user' // import {useChatDebugDump} from '@/constants/chat2/debug' const enoughTimeBetweenMessages = (mtimestamp?: number, ptimestamp?: number): boolean => diff --git a/shared/chat/conversation/messages/set-channelname/wrapper.tsx b/shared/chat/conversation/messages/set-channelname/wrapper.tsx index e3a0c0164c7d..c507ae29e940 100644 --- a/shared/chat/conversation/messages/set-channelname/wrapper.tsx +++ b/shared/chat/conversation/messages/set-channelname/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SetChannelnameType from './container' diff --git a/shared/chat/conversation/messages/set-description/wrapper.tsx b/shared/chat/conversation/messages/set-description/wrapper.tsx index 9f8400a9e58d..0383a7edc43e 100644 --- a/shared/chat/conversation/messages/set-description/wrapper.tsx +++ b/shared/chat/conversation/messages/set-description/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SetDescriptionType from './container' diff --git a/shared/chat/conversation/messages/special-bottom-message.tsx b/shared/chat/conversation/messages/special-bottom-message.tsx index e6e45bf35bee..386a56528d86 100644 --- a/shared/chat/conversation/messages/special-bottom-message.tsx +++ b/shared/chat/conversation/messages/special-bottom-message.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import OldProfileReset from './system-old-profile-reset-notice/container' import ResetUser from './reset-user' diff --git a/shared/chat/conversation/messages/special-top-message.tsx b/shared/chat/conversation/messages/special-top-message.tsx index 40205b7dc910..902b3c7f2bf0 100644 --- a/shared/chat/conversation/messages/special-top-message.tsx +++ b/shared/chat/conversation/messages/special-top-message.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import * as React from 'react' @@ -10,8 +10,8 @@ import NewChatCard from './cards/new-chat' import ProfileResetNotice from './system-profile-reset-notice' import RetentionNotice from './retention-notice' import {usingFlashList} from '../list-area/flashlist-config' -import * as FS from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import * as FS from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' const ErrorMessage = () => { const createConversationError = Chat.useChatState(s => s.createConversationError) diff --git a/shared/chat/conversation/messages/system-added-to-team/container.tsx b/shared/chat/conversation/messages/system-added-to-team/container.tsx index 58c6e70e030f..10999c12dc9f 100644 --- a/shared/chat/conversation/messages/system-added-to-team/container.tsx +++ b/shared/chat/conversation/messages/system-added-to-team/container.tsx @@ -1,12 +1,12 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import UserNotice from '../user-notice' import {getAddedUsernames} from '../system-users-added-to-conv/container' import {indefiniteArticle} from '@/util/string' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {message: T.Chat.MessageSystemAddedToTeam} diff --git a/shared/chat/conversation/messages/system-added-to-team/wrapper.tsx b/shared/chat/conversation/messages/system-added-to-team/wrapper.tsx index f90914a28f97..dcefb1626e38 100644 --- a/shared/chat/conversation/messages/system-added-to-team/wrapper.tsx +++ b/shared/chat/conversation/messages/system-added-to-team/wrapper.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemAddedToTeamType from './container' diff --git a/shared/chat/conversation/messages/system-change-avatar/index.tsx b/shared/chat/conversation/messages/system-change-avatar/index.tsx index bdf0fffdfe4b..8aa32c6b3098 100644 --- a/shared/chat/conversation/messages/system-change-avatar/index.tsx +++ b/shared/chat/conversation/messages/system-change-avatar/index.tsx @@ -1,7 +1,7 @@ import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import UserNotice from '../user-notice' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type Props = { message: T.Chat.MessageSystemChangeAvatar diff --git a/shared/chat/conversation/messages/system-change-avatar/wrapper.tsx b/shared/chat/conversation/messages/system-change-avatar/wrapper.tsx index 172ac0051c55..ed14bda12cb3 100644 --- a/shared/chat/conversation/messages/system-change-avatar/wrapper.tsx +++ b/shared/chat/conversation/messages/system-change-avatar/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemChangeAvatarType from '.' diff --git a/shared/chat/conversation/messages/system-change-retention/container.tsx b/shared/chat/conversation/messages/system-change-retention/container.tsx index c0ad42530fa3..d192ebd93f88 100644 --- a/shared/chat/conversation/messages/system-change-retention/container.tsx +++ b/shared/chat/conversation/messages/system-change-retention/container.tsx @@ -1,11 +1,11 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import UserNotice from '../user-notice' import * as T from '@/constants/types' import * as dateFns from 'date-fns' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {message: T.Chat.MessageSystemChangeRetention} diff --git a/shared/chat/conversation/messages/system-change-retention/wrapper.tsx b/shared/chat/conversation/messages/system-change-retention/wrapper.tsx index 85490ad934a3..8d6d231f78ed 100644 --- a/shared/chat/conversation/messages/system-change-retention/wrapper.tsx +++ b/shared/chat/conversation/messages/system-change-retention/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemChangeRetentionType from './container' diff --git a/shared/chat/conversation/messages/system-create-team/container.tsx b/shared/chat/conversation/messages/system-create-team/container.tsx index f248de32f0f6..b3c654e66d2f 100644 --- a/shared/chat/conversation/messages/system-create-team/container.tsx +++ b/shared/chat/conversation/messages/system-create-team/container.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import UserNotice from '../user-notice' import type * as T from '@/constants/types' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {message: T.Chat.MessageSystemCreateTeam} diff --git a/shared/chat/conversation/messages/system-create-team/wrapper.tsx b/shared/chat/conversation/messages/system-create-team/wrapper.tsx index 4d4cd246197a..2a9216ababec 100644 --- a/shared/chat/conversation/messages/system-create-team/wrapper.tsx +++ b/shared/chat/conversation/messages/system-create-team/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemCreateTeamType from './container' diff --git a/shared/chat/conversation/messages/system-git-push/container.tsx b/shared/chat/conversation/messages/system-git-push/container.tsx index 3d8d2c346a98..cd31144d737f 100644 --- a/shared/chat/conversation/messages/system-git-push/container.tsx +++ b/shared/chat/conversation/messages/system-git-push/container.tsx @@ -1,11 +1,11 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' -import {useGitState} from '@/constants/git' +import {useGitState} from '@/stores/git' import UserNotice from '../user-notice' -import * as FS from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import * as FS from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {message: T.Chat.MessageSystemGitPush} diff --git a/shared/chat/conversation/messages/system-git-push/wrapper.tsx b/shared/chat/conversation/messages/system-git-push/wrapper.tsx index aaac3ac464e6..89e05a0090f8 100644 --- a/shared/chat/conversation/messages/system-git-push/wrapper.tsx +++ b/shared/chat/conversation/messages/system-git-push/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemGitPushType from './container' diff --git a/shared/chat/conversation/messages/system-invite-accepted/container.tsx b/shared/chat/conversation/messages/system-invite-accepted/container.tsx index b3b76a752bba..b2d1357a85fd 100644 --- a/shared/chat/conversation/messages/system-invite-accepted/container.tsx +++ b/shared/chat/conversation/messages/system-invite-accepted/container.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import UserNotice from '../user-notice' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {message: T.Chat.MessageSystemInviteAccepted} diff --git a/shared/chat/conversation/messages/system-invite-accepted/wrapper.tsx b/shared/chat/conversation/messages/system-invite-accepted/wrapper.tsx index 118224348648..aeed739b80d4 100644 --- a/shared/chat/conversation/messages/system-invite-accepted/wrapper.tsx +++ b/shared/chat/conversation/messages/system-invite-accepted/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemInviteAcceptedType from './container' diff --git a/shared/chat/conversation/messages/system-joined/container.tsx b/shared/chat/conversation/messages/system-joined/container.tsx index 7ca9df41d333..a9dc7563c9d2 100644 --- a/shared/chat/conversation/messages/system-joined/container.tsx +++ b/shared/chat/conversation/messages/system-joined/container.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/messages/system-joined/wrapper.tsx b/shared/chat/conversation/messages/system-joined/wrapper.tsx index 996f2dc95968..7fe46e21979f 100644 --- a/shared/chat/conversation/messages/system-joined/wrapper.tsx +++ b/shared/chat/conversation/messages/system-joined/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemJoinedType from './container' diff --git a/shared/chat/conversation/messages/system-left/container.tsx b/shared/chat/conversation/messages/system-left/container.tsx index 70ed9a1b3d74..65d0cdf61516 100644 --- a/shared/chat/conversation/messages/system-left/container.tsx +++ b/shared/chat/conversation/messages/system-left/container.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import UserNotice from '../user-notice' diff --git a/shared/chat/conversation/messages/system-left/wrapper.tsx b/shared/chat/conversation/messages/system-left/wrapper.tsx index cf6f97dea1dd..53f8df6c82d2 100644 --- a/shared/chat/conversation/messages/system-left/wrapper.tsx +++ b/shared/chat/conversation/messages/system-left/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemLeftType from './container' diff --git a/shared/chat/conversation/messages/system-new-channel/container.tsx b/shared/chat/conversation/messages/system-new-channel/container.tsx index fb791f2b70b4..f8e1e201837d 100644 --- a/shared/chat/conversation/messages/system-new-channel/container.tsx +++ b/shared/chat/conversation/messages/system-new-channel/container.tsx @@ -1,6 +1,6 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as React from 'react' import type * as T from '@/constants/types' import UserNotice from '../user-notice' diff --git a/shared/chat/conversation/messages/system-new-channel/wrapper.tsx b/shared/chat/conversation/messages/system-new-channel/wrapper.tsx index 27da6aaba425..be12f9f0554f 100644 --- a/shared/chat/conversation/messages/system-new-channel/wrapper.tsx +++ b/shared/chat/conversation/messages/system-new-channel/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemNewChannelType from './container' diff --git a/shared/chat/conversation/messages/system-old-profile-reset-notice/container.tsx b/shared/chat/conversation/messages/system-old-profile-reset-notice/container.tsx index 4044fd8a281b..e306630f87ad 100644 --- a/shared/chat/conversation/messages/system-old-profile-reset-notice/container.tsx +++ b/shared/chat/conversation/messages/system-old-profile-reset-notice/container.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import type * as T from '@/constants/types' import {Text} from '@/common-adapters' import UserNotice from '../user-notice' diff --git a/shared/chat/conversation/messages/system-profile-reset-notice.tsx b/shared/chat/conversation/messages/system-profile-reset-notice.tsx index 2d7deca69d72..0a2677a6140d 100644 --- a/shared/chat/conversation/messages/system-profile-reset-notice.tsx +++ b/shared/chat/conversation/messages/system-profile-reset-notice.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import UserNotice from './user-notice' diff --git a/shared/chat/conversation/messages/system-sbs-resolve/container.tsx b/shared/chat/conversation/messages/system-sbs-resolve/container.tsx index 51da16607892..8346cd4d5a80 100644 --- a/shared/chat/conversation/messages/system-sbs-resolve/container.tsx +++ b/shared/chat/conversation/messages/system-sbs-resolve/container.tsx @@ -2,7 +2,7 @@ import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {e164ToDisplay} from '@/util/phone-numbers' import UserNotice from '../user-notice' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {message: T.Chat.MessageSystemSBSResolved} diff --git a/shared/chat/conversation/messages/system-sbs-resolve/wrapper.tsx b/shared/chat/conversation/messages/system-sbs-resolve/wrapper.tsx index 32db70666c32..bd9d9626c95a 100644 --- a/shared/chat/conversation/messages/system-sbs-resolve/wrapper.tsx +++ b/shared/chat/conversation/messages/system-sbs-resolve/wrapper.tsx @@ -1,9 +1,9 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemSBSResolvedType from './container' import type SystemJoinedType from '../system-joined/container' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' const WrapperSystemInvite = React.memo(function WrapperSystemInvite(p: Props) { const {ordinal} = p diff --git a/shared/chat/conversation/messages/system-simple-to-complex/container.tsx b/shared/chat/conversation/messages/system-simple-to-complex/container.tsx index d0066afafefb..baa73a2f6af5 100644 --- a/shared/chat/conversation/messages/system-simple-to-complex/container.tsx +++ b/shared/chat/conversation/messages/system-simple-to-complex/container.tsx @@ -1,10 +1,10 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import UserNotice from '../user-notice' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {message: T.Chat.MessageSystemSimpleToComplex} diff --git a/shared/chat/conversation/messages/system-simple-to-complex/wrapper.tsx b/shared/chat/conversation/messages/system-simple-to-complex/wrapper.tsx index 93d830470578..d894327e7599 100644 --- a/shared/chat/conversation/messages/system-simple-to-complex/wrapper.tsx +++ b/shared/chat/conversation/messages/system-simple-to-complex/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemSimpleToComplexType from './container' diff --git a/shared/chat/conversation/messages/system-text/wrapper.tsx b/shared/chat/conversation/messages/system-text/wrapper.tsx index 9b99bc02b180..4f2efa4555f6 100644 --- a/shared/chat/conversation/messages/system-text/wrapper.tsx +++ b/shared/chat/conversation/messages/system-text/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemTextType from './container' diff --git a/shared/chat/conversation/messages/system-users-added-to-conv/container.tsx b/shared/chat/conversation/messages/system-users-added-to-conv/container.tsx index 3d67beba56bb..1a9d48e4233d 100644 --- a/shared/chat/conversation/messages/system-users-added-to-conv/container.tsx +++ b/shared/chat/conversation/messages/system-users-added-to-conv/container.tsx @@ -1,9 +1,9 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import UserNotice from '../user-notice' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {message: T.Chat.MessageSystemUsersAddedToConversation} diff --git a/shared/chat/conversation/messages/system-users-added-to-conv/wrapper.tsx b/shared/chat/conversation/messages/system-users-added-to-conv/wrapper.tsx index 5941d8eebbcd..1fe3e0bf1c8b 100644 --- a/shared/chat/conversation/messages/system-users-added-to-conv/wrapper.tsx +++ b/shared/chat/conversation/messages/system-users-added-to-conv/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {WrapperMessage, useCommon, type Props} from '../wrapper/wrapper' import type SystemUsersAddedToConvType from './container' diff --git a/shared/chat/conversation/messages/text/bottom.tsx b/shared/chat/conversation/messages/text/bottom.tsx index 128cc464ef16..e1a26112b6ab 100644 --- a/shared/chat/conversation/messages/text/bottom.tsx +++ b/shared/chat/conversation/messages/text/bottom.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import type * as T from '@/constants/types' import type CoinFlipType from './coinflip' diff --git a/shared/chat/conversation/messages/text/coinflip/index.tsx b/shared/chat/conversation/messages/text/coinflip/index.tsx index 223547f15130..45f53d2d088d 100644 --- a/shared/chat/conversation/messages/text/coinflip/index.tsx +++ b/shared/chat/conversation/messages/text/coinflip/index.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import * as T from '@/constants/types' diff --git a/shared/chat/conversation/messages/text/reply.tsx b/shared/chat/conversation/messages/text/reply.tsx index 7ad7cfacd4f9..bc0d9c745128 100644 --- a/shared/chat/conversation/messages/text/reply.tsx +++ b/shared/chat/conversation/messages/text/reply.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import {useOrdinal, useIsHighlighted} from '../ids-context' diff --git a/shared/chat/conversation/messages/text/unfurl/prompt-list/container.tsx b/shared/chat/conversation/messages/text/unfurl/prompt-list/container.tsx index 240d090eab40..ea0da57b5081 100644 --- a/shared/chat/conversation/messages/text/unfurl/prompt-list/container.tsx +++ b/shared/chat/conversation/messages/text/unfurl/prompt-list/container.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {useOrdinal} from '@/chat/conversation/messages/ids-context' import * as T from '@/constants/types' diff --git a/shared/chat/conversation/messages/text/unfurl/unfurl-list/generic.tsx b/shared/chat/conversation/messages/text/unfurl/unfurl-list/generic.tsx index 444f2452a61e..51105368b6e1 100644 --- a/shared/chat/conversation/messages/text/unfurl/unfurl-list/generic.tsx +++ b/shared/chat/conversation/messages/text/unfurl/unfurl-list/generic.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters/index' import * as T from '@/constants/types' import * as React from 'react' diff --git a/shared/chat/conversation/messages/text/unfurl/unfurl-list/giphy.tsx b/shared/chat/conversation/messages/text/unfurl/unfurl-list/giphy.tsx index 3e97b16ef8fd..238515cda7c3 100644 --- a/shared/chat/conversation/messages/text/unfurl/unfurl-list/giphy.tsx +++ b/shared/chat/conversation/messages/text/unfurl/unfurl-list/giphy.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters/index' import * as React from 'react' import UnfurlImage from './image' diff --git a/shared/chat/conversation/messages/text/unfurl/unfurl-list/image/index.tsx b/shared/chat/conversation/messages/text/unfurl/unfurl-list/image/index.tsx index a826e6dc5e04..e2a3ba2f2c5d 100644 --- a/shared/chat/conversation/messages/text/unfurl/unfurl-list/image/index.tsx +++ b/shared/chat/conversation/messages/text/unfurl/unfurl-list/image/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import * as Kb from '@/common-adapters/index' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import {maxWidth} from '@/chat/conversation/messages/attachment/shared' import {Video} from './video' import openURL from '@/util/open-url' diff --git a/shared/chat/conversation/messages/text/unfurl/unfurl-list/index.tsx b/shared/chat/conversation/messages/text/unfurl/unfurl-list/index.tsx index 1aa89030311a..65c37cb40387 100644 --- a/shared/chat/conversation/messages/text/unfurl/unfurl-list/index.tsx +++ b/shared/chat/conversation/messages/text/unfurl/unfurl-list/index.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import * as React from 'react' import UnfurlGeneric from './generic' diff --git a/shared/chat/conversation/messages/text/unfurl/unfurl-list/map-popup.tsx b/shared/chat/conversation/messages/text/unfurl/unfurl-list/map-popup.tsx index 243034849db6..59e03f3db1c5 100644 --- a/shared/chat/conversation/messages/text/unfurl/unfurl-list/map-popup.tsx +++ b/shared/chat/conversation/messages/text/unfurl/unfurl-list/map-popup.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters/index' import type * as T from '@/constants/types' import openURL from '@/util/open-url' import LocationMap from '@/chat/location-map' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' type Props = { coord: T.Chat.Coordinate diff --git a/shared/chat/conversation/messages/text/unfurl/unfurl-list/map.tsx b/shared/chat/conversation/messages/text/unfurl/unfurl-list/map.tsx index 2cf754f6891e..68ec76e60397 100644 --- a/shared/chat/conversation/messages/text/unfurl/unfurl-list/map.tsx +++ b/shared/chat/conversation/messages/text/unfurl/unfurl-list/map.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters/index' import * as T from '@/constants/types' import * as React from 'react' diff --git a/shared/chat/conversation/messages/text/unfurl/unfurl-list/use-state.tsx b/shared/chat/conversation/messages/text/unfurl/unfurl-list/use-state.tsx index 4a7fddb9d9dd..1092daf24b90 100644 --- a/shared/chat/conversation/messages/text/unfurl/unfurl-list/use-state.tsx +++ b/shared/chat/conversation/messages/text/unfurl/unfurl-list/use-state.tsx @@ -1,7 +1,7 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import type * as T from '@/constants/types' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' export const useActions = (youAreAuthor: boolean, messageID: T.Chat.MessageID, ordinal: T.Chat.Ordinal) => { const unfurlRemove = Chat.useChatContext(s => s.dispatch.unfurlRemove) diff --git a/shared/chat/conversation/messages/text/wrapper.tsx b/shared/chat/conversation/messages/text/wrapper.tsx index d3a6ed554bae..c1b077922b4b 100644 --- a/shared/chat/conversation/messages/text/wrapper.tsx +++ b/shared/chat/conversation/messages/text/wrapper.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import {useReply} from './reply' diff --git a/shared/chat/conversation/messages/wrapper/edited.tsx b/shared/chat/conversation/messages/wrapper/edited.tsx index bc39cbae643b..a3e2d0df2fbe 100644 --- a/shared/chat/conversation/messages/wrapper/edited.tsx +++ b/shared/chat/conversation/messages/wrapper/edited.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import {useIsHighlighted, useOrdinal} from '../ids-context' diff --git a/shared/chat/conversation/messages/wrapper/exploding-height-retainer/container.tsx b/shared/chat/conversation/messages/wrapper/exploding-height-retainer/container.tsx index fae3926d1218..0fc71930593c 100644 --- a/shared/chat/conversation/messages/wrapper/exploding-height-retainer/container.tsx +++ b/shared/chat/conversation/messages/wrapper/exploding-height-retainer/container.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import ExplodingHeightRetainer from '.' import {useOrdinal} from '../../ids-context' diff --git a/shared/chat/conversation/messages/wrapper/exploding-meta.tsx b/shared/chat/conversation/messages/wrapper/exploding-meta.tsx index c6a3a6c1bdde..fa796f6b0354 100644 --- a/shared/chat/conversation/messages/wrapper/exploding-meta.tsx +++ b/shared/chat/conversation/messages/wrapper/exploding-meta.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {useIsHighlighted, useOrdinal} from '../ids-context' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/messages/wrapper/long-pressable/index.native.tsx b/shared/chat/conversation/messages/wrapper/long-pressable/index.native.tsx index f5d163fce1c0..72f39ea87942 100644 --- a/shared/chat/conversation/messages/wrapper/long-pressable/index.native.tsx +++ b/shared/chat/conversation/messages/wrapper/long-pressable/index.native.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import type {Props} from '.' diff --git a/shared/chat/conversation/messages/wrapper/send-indicator.tsx b/shared/chat/conversation/messages/wrapper/send-indicator.tsx index 4f5df715d762..6f197da1ed5a 100644 --- a/shared/chat/conversation/messages/wrapper/send-indicator.tsx +++ b/shared/chat/conversation/messages/wrapper/send-indicator.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import {useOrdinal} from '../ids-context' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/chat/conversation/messages/wrapper/wrapper.tsx b/shared/chat/conversation/messages/wrapper/wrapper.tsx index d1c4186278d0..e4f0a9609e36 100644 --- a/shared/chat/conversation/messages/wrapper/wrapper.tsx +++ b/shared/chat/conversation/messages/wrapper/wrapper.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import {MessageContext, useOrdinal} from '../ids-context' @@ -13,7 +13,7 @@ import SendIndicator from './send-indicator' import * as T from '@/constants/types' import capitalize from 'lodash/capitalize' import {useEdited} from './edited' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' // import {useDebugLayout} from '@/util/debug-react' export type Props = { diff --git a/shared/chat/conversation/normal/container.tsx b/shared/chat/conversation/normal/container.tsx index dbbb9157900a..dc1ee30496aa 100644 --- a/shared/chat/conversation/normal/container.tsx +++ b/shared/chat/conversation/normal/container.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useConfigState} from '@/constants/config' +import * as Chat from '@/stores/chat2' +import {useConfigState} from '@/stores/config' import * as React from 'react' import Normal from '.' import * as T from '@/constants/types' diff --git a/shared/chat/conversation/normal/index.desktop.tsx b/shared/chat/conversation/normal/index.desktop.tsx index 645314cf0f43..2e5dde5320c0 100644 --- a/shared/chat/conversation/normal/index.desktop.tsx +++ b/shared/chat/conversation/normal/index.desktop.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import Banner from '../bottom-banner' diff --git a/shared/chat/conversation/normal/index.native.tsx b/shared/chat/conversation/normal/index.native.tsx index b51457ece826..bfb4263d9019 100644 --- a/shared/chat/conversation/normal/index.native.tsx +++ b/shared/chat/conversation/normal/index.native.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import {PortalHost} from '@/common-adapters/portal.native' import * as Kb from '@/common-adapters' import * as React from 'react' diff --git a/shared/chat/conversation/pinned-message.tsx b/shared/chat/conversation/pinned-message.tsx index c1bee40e5890..9e18af274b21 100644 --- a/shared/chat/conversation/pinned-message.tsx +++ b/shared/chat/conversation/pinned-message.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' const PinnedMessage = React.memo(function PinnedMessage() { const {conversationIDKey, teamname, pinnedMsg, replyJump, onIgnore, pinMessage} = Chat.useChatContext( diff --git a/shared/chat/conversation/rekey/container.tsx b/shared/chat/conversation/rekey/container.tsx index d4397fb0346a..8cc2428b7f7b 100644 --- a/shared/chat/conversation/rekey/container.tsx +++ b/shared/chat/conversation/rekey/container.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useProfileState} from '@/constants/profile' -import {useCurrentUserState} from '@/constants/current-user' +import * as Chat from '@/stores/chat2' +import {useProfileState} from '@/stores/profile' +import {useCurrentUserState} from '@/stores/current-user' import * as T from '@/constants/types' import ParticipantRekey from './participant-rekey' import YouRekey from './you-rekey' diff --git a/shared/chat/conversation/reply-preview.tsx b/shared/chat/conversation/reply-preview.tsx index 4997bad338bd..b194fb2091cb 100644 --- a/shared/chat/conversation/reply-preview.tsx +++ b/shared/chat/conversation/reply-preview.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' diff --git a/shared/chat/conversation/search.tsx b/shared/chat/conversation/search.tsx index 20d9d78fa081..455b96ee6743 100644 --- a/shared/chat/conversation/search.tsx +++ b/shared/chat/conversation/search.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import type * as Styles from '@/styles' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/chat/create-channel/hooks.tsx b/shared/chat/create-channel/hooks.tsx index ec52505df5e5..ae69f3d75443 100644 --- a/shared/chat/create-channel/hooks.tsx +++ b/shared/chat/create-channel/hooks.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import upperFirst from 'lodash/upperFirst' import type {Props} from '.' diff --git a/shared/chat/delete-history-warning.tsx b/shared/chat/delete-history-warning.tsx index 1e748facdc92..47ffafd71431 100644 --- a/shared/chat/delete-history-warning.tsx +++ b/shared/chat/delete-history-warning.tsx @@ -1,6 +1,6 @@ import * as Kb from '@/common-adapters' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import MaybePopup from './maybe-popup' const DeleteHistoryWarning = () => { diff --git a/shared/chat/emoji-picker/container.tsx b/shared/chat/emoji-picker/container.tsx index abe1b741f551..34376fe70b98 100644 --- a/shared/chat/emoji-picker/container.tsx +++ b/shared/chat/emoji-picker/container.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import * as Teams from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' diff --git a/shared/chat/inbox-and-conversation-2.tsx b/shared/chat/inbox-and-conversation-2.tsx index 730766b62d5b..f0a13e01420a 100644 --- a/shared/chat/inbox-and-conversation-2.tsx +++ b/shared/chat/inbox-and-conversation-2.tsx @@ -1,6 +1,6 @@ // Just for desktop and tablet, we show inbox and conversation side by side import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import type * as T from '@/constants/types' diff --git a/shared/chat/inbox-and-conversation-header.tsx b/shared/chat/inbox-and-conversation-header.tsx index 157b61f73d3b..46fba91a82b5 100644 --- a/shared/chat/inbox-and-conversation-header.tsx +++ b/shared/chat/inbox-and-conversation-header.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import type {StyleOverride} from '@/common-adapters/markdown' @@ -7,9 +7,9 @@ import SearchRow from './inbox/search-row' import NewChatButton from './inbox/new-chat-button' import {useRoute} from '@react-navigation/native' import type {RootRouteProps} from '@/router-v2/route-params' -import {useUsersState} from '@/constants/users' -import {useCurrentUserState} from '@/constants/current-user' -import * as Teams from '@/constants/teams' +import {useUsersState} from '@/stores/users' +import {useCurrentUserState} from '@/stores/current-user' +import * as Teams from '@/stores/teams' const Header = () => { const {params} = useRoute>() diff --git a/shared/chat/inbox-search/index.tsx b/shared/chat/inbox-search/index.tsx index f85ab2edb2d3..823e2b970a33 100644 --- a/shared/chat/inbox-search/index.tsx +++ b/shared/chat/inbox-search/index.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useTeamsState} from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import * as React from 'react' import Rover from './background' diff --git a/shared/chat/inbox/container.tsx b/shared/chat/inbox/container.tsx index a8f303cc416c..210348d199d1 100644 --- a/shared/chat/inbox/container.tsx +++ b/shared/chat/inbox/container.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as T from '@/constants/types' import Inbox, {type Props} from '.' diff --git a/shared/chat/inbox/filter-row.tsx b/shared/chat/inbox/filter-row.tsx index 8a5651be6445..1d7214f8b4c1 100644 --- a/shared/chat/inbox/filter-row.tsx +++ b/shared/chat/inbox/filter-row.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/chat/inbox/index.native.tsx b/shared/chat/inbox/index.native.tsx index 3a33bbcbe653..41cafa1c706e 100644 --- a/shared/chat/inbox/index.native.tsx +++ b/shared/chat/inbox/index.native.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import * as RowSizes from './row/sizes' diff --git a/shared/chat/inbox/new-chat-button.tsx b/shared/chat/inbox/new-chat-button.tsx index e6987c1ddc92..bb086547ac38 100644 --- a/shared/chat/inbox/new-chat-button.tsx +++ b/shared/chat/inbox/new-chat-button.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/chat/inbox/row/big-team-channel.tsx b/shared/chat/inbox/row/big-team-channel.tsx index 79a4e46f06f3..e4089507b3b3 100644 --- a/shared/chat/inbox/row/big-team-channel.tsx +++ b/shared/chat/inbox/row/big-team-channel.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import * as RowSizes from './sizes' diff --git a/shared/chat/inbox/row/big-team-header.tsx b/shared/chat/inbox/row/big-team-header.tsx index b4cf9085a9b0..0fc4172f6497 100644 --- a/shared/chat/inbox/row/big-team-header.tsx +++ b/shared/chat/inbox/row/big-team-header.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as RowSizes from './sizes' import type * as T from '@/constants/types' diff --git a/shared/chat/inbox/row/big-teams-divider.tsx b/shared/chat/inbox/row/big-teams-divider.tsx index 35fc6ab594b1..547f2e267670 100644 --- a/shared/chat/inbox/row/big-teams-divider.tsx +++ b/shared/chat/inbox/row/big-teams-divider.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import * as RowSizes from './sizes' diff --git a/shared/chat/inbox/row/build-team.tsx b/shared/chat/inbox/row/build-team.tsx index 7f6415928fed..822260af2b68 100644 --- a/shared/chat/inbox/row/build-team.tsx +++ b/shared/chat/inbox/row/build-team.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import {useSafeNavigation} from '@/util/safe-navigation' diff --git a/shared/chat/inbox/row/opened-row-state.tsx b/shared/chat/inbox/row/opened-row-state.tsx index f32a8b91ce9a..29c1d4c415ff 100644 --- a/shared/chat/inbox/row/opened-row-state.tsx +++ b/shared/chat/inbox/row/opened-row-state.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Z from '@/util/zustand' import type * as T from '@/constants/types' diff --git a/shared/chat/inbox/row/small-team/bottom-line.tsx b/shared/chat/inbox/row/small-team/bottom-line.tsx index eccb3d94d2bb..1dfbc213d35e 100644 --- a/shared/chat/inbox/row/small-team/bottom-line.tsx +++ b/shared/chat/inbox/row/small-team/bottom-line.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import {SnippetContext, SnippetDecorationContext} from './contexts' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type Props = { layoutSnippet?: string diff --git a/shared/chat/inbox/row/small-team/index.tsx b/shared/chat/inbox/row/small-team/index.tsx index 869aaa3a9957..f0289b126b34 100644 --- a/shared/chat/inbox/row/small-team/index.tsx +++ b/shared/chat/inbox/row/small-team/index.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import {SimpleTopLine} from './top-line' @@ -9,7 +9,7 @@ import * as RowSizes from '../sizes' import * as T from '@/constants/types' import SwipeConvActions from './swipe-conv-actions' import './small-team.css' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' import { IsTeamContext, ParticipantsContext, diff --git a/shared/chat/inbox/row/small-team/swipe-conv-actions/index.native.tsx b/shared/chat/inbox/row/small-team/swipe-conv-actions/index.native.tsx index 5ec1de0c2ee2..94ff76ff16f9 100644 --- a/shared/chat/inbox/row/small-team/swipe-conv-actions/index.native.tsx +++ b/shared/chat/inbox/row/small-team/swipe-conv-actions/index.native.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import * as Reanimated from 'react-native-reanimated' diff --git a/shared/chat/inbox/row/small-team/top-line.tsx b/shared/chat/inbox/row/small-team/top-line.tsx index 86825d823584..3e45c439e679 100644 --- a/shared/chat/inbox/row/small-team/top-line.tsx +++ b/shared/chat/inbox/row/small-team/top-line.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import TeamMenu from '@/chat/conversation/info-panel/menu' diff --git a/shared/chat/inbox/row/teams-divider.tsx b/shared/chat/inbox/row/teams-divider.tsx index 282156d7da76..a45090ee43b3 100644 --- a/shared/chat/inbox/row/teams-divider.tsx +++ b/shared/chat/inbox/row/teams-divider.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import * as React from 'react' diff --git a/shared/chat/inbox/search-row.tsx b/shared/chat/inbox/search-row.tsx index c97a2cc786bd..ceedb67615a9 100644 --- a/shared/chat/inbox/search-row.tsx +++ b/shared/chat/inbox/search-row.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import ChatFilterRow from './filter-row' import StartNewChat from './row/start-new-chat' diff --git a/shared/chat/new-team-dialog-container.tsx b/shared/chat/new-team-dialog-container.tsx index 0421c30d6fef..4c4d1864c28e 100644 --- a/shared/chat/new-team-dialog-container.tsx +++ b/shared/chat/new-team-dialog-container.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import {CreateNewTeam} from '../teams/new-team' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import upperFirst from 'lodash/upperFirst' const NewTeamDialog = () => { diff --git a/shared/chat/payments/status/index.tsx b/shared/chat/payments/status/index.tsx index 3fe3ec65668b..05236a073498 100644 --- a/shared/chat/payments/status/index.tsx +++ b/shared/chat/payments/status/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import * as Styles from '@/styles' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import PaymentStatusError from './error' import Text from '@/common-adapters/text' import {Box2} from '@/common-adapters/box' @@ -9,7 +9,7 @@ import type * as T from '@/constants/types' import type {MeasureRef} from '@/common-adapters/measure-ref' import type * as WalletTypes from '@/constants/types/wallets' import {useOrdinal} from '@/chat/conversation/messages/ids-context' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' // This is actually a dependency of common-adapters/markdown so we have to treat it like a common-adapter, no * import allowed const Kb = { diff --git a/shared/chat/pdf/index.desktop.tsx b/shared/chat/pdf/index.desktop.tsx index d0c53c8853c4..6fcee8301fc1 100644 --- a/shared/chat/pdf/index.desktop.tsx +++ b/shared/chat/pdf/index.desktop.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import type {Props} from '.' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' const ChatPDF = (props: Props) => { const {ordinal} = props diff --git a/shared/chat/pdf/index.native.tsx b/shared/chat/pdf/index.native.tsx index 044e8691e00b..8f6253a027d2 100644 --- a/shared/chat/pdf/index.native.tsx +++ b/shared/chat/pdf/index.native.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import type {Props} from '.' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const ChatPDF = (props: Props) => { const {ordinal, url} = props diff --git a/shared/chat/routes.tsx b/shared/chat/routes.tsx index b34bfe654bdd..d9dcd49db022 100644 --- a/shared/chat/routes.tsx +++ b/shared/chat/routes.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import chatNewChat from '../team-building/page' import {headerNavigationOptions} from './conversation/header-area' import inboxGetOptions from './inbox/get-options' diff --git a/shared/chat/selectable-big-team-channel-container.tsx b/shared/chat/selectable-big-team-channel-container.tsx index 19af38e9941a..35e0b58f9614 100644 --- a/shared/chat/selectable-big-team-channel-container.tsx +++ b/shared/chat/selectable-big-team-channel-container.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import SelectableBigTeamChannel from './selectable-big-team-channel' type OwnProps = { diff --git a/shared/chat/selectable-small-team-container.tsx b/shared/chat/selectable-small-team-container.tsx index 2248c71d3a05..0a1f5f44b24a 100644 --- a/shared/chat/selectable-small-team-container.tsx +++ b/shared/chat/selectable-small-team-container.tsx @@ -1,8 +1,8 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import type {AllowedColors} from '@/common-adapters/text' import SelectableSmallTeam from './selectable-small-team' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = { filter?: string diff --git a/shared/chat/send-to-chat/index.tsx b/shared/chat/send-to-chat/index.tsx index 2bba86a3e4df..0b6d8b22f634 100644 --- a/shared/chat/send-to-chat/index.tsx +++ b/shared/chat/send-to-chat/index.tsx @@ -1,14 +1,14 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import * as React from 'react' import * as Kb from '@/common-adapters' import * as Kbfs from '@/fs/common' import ConversationList from './conversation-list/conversation-list' import ChooseConversation from './conversation-list/choose-conversation' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' type Props = { canBack?: boolean diff --git a/shared/common-adapters/avatar/hooks.tsx b/shared/common-adapters/avatar/hooks.tsx index 0307b138030d..e1177a28b72f 100644 --- a/shared/common-adapters/avatar/hooks.tsx +++ b/shared/common-adapters/avatar/hooks.tsx @@ -1,5 +1,5 @@ // High level avatar class. Handdles converting from usernames to urls. Deals with testing mode. -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import * as React from 'react' import {iconTypeToImgSet, urlsToImgSet, urlsToSrcSet, urlsToBaseSrc, type IconType} from '../icon' import * as Styles from '@/styles' @@ -7,9 +7,9 @@ import * as AvatarZus from './store' import './avatar.css' import type {Props} from '.' import {useColorScheme} from 'react-native' -import {useUsersState} from '@/constants/users' -import {useFollowerState} from '@/constants/followers' -import {navToProfile} from '@/constants/router2' +import {useUsersState} from '@/stores/users' +import {useFollowerState} from '@/stores/followers' +import {navToProfile} from '@/stores/router2' export const avatarSizes = [128, 96, 64, 48, 32, 24, 16] as const export type AvatarSize = (typeof avatarSizes)[number] diff --git a/shared/common-adapters/avatar/util.tsx b/shared/common-adapters/avatar/util.tsx deleted file mode 100644 index 6e08e360ab2f..000000000000 --- a/shared/common-adapters/avatar/util.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import {useAvatarState} from '@/common-adapters/avatar/store' - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyTeamAvatarUpdated: { - const {name} = action.payload.params - useAvatarState.getState().dispatch.updated(name) - break - } - default: - } -} - diff --git a/shared/common-adapters/copy-text.tsx b/shared/common-adapters/copy-text.tsx index 7942082307fb..505513bd6efd 100644 --- a/shared/common-adapters/copy-text.tsx +++ b/shared/common-adapters/copy-text.tsx @@ -8,7 +8,7 @@ import {useTimeout} from './use-timers' import * as Styles from '@/styles' import logger from '@/logger' import type {MeasureRef} from './measure-ref' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const Kb = { Box2Measure, diff --git a/shared/common-adapters/markdown/channel.tsx b/shared/common-adapters/markdown/channel.tsx index 55a2dc3d237e..a80546942696 100644 --- a/shared/common-adapters/markdown/channel.tsx +++ b/shared/common-adapters/markdown/channel.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import type * as T from '@/constants/types' import Text, {type StylesTextCrossPlatform} from '../text' import * as React from 'react' diff --git a/shared/common-adapters/markdown/maybe-mention/index.tsx b/shared/common-adapters/markdown/maybe-mention/index.tsx index 33431631f674..86bbe6a0a396 100644 --- a/shared/common-adapters/markdown/maybe-mention/index.tsx +++ b/shared/common-adapters/markdown/maybe-mention/index.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import Text, {type StylesTextCrossPlatform} from '@/common-adapters/text' import Mention from '../../mention-container' diff --git a/shared/common-adapters/markdown/maybe-mention/team.tsx b/shared/common-adapters/markdown/maybe-mention/team.tsx index 90bd396a1ee5..e9b7f234f06b 100644 --- a/shared/common-adapters/markdown/maybe-mention/team.tsx +++ b/shared/common-adapters/markdown/maybe-mention/team.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as React from 'react' import Text, {type StylesTextCrossPlatform} from '@/common-adapters/text' import {Box2} from '@/common-adapters/box' diff --git a/shared/common-adapters/mention-container.tsx b/shared/common-adapters/mention-container.tsx index 7cd4ab40f54f..f7044658c04c 100644 --- a/shared/common-adapters/mention-container.tsx +++ b/shared/common-adapters/mention-container.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import Mention, {type OwnProps} from './mention' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' -import {useFollowerState} from '@/constants/followers' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' +import {useFollowerState} from '@/stores/followers' +import {useCurrentUserState} from '@/stores/current-user' const Container = (ownProps: OwnProps) => { let {username} = ownProps diff --git a/shared/common-adapters/mention.tsx b/shared/common-adapters/mention.tsx index 468c66b4297e..973ec7212085 100644 --- a/shared/common-adapters/mention.tsx +++ b/shared/common-adapters/mention.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Styles from '@/styles' import {WithProfileCardPopup} from './profile-card' import Text from './text' diff --git a/shared/common-adapters/name-with-icon.tsx b/shared/common-adapters/name-with-icon.tsx index fdadf76d3ba6..07c7f2c4f3c7 100644 --- a/shared/common-adapters/name-with-icon.tsx +++ b/shared/common-adapters/name-with-icon.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as Styles from '@/styles' import * as C from '@/constants' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import Avatar, {type AvatarSize} from './avatar' import {Box} from './box' import ClickableBox from './clickable-box' @@ -13,8 +13,8 @@ import Text, { type TextTypeBold, } from './text' import ConnectedUsernames from './usernames' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' type Size = 'smaller' | 'small' | 'default' | 'big' | 'huge' diff --git a/shared/common-adapters/profile-card.tsx b/shared/common-adapters/profile-card.tsx index 933bfa706f49..a053acccd437 100644 --- a/shared/common-adapters/profile-card.tsx +++ b/shared/common-adapters/profile-card.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import * as React from 'react' import * as Styles from '@/styles' import * as Platforms from '@/util/platforms' -import * as Tracker from '@/constants/tracker2' +import * as Tracker from '@/stores/tracker2' import type * as T from '@/constants/types' import capitalize from 'lodash/capitalize' import Box, {Box2, Box2Measure} from './box' @@ -12,16 +12,16 @@ import {_setWithProfileCardPopup} from './usernames' import FloatingMenu from './floating-menu' import Icon from './icon' import Meta from './meta' -import {useProfileState} from '@/constants/profile' -import {useFollowerState} from '@/constants/followers' -import {useCurrentUserState} from '@/constants/current-user' +import {useProfileState} from '@/stores/profile' +import {useFollowerState} from '@/stores/followers' +import {useCurrentUserState} from '@/stores/current-user' import ProgressIndicator from './progress-indicator' import Text from './text' import WithTooltip from './with-tooltip' import DelayedMounting from './delayed-mounting' import {type default as FollowButtonType} from '../profile/user/actions/follow-button' import type ChatButtonType from '../chat/chat-button' -import {useTrackerState} from '@/constants/tracker2' +import {useTrackerState} from '@/stores/tracker2' import type {MeasureRef} from './measure-ref' const positionFallbacks = ['top center', 'bottom center'] as const diff --git a/shared/common-adapters/proof-broken-banner.tsx b/shared/common-adapters/proof-broken-banner.tsx index 861ead336641..e1ecfd0cb296 100644 --- a/shared/common-adapters/proof-broken-banner.tsx +++ b/shared/common-adapters/proof-broken-banner.tsx @@ -1,8 +1,8 @@ import * as C from '@/constants' import * as React from 'react' import {Banner, BannerParagraph} from './banner' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' const Kb = {Banner} type Props = {users?: Array} diff --git a/shared/common-adapters/reload.tsx b/shared/common-adapters/reload.tsx index a3e150277db7..08fe71c05cd7 100644 --- a/shared/common-adapters/reload.tsx +++ b/shared/common-adapters/reload.tsx @@ -10,7 +10,7 @@ import Button from './button' import Icon from './icon' import type {RPCError} from '@/util/errors' import {settingsFeedbackTab} from '@/constants/settings/util' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const Kb = { Box2, diff --git a/shared/common-adapters/team-with-popup.tsx b/shared/common-adapters/team-with-popup.tsx index 4059c9608948..f907e5e1ca80 100644 --- a/shared/common-adapters/team-with-popup.tsx +++ b/shared/common-adapters/team-with-popup.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import {Box2} from './box' import * as Styles from '@/styles' diff --git a/shared/common-adapters/usernames.tsx b/shared/common-adapters/usernames.tsx index e86fcb564666..570f91b6abab 100644 --- a/shared/common-adapters/usernames.tsx +++ b/shared/common-adapters/usernames.tsx @@ -12,11 +12,11 @@ import Text, { import {backgroundModeIsNegative} from './text.shared' import isArray from 'lodash/isArray' import type {e164ToDisplay as e164ToDisplayType} from '@/util/phone-numbers' -import {useTrackerState} from '@/constants/tracker2' -import {useUsersState} from '@/constants/users' -import {useProfileState} from '@/constants/profile' -import {useFollowerState} from '@/constants/followers' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useUsersState} from '@/stores/users' +import {useProfileState} from '@/stores/profile' +import {useFollowerState} from '@/stores/followers' +import {useCurrentUserState} from '@/stores/current-user' export type User = { username: string diff --git a/shared/common-adapters/wave-button.tsx b/shared/common-adapters/wave-button.tsx index 40a33f359a66..63a8ab05699a 100644 --- a/shared/common-adapters/wave-button.tsx +++ b/shared/common-adapters/wave-button.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import {Box2, Box} from './box' import Icon from './icon' diff --git a/shared/constants/archive/util.tsx b/shared/constants/archive/util.tsx deleted file mode 100644 index 3be104f15ecb..000000000000 --- a/shared/constants/archive/util.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import type * as UseArchiveStateType from '../archive' - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifySimpleFSSimpleFSArchiveStatusChanged: - case EngineGen.chat1NotifyChatChatArchiveComplete: - case EngineGen.chat1NotifyChatChatArchiveProgress: - { - const {useArchiveState} = require('../archive') as typeof UseArchiveStateType - useArchiveState.getState().dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/autoreset/util.tsx b/shared/constants/autoreset/util.tsx deleted file mode 100644 index ccaa494f61a0..000000000000 --- a/shared/constants/autoreset/util.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyBadgesBadgeState: - { - storeRegistry.getState('autoreset').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/bots/util.tsx b/shared/constants/bots/util.tsx deleted file mode 100644 index 1af60048ec8d..000000000000 --- a/shared/constants/bots/util.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import type * as T from '../types' -import {storeRegistry} from '../store-registry' - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyFeaturedBotsFeaturedBotsUpdate: - { - storeRegistry.getState('bots').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} - - -export const getFeaturedSorted = ( - featuredBotsMap: ReadonlyMap -): Array => { - const featured = [...featuredBotsMap.values()] - featured.sort((a: T.RPCGen.FeaturedBot, b: T.RPCGen.FeaturedBot) => { - if (a.rank < b.rank) { - return 1 - } else if (a.rank > b.rank) { - return -1 - } - return 0 - }) - return featured -} diff --git a/shared/constants/chat2/common.tsx b/shared/constants/chat2/common.tsx index 8c63c456b387..c16ed15eb76f 100644 --- a/shared/constants/chat2/common.tsx +++ b/shared/constants/chat2/common.tsx @@ -1,7 +1,7 @@ import * as T from '../types' import {isMobile, isTablet} from '../platform' -import * as Router2 from '../router2' -import {useConfigState} from '../config' +import * as Router2 from '@/stores/router2' +import {useConfigState} from '@/stores/config' export const explodingModeGregorKeyPrefix = 'exploding:' diff --git a/shared/constants/chat2/convostate.tsx b/shared/constants/chat2/convostate.tsx index fe96a91842d7..a1c4d33dd1df 100644 --- a/shared/constants/chat2/convostate.tsx +++ b/shared/constants/chat2/convostate.tsx @@ -47,8 +47,8 @@ import {enumKeys, ignorePromise, shallowEqual} from '../utils' import * as Strings from '@/constants/strings' import {storeRegistry} from '../store-registry' -import {useConfigState} from '../config' -import {useCurrentUserState} from '../current-user' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' const {darwinCopyToChatTempUploadFile} = KB2.functions diff --git a/shared/constants/chat2/debug.tsx b/shared/constants/chat2/debug.tsx index ba94fb89a7f8..e91c336a2aca 100644 --- a/shared/constants/chat2/debug.tsx +++ b/shared/constants/chat2/debug.tsx @@ -1,5 +1,5 @@ // Debug utilities for chat -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import type * as T from '@/constants/types' import logger from '@/logger' diff --git a/shared/constants/chat2/meta.tsx b/shared/constants/chat2/meta.tsx index 243060f08637..93b889627441 100644 --- a/shared/constants/chat2/meta.tsx +++ b/shared/constants/chat2/meta.tsx @@ -5,7 +5,7 @@ import * as Teams from '../teams/util' import * as Message from './message' import {base64ToUint8Array, uint8ArrayToHex} from 'uint8array-extras' import {storeRegistry} from '../store-registry' -import {useCurrentUserState} from '../current-user' +import {useCurrentUserState} from '@/stores/current-user' const conversationMemberStatusToMembershipType = (m: T.RPCChat.ConversationMemberStatus) => { switch (m) { @@ -41,9 +41,9 @@ export const unverifiedInboxUIItemToConversationMeta = ( // We only treat implicit adhoc teams as having resetParticipants const resetParticipants: Set = new Set( i.localMetadata && - (i.membersType === T.RPCChat.ConversationMembersType.impteamnative || - i.membersType === T.RPCChat.ConversationMembersType.impteamupgrade) && - i.localMetadata.resetParticipants + (i.membersType === T.RPCChat.ConversationMembersType.impteamnative || + i.membersType === T.RPCChat.ConversationMembersType.impteamupgrade) && + i.localMetadata.resetParticipants ? i.localMetadata.resetParticipants : [] ) @@ -237,7 +237,7 @@ export const inboxUIItemToConversationMeta = ( const resetParticipants = new Set( (i.membersType === T.RPCChat.ConversationMembersType.impteamnative || i.membersType === T.RPCChat.ConversationMembersType.impteamupgrade) && - i.resetParticipants + i.resetParticipants ? i.resetParticipants : [] ) diff --git a/shared/constants/chat2/util.tsx b/shared/constants/chat2/util.tsx index a1e5b2c74fc6..e69de29bb2d1 100644 --- a/shared/constants/chat2/util.tsx +++ b/shared/constants/chat2/util.tsx @@ -1,61 +0,0 @@ -import * as T from '../types' -import {ignorePromise} from '../utils' -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' - -export const onEngineConnected = () => { - const f = async () => { - try { - await T.RPCGen.delegateUiCtlRegisterChatUIRpcPromise() - await T.RPCGen.delegateUiCtlRegisterLogUIRpcPromise() - console.log('Registered Chat UI') - } catch (error) { - console.warn('Error in registering Chat UI:', error) - } - } - ignorePromise(f()) -} - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.chat1ChatUiChatInboxFailed: - case EngineGen.chat1NotifyChatChatSetConvSettings: - case EngineGen.chat1NotifyChatChatAttachmentUploadStart: - case EngineGen.chat1NotifyChatChatPromptUnfurl: - case EngineGen.chat1NotifyChatChatPaymentInfo: - case EngineGen.chat1NotifyChatChatRequestInfo: - case EngineGen.chat1NotifyChatChatAttachmentDownloadProgress: - case EngineGen.chat1NotifyChatChatAttachmentDownloadComplete: - case EngineGen.chat1NotifyChatChatAttachmentUploadProgress: - case EngineGen.chat1ChatUiChatCommandMarkdown: - case EngineGen.chat1ChatUiChatGiphyToggleResultWindow: - case EngineGen.chat1ChatUiChatCommandStatus: - case EngineGen.chat1ChatUiChatBotCommandsUpdateStatus: - case EngineGen.chat1ChatUiChatGiphySearchResults: - case EngineGen.chat1NotifyChatChatParticipantsInfo: - case EngineGen.chat1ChatUiChatMaybeMentionUpdate: - case EngineGen.chat1NotifyChatChatConvUpdate: - case EngineGen.chat1ChatUiChatCoinFlipStatus: - case EngineGen.chat1NotifyChatChatThreadsStale: - case EngineGen.chat1NotifyChatChatSubteamRename: - case EngineGen.chat1NotifyChatChatTLFFinalize: - case EngineGen.chat1NotifyChatChatIdentifyUpdate: - case EngineGen.chat1ChatUiChatInboxUnverified: - case EngineGen.chat1NotifyChatChatInboxSyncStarted: - case EngineGen.chat1NotifyChatChatInboxSynced: - case EngineGen.chat1ChatUiChatInboxLayout: - case EngineGen.chat1NotifyChatChatInboxStale: - case EngineGen.chat1ChatUiChatInboxConversation: - case EngineGen.chat1NotifyChatNewChatActivity: - case EngineGen.chat1NotifyChatChatTypingUpdate: - case EngineGen.chat1NotifyChatChatSetConvRetention: - case EngineGen.chat1NotifyChatChatSetTeamRetention: - case EngineGen.keybase1NotifyBadgesBadgeState: - case EngineGen.keybase1GregorUIPushState: - { - storeRegistry.getState('chat').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/deeplinks/index.tsx b/shared/constants/deeplinks/index.tsx index a81ec61f4f5f..998f184dc780 100644 --- a/shared/constants/deeplinks/index.tsx +++ b/shared/constants/deeplinks/index.tsx @@ -1,15 +1,14 @@ import * as Crypto from '../crypto/util' import * as Tabs from '../tabs' import {isPathSaltpackEncrypted, isPathSaltpackSigned} from '@/util/path' -import * as EngineGen from '@/actions/engine-gen-gen' import type HiddenString from '@/util/hidden-string' import URL from 'url-parse' import logger from '@/logger' import * as T from '@/constants/types' import {navigateAppend, switchTab} from '../router2/util' import {storeRegistry} from '../store-registry' -import {useCryptoState} from '../crypto' -import {useConfigState} from '../config' +import {useCryptoState} from '@/stores/crypto' +import {useConfigState} from '@/stores/config' const prefix = 'keybase://' export const linkFromConvAndMessage = (conv: string, messageID: number) => @@ -38,77 +37,77 @@ const validTeamnamePart = (s: string): boolean => { } const validTeamname = (s: string) => s.split('.').every(validTeamnamePart) - const handleShowUserProfileLink = (username: string) => { - switchTab(Tabs.peopleTab) - storeRegistry.getState('profile').dispatch.showUserProfile(username) - } +const handleShowUserProfileLink = (username: string) => { + switchTab(Tabs.peopleTab) + storeRegistry.getState('profile').dispatch.showUserProfile(username) +} - const isKeybaseIoUrl = (url: URL) => { - const {protocol} = url - if (protocol !== 'http:' && protocol !== 'https:') return false - if (url.username || url.password) return false - const {hostname} = url - if (hostname !== 'keybase.io' && hostname !== 'www.keybase.io') return false - const {port} = url - if (port) { - if (protocol === 'http:' && port !== '80') return false - if (protocol === 'https:' && port !== '443') return false - } - return true +const isKeybaseIoUrl = (url: URL) => { + const {protocol} = url + if (protocol !== 'http:' && protocol !== 'https:') return false + if (url.username || url.password) return false + const {hostname} = url + if (hostname !== 'keybase.io' && hostname !== 'www.keybase.io') return false + const {port} = url + if (port) { + if (protocol === 'http:' && port !== '80') return false + if (protocol === 'https:' && port !== '443') return false } + return true +} - const urlToUsername = (url: URL) => { - if (!isKeybaseIoUrl(url)) { - return null - } - // Adapted username regexp (see libkb/checkers.go) with a leading /, an - // optional trailing / and a dash for custom links. - const match = url.pathname.match(/^\/((?:[a-zA-Z0-9][a-zA-Z0-9_-]?)+)\/?$/) - if (!match) { - return null - } - const usernameMatch = match[1] - if (!usernameMatch || usernameMatch.length < 2 || usernameMatch.length > 16) { - return null - } - // Ignore query string and hash parameters. - return usernameMatch.toLowerCase() +const urlToUsername = (url: URL) => { + if (!isKeybaseIoUrl(url)) { + return null } - - const urlToTeamDeepLink = (url: URL) => { - if (!isKeybaseIoUrl(url)) { - return null - } - // Similar regexp to username but allow `.` for subteams - const match = url.pathname.match(/^\/team\/((?:[a-zA-Z0-9][a-zA-Z0-9_.-]?)+)\/?$/) - if (!match) { - return null - } - const teamName = match[1] - if (!teamName || teamName.length < 2 || teamName.length > 255) { - return null - } - // `url.query` has a wrong type in @types/url-parse. It's a `string` in the - // code, but @types claim it's a {[k: string]: string | undefined}. - const queryString = url.query as unknown as string - // URLSearchParams is not available in react-native. See if any of recognized - // query parameters is passed using regular expressions. - const action = (['add_or_invite', 'manage_settings'] satisfies readonly TeamPageAction[]).find( - x => queryString.search(`[?&]applink=${x}([?&].+)?$`) !== -1 - ) - return {action, teamName} + // Adapted username regexp (see libkb/checkers.go) with a leading /, an + // optional trailing / and a dash for custom links. + const match = url.pathname.match(/^\/((?:[a-zA-Z0-9][a-zA-Z0-9_-]?)+)\/?$/) + if (!match) { + return null + } + const usernameMatch = match[1] + if (!usernameMatch || usernameMatch.length < 2 || usernameMatch.length > 16) { + return null } + // Ignore query string and hash parameters. + return usernameMatch.toLowerCase() +} - const handleTeamPageLink = (teamname: string, action?: TeamPageAction) => { - storeRegistry - .getState('teams') - .dispatch.showTeamByName( - teamname, - action === 'manage_settings' ? 'settings' : undefined, - action === 'join' ? true : undefined, - action === 'add_or_invite' ? true : undefined - ) +const urlToTeamDeepLink = (url: URL) => { + if (!isKeybaseIoUrl(url)) { + return null } + // Similar regexp to username but allow `.` for subteams + const match = url.pathname.match(/^\/team\/((?:[a-zA-Z0-9][a-zA-Z0-9_.-]?)+)\/?$/) + if (!match) { + return null + } + const teamName = match[1] + if (!teamName || teamName.length < 2 || teamName.length > 255) { + return null + } + // `url.query` has a wrong type in @types/url-parse. It's a `string` in the + // code, but @types claim it's a {[k: string]: string | undefined}. + const queryString = url.query as unknown as string + // URLSearchParams is not available in react-native. See if any of recognized + // query parameters is passed using regular expressions. + const action = (['add_or_invite', 'manage_settings'] satisfies readonly TeamPageAction[]).find( + x => queryString.search(`[?&]applink=${x}([?&].+)?$`) !== -1 + ) + return {action, teamName} +} + +const handleTeamPageLink = (teamname: string, action?: TeamPageAction) => { + storeRegistry + .getState('teams') + .dispatch.showTeamByName( + teamname, + action === 'manage_settings' ? 'settings' : undefined, + action === 'join' ? true : undefined, + action === 'add_or_invite' ? true : undefined + ) +} export const handleAppLink = (link: string) => { if (link.startsWith('keybase://')) { @@ -147,9 +146,7 @@ export const handleKeybaseLink = (link: string) => { switch (parts[0]) { case 'profile': if (parts[1] === 'new-proof' && (parts.length === 3 || parts.length === 4)) { - parts.length === 4 && - parts[3] && - storeRegistry.getState('profile').dispatch.showUserProfile(parts[3]) + parts.length === 4 && parts[3] && storeRegistry.getState('profile').dispatch.showUserProfile(parts[3]) storeRegistry.getState('profile').dispatch.addProof(parts[2]!, 'appLink') return } else if (parts[1] === 'show' && parts.length === 3) { @@ -288,17 +285,3 @@ export const handleSaltPackOpen = (_path: string | HiddenString) => { useCryptoState.getState().dispatch.onSaltpackOpenFile(operation, path) switchTab(Tabs.cryptoTab) } - -export const onEngineIncomingImpl = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyServiceHandleKeybaseLink: { - const {link, deferred} = action.payload.params - if (deferred && !link.startsWith('keybase://team-invite-link/')) { - return - } - handleKeybaseLink(link) - break - } - default: - } -} diff --git a/shared/constants/deeplinks/util.tsx b/shared/constants/deeplinks/util.tsx deleted file mode 100644 index e5f2d279fcc6..000000000000 --- a/shared/constants/deeplinks/util.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import {onEngineIncomingImpl} from './index' - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyServiceHandleKeybaseLink: - { - onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/devices/util.tsx b/shared/constants/devices/util.tsx deleted file mode 100644 index 23b3694282b6..000000000000 --- a/shared/constants/devices/util.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' - -let loaded = false - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyBadgesBadgeState: - { - const {badgeState} = action.payload.params - const {newDevices, revokedDevices} = badgeState - const hasValue = (newDevices?.length ?? 0) + (revokedDevices?.length ?? 0) > 0 - if (loaded || hasValue) { - loaded = true - storeRegistry.getState('devices').dispatch.onEngineIncomingImpl(action) - } - } - break - default: - } -} diff --git a/shared/constants/followers/util.tsx b/shared/constants/followers/util.tsx deleted file mode 100644 index 34ea577cab45..000000000000 --- a/shared/constants/followers/util.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import isEqual from 'lodash/isEqual' -import {useCurrentUserState} from '../current-user' -import {useFollowerState} from '../followers' - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyTrackingTrackingChanged: { - const {isTracking, username} = action.payload.params - useFollowerState.getState().dispatch.updateFollowing(username, isTracking) - break - } - case EngineGen.keybase1NotifyTrackingTrackingInfo: { - const {uid, followers: _newFollowers, followees: _newFollowing} = action.payload.params - if (useCurrentUserState.getState().uid !== uid) { - return - } - const newFollowers = new Set(_newFollowers) - const newFollowing = new Set(_newFollowing) - const {following: oldFollowing, followers: oldFollowers, dispatch} = useFollowerState.getState() - const following = isEqual(newFollowing, oldFollowing) ? oldFollowing : newFollowing - const followers = isEqual(newFollowers, oldFollowers) ? oldFollowers : newFollowers - dispatch.replace(followers, following) - break - } - default: - } -} - diff --git a/shared/constants/fs/common.native.tsx b/shared/constants/fs/common.native.tsx index c75025efc827..920f0561993f 100644 --- a/shared/constants/fs/common.native.tsx +++ b/shared/constants/fs/common.native.tsx @@ -3,10 +3,10 @@ import {ignorePromise} from '../utils' import {wrapErrors} from '@/util/debug' import * as T from '../types' import * as Styles from '@/styles' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' import {launchImageLibraryAsync} from '@/util/expo-image-picker.native' import {saveAttachmentToCameraRoll, showShareActionSheet} from '../platform-specific' -import {useFSState} from '.' +import {useFSState} from '@/stores/fs' export default function initNative() { useFSState.setState(s => { diff --git a/shared/constants/fs/platform-specific.android.tsx b/shared/constants/fs/platform-specific.android.tsx index 8e7f3ff2a04b..a31524a9b47e 100644 --- a/shared/constants/fs/platform-specific.android.tsx +++ b/shared/constants/fs/platform-specific.android.tsx @@ -1,9 +1,9 @@ import * as T from '../types' import {ignorePromise, wrapErrors} from '../utils' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' import logger from '@/logger' import nativeInit from './common.native' -import {useFSState} from '.' +import {useFSState} from '@/stores/fs' import {androidAddCompleteDownload, fsCacheDir, fsDownloadDir} from 'react-native-kb' const finishedRegularDownloadIDs = new Set() @@ -26,43 +26,41 @@ export default function initPlatformSpecific() { // needs to be called, TODO could make this better s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged() - s.dispatch.dynamic.finishedRegularDownloadMobile = wrapErrors( - (downloadID: string, mimeType: string) => { - const f = async () => { - // This is fired from a hook and can happen more than once per downloadID. - // So just deduplicate them here. This is small enough and won't happen - // constantly, so don't worry about clearing them. - if (finishedRegularDownloadIDs.has(downloadID)) { - return - } - finishedRegularDownloadIDs.add(downloadID) + s.dispatch.dynamic.finishedRegularDownloadMobile = wrapErrors((downloadID: string, mimeType: string) => { + const f = async () => { + // This is fired from a hook and can happen more than once per downloadID. + // So just deduplicate them here. This is small enough and won't happen + // constantly, so don't worry about clearing them. + if (finishedRegularDownloadIDs.has(downloadID)) { + return + } + finishedRegularDownloadIDs.add(downloadID) - const {downloads} = useFSState.getState() + const {downloads} = useFSState.getState() - const downloadState = downloads.state.get(downloadID) || FS.emptyDownloadState - const downloadInfo = downloads.info.get(downloadID) || FS.emptyDownloadInfo - if (downloadState === FS.emptyDownloadState || downloadInfo === FS.emptyDownloadInfo) { - logger.warn('missing download', downloadID) - return - } - if (downloadState.error) { - return - } - try { - await androidAddCompleteDownload({ - description: `Keybase downloaded ${downloadInfo.filename}`, - mime: mimeType, - path: downloadState.localPath, - showNotification: true, - title: downloadInfo.filename, - }) - } catch { - logger.warn('Failed to addCompleteDownload') - } - // No need to dismiss here as the download wrapper does it for Android. + const downloadState = downloads.state.get(downloadID) || FS.emptyDownloadState + const downloadInfo = downloads.info.get(downloadID) || FS.emptyDownloadInfo + if (downloadState === FS.emptyDownloadState || downloadInfo === FS.emptyDownloadInfo) { + logger.warn('missing download', downloadID) + return + } + if (downloadState.error) { + return } - ignorePromise(f()) + try { + await androidAddCompleteDownload({ + description: `Keybase downloaded ${downloadInfo.filename}`, + mime: mimeType, + path: downloadState.localPath, + showNotification: true, + title: downloadInfo.filename, + }) + } catch { + logger.warn('Failed to addCompleteDownload') + } + // No need to dismiss here as the download wrapper does it for Android. } - ) + ignorePromise(f()) + }) }) } diff --git a/shared/constants/fs/platform-specific.desktop.tsx b/shared/constants/fs/platform-specific.desktop.tsx index 71bee000e649..557910c110af 100644 --- a/shared/constants/fs/platform-specific.desktop.tsx +++ b/shared/constants/fs/platform-specific.desktop.tsx @@ -1,15 +1,16 @@ import * as T from '@/constants/types' import {ignorePromise, wrapErrors} from '../utils' -import * as Constants from '../fs' +import * as Constants from '@/stores/fs' import * as Tabs from '../tabs' import {isWindows, isLinux, pathSep, isDarwin} from '../platform.desktop' import logger from '@/logger' import * as Path from '@/util/path' import KB2 from '@/util/electron.desktop' import {uint8ArrayToHex} from 'uint8array-extras' -import {useFSState} from '.' import {navigateAppend} from '../router2/util' -import {useConfigState} from '../config' +import {useConfigState} from '@/stores/config' + +const useFSState = Constants.useFSState const {openPathInFinder, openURL, getPathType, selectFilesToUploadDialog} = KB2.functions const {darwinCopyToKBFSTempUploadFile, relaunchApp, uninstallKBFSDialog, uninstallDokanDialog} = KB2.functions diff --git a/shared/constants/fs/util.tsx b/shared/constants/fs/util.tsx index e680702022f8..d57ccfd6c7cc 100644 --- a/shared/constants/fs/util.tsx +++ b/shared/constants/fs/util.tsx @@ -1,25 +1,9 @@ -import * as EngineGen from '@/actions/engine-gen-gen' import type * as React from 'react' import * as Tabs from '../tabs' import * as T from '../types' import {isLinux, isMobile} from '../platform' import {settingsFsTab} from '../settings/util' import {navigateAppend} from '../router2/util' -import {storeRegistry} from '../store-registry' - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyFSFSOverallSyncStatusChanged: - case EngineGen.keybase1NotifyFSFSSubscriptionNotifyPath: - case EngineGen.keybase1NotifyFSFSSubscriptionNotify: - { - storeRegistry.getState('fs').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} - export const makeActionForOpenPathInFilesTab = ( // TODO: remove the second arg when we are done with migrating to nav2 path: T.FS.Path diff --git a/shared/constants/git/util.tsx b/shared/constants/git/util.tsx deleted file mode 100644 index c72418bcf735..000000000000 --- a/shared/constants/git/util.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' - -let loadedStore = false -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyBadgesBadgeState: - { - const {badgeState} = action.payload.params - const badges = new Set(badgeState.newGitRepoGlobalUniqueIDs) - // don't bother loading the store if no badges - if (loadedStore || badges.size) { - loadedStore = true - storeRegistry.getState('git').dispatch.onEngineIncomingImpl(action) - } - } - break - default: - } -} diff --git a/shared/constants/index.tsx b/shared/constants/index.tsx index b3359e15383d..7911ee17773b 100644 --- a/shared/constants/index.tsx +++ b/shared/constants/index.tsx @@ -1,10 +1,10 @@ export * from './platform' export * from './values' export * from './strings' -export {useRouterState, makeScreen} from './router2' -export * as Router2 from './router2' +export {useRouterState, makeScreen} from '@/stores/router2' +export * as Router2 from '@/stores/router2' export * as Tabs from './tabs' -export {useWaitingState} from './waiting' -export * as Waiting from './waiting' +export {useWaitingState} from '@/stores/waiting' +export * as Waiting from '@/stores/waiting' export * as PlatformSpecific from './platform-specific' export * from './utils' diff --git a/shared/constants/init/index.desktop.tsx b/shared/constants/init/index.desktop.tsx index 90e9d5834292..c7ba7e02fb83 100644 --- a/shared/constants/init/index.desktop.tsx +++ b/shared/constants/init/index.desktop.tsx @@ -1,24 +1,24 @@ // links all the stores together, stores never import this -import * as Chat from '../chat2' -import {ignorePromise} from '../utils' -import {useConfigState} from '../config' -import * as ConfigConstants from '../config' -import {useDaemonState} from '../daemon' -import {useFSState} from '../fs' -import {useProfileState} from '../profile' -import {useRouterState} from '../router2' +import * as Chat from '@/stores/chat2' +import {ignorePromise} from '@/constants/utils' +import {useConfigState} from '@/stores/config' +import * as ConfigConstants from '@/stores/config' +import {useDaemonState} from '@/stores/daemon' +import {useFSState} from '@/stores/fs' +import {useProfileState} from '@/stores/profile' +import {useRouterState} from '@/stores/router2' import * as EngineGen from '@/actions/engine-gen-gen' -import * as T from '../types' -import InputMonitor from '../platform-specific/input-monitor.desktop' +import * as T from '@/constants/types' +import InputMonitor from '@/constants/platform-specific/input-monitor.desktop' import KB2 from '@/util/electron.desktop' import logger from '@/logger' import type {RPCError} from '@/util/errors' import {getEngine} from '@/engine' -import {isLinux, isWindows} from '../platform.desktop' -import {kbfsNotification} from '../platform-specific/kbfs-notifications' +import {isLinux, isWindows} from '@/constants/platform.desktop' +import {kbfsNotification} from '@/constants/platform-specific/kbfs-notifications' import {skipAppFocusActions} from '@/local-debug.desktop' import NotifyPopup from '@/util/notify-popup' -import {noKBFSFailReason} from '../config/util' +import {noKBFSFailReason} from '@/constants/config/util' import {initSharedSubscriptions, _onEngineIncoming} from './shared' import {wrapErrors} from '@/util/debug' diff --git a/shared/constants/init/index.native.tsx b/shared/constants/init/index.native.tsx index 39a02773ae59..380f554e8503 100644 --- a/shared/constants/init/index.native.tsx +++ b/shared/constants/init/index.native.tsx @@ -1,27 +1,27 @@ // links all the stores together, stores never import this import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from '../utils' -import {useChatState} from '../chat2' -import {useConfigState} from '../config' -import {useCurrentUserState} from '../current-user' -import {useDaemonState} from '../daemon' -import {useDarkModeState} from '../darkmode' -import {useFSState} from '../fs' -import {useProfileState} from '../profile' -import {useRouterState} from '../router2' -import {useSettingsContactsState} from '../settings-contacts' -import * as T from '../types' +import {useChatState} from '@/stores/chat2' +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' +import {useProfileState} from '@/stores/profile' +import {useRouterState} from '@/stores/router2' +import {useSettingsContactsState} from '@/stores/settings-contacts' +import * as T from '@/constants/types' import * as Clipboard from 'expo-clipboard' import * as EngineGen from '@/actions/engine-gen-gen' import * as ExpoLocation from 'expo-location' import * as ExpoTaskManager from 'expo-task-manager' -import * as Tabs from '../tabs' +import * as Tabs from '@/constants/tabs' import * as NetInfo from '@react-native-community/netinfo' import NotifyPopup from '@/util/notify-popup' import logger from '@/logger' import {Alert, Linking} from 'react-native' -import {isAndroid} from '../platform.native' +import {isAndroid} from '@/constants/platform.native' import {wrapErrors} from '@/util/debug' -import {getTab, getVisiblePath, logState} from '../router2' +import {getTab, getVisiblePath, logState} from '@/stores/router2' import {launchImageLibraryAsync} from '@/util/expo-image-picker.native' import {setupAudioMode} from '@/util/audio.native' import { diff --git a/shared/constants/init/shared.tsx b/shared/constants/init/shared.tsx index 8ed40061299a..7be982c97f36 100644 --- a/shared/constants/init/shared.tsx +++ b/shared/constants/init/shared.tsx @@ -1,50 +1,88 @@ -import type * as EngineGen from '@/actions/engine-gen-gen' +import * as EngineGen from '@/actions/engine-gen-gen' import logger from '@/logger' -import {serverConfigFileName} from '../platform' +import {isMobile, serverConfigFileName} from '../platform' import * as T from '../types' import {ignorePromise} from '../utils' -import * as ArchiveUtil from '../archive/util' -import * as AutoResetUtil from '../autoreset/util' -import * as AvatarUtil from '@/common-adapters/avatar/util' -import * as BotsUtil from '../bots/util' -import {useChatState} from '../chat2' -import {getSelectedConversation} from '../chat2/common' -import * as ChatUtil from '../chat2/util' -import {useConfigState} from '../config' -import {useCurrentUserState} from '../current-user' -import {useDaemonState} from '../daemon' -import {useDarkModeState} from '../darkmode' -import * as DeepLinksUtil from '../deeplinks/util' -import * as DevicesUtil from '../devices/util' -import * as FollowerUtil from '../followers/util' -import * as FSUtil from '../fs/util' -import * as GitUtil from '../git/util' -import * as NotifUtil from '../notifications/util' -import * as PeopleUtil from '../people/util' -import * as PinentryUtil from '../pinentry/util' -import {useProvisionState} from '../provision' +import type * as UseArchiveStateType from '@/stores/archive' +import type * as UseAutoResetStateType from '@/stores/autoreset' +import type * as UseDevicesStateType from '@/stores/devices' +import {useAvatarState} from '@/common-adapters/avatar/store' +import type * as UseBotsStateType from '@/stores/bots' +import {useChatState} from '@/stores/chat2' +import {getSelectedConversation} from '@/constants/chat2/common' +import type * as UseChatStateType from '@/stores/chat2' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' +import {useDaemonState} from '@/stores/daemon' +import {useDarkModeState} from '@/stores/darkmode' +import {handleKeybaseLink} from '../deeplinks' +import {useFollowerState} from '@/stores/followers' +import isEqual from 'lodash/isEqual' +import type * as UseFSStateType from '@/stores/fs' +import type * as UseGitStateType from '@/stores/git' +import type * as UseNotificationsStateType from '@/stores/notifications' +import type * as UsePeopleStateType from '@/stores/people' +import type * as UsePinentryStateType from '@/stores/pinentry' +import {useProvisionState} from '@/stores/provision' import {storeRegistry} from '../store-registry' -import {useSettingsContactsState} from '../settings-contacts' -import * as SettingsUtil from '../settings/util' -import * as SignupUtil from '../signup/util' -import {useTeamsState} from '../teams' -import * as TeamsUtil from '../teams/util' -import * as TrackerUtil from '../tracker2/util' -import * as UnlockFoldersUtil from '../unlock-folders/util' -import * as UsersUtil from '../users/util' -import {useWhatsNewState} from '../whats-new' +import {useSettingsContactsState} from '@/stores/settings-contacts' +import type * as UseSignupStateType from '@/stores/signup' +import type * as UseTeamsStateType from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' +import type * as UseTracker2StateType from '@/stores/tracker2' +import type * as UseUnlockFoldersStateType from '@/stores/unlock-folders' +import type * as UseUsersStateType from '@/stores/users' +import {useWhatsNewState} from '@/stores/whats-new' let _emitStartupOnLoadDaemonConnectedOnce = false +let _devicesLoaded = false +let _gitLoaded = false export const onEngineConnected = () => { - ChatUtil.onEngineConnected() + { + const registerUIs = async () => { + try { + await T.RPCGen.delegateUiCtlRegisterChatUIRpcPromise() + await T.RPCGen.delegateUiCtlRegisterLogUIRpcPromise() + logger.info('Registered Chat UI') + await T.RPCGen.delegateUiCtlRegisterHomeUIRpcPromise() + logger.info('Registered home UI') + await T.RPCGen.delegateUiCtlRegisterSecretUIRpcPromise() + logger.info('Registered secret ui') + await T.RPCGen.delegateUiCtlRegisterIdentify3UIRpcPromise() + logger.info('Registered identify ui') + await T.RPCGen.delegateUiCtlRegisterRekeyUIRpcPromise() + logger.info('Registered rekey ui') + } catch (error) { + logger.error('Error in registering UIs:', error) + } + } + ignorePromise(registerUIs()) + } useConfigState.getState().dispatch.onEngineConnected() storeRegistry.getState('daemon').dispatch.startHandshake() - NotifUtil.onEngineConnected() - PeopleUtil.onEngineConnected() - PinentryUtil.onEngineConnected() - TrackerUtil.onEngineConnected() - UnlockFoldersUtil.onEngineConnected() + { + const notifyCtl = async () => { + try { + // prettier-ignore + await T.RPCGen.notifyCtlSetNotificationsRpcPromise({ + channels: { + allowChatNotifySkips: true, app: true, audit: true, badges: true, chat: true, chatarchive: true, + chatattachments: true, chatdev: false, chatemoji: false, chatemojicross: false, chatkbfsedits: false, + deviceclone: false, ephemeral: false, favorites: false, featuredBots: true, kbfs: true, kbfsdesktop: !isMobile, + kbfslegacy: false, kbfsrequest: false, kbfssubscription: true, keyfamily: false, notifysimplefs: true, + paperkeys: false, pgp: true, reachability: true, runtimestats: true, saltpack: true, service: true, session: true, + team: true, teambot: false, tracking: true, users: true, wallet: false, + }, + }) + } catch (error) { + if (error) { + logger.warn('error in toggling notifications: ', error) + } + } + } + ignorePromise(notifyCtl()) + } } export const onEngineDisconnected = () => { @@ -241,25 +279,223 @@ export const initSharedSubscriptions = () => { }) } +// This is to defer loading stores we don't need immediately. export const _onEngineIncoming = (action: EngineGen.Actions) => { - ArchiveUtil.onEngineIncoming(action) - AutoResetUtil.onEngineIncoming(action) - AvatarUtil.onEngineIncoming(action) - BotsUtil.onEngineIncoming(action) - ChatUtil.onEngineIncoming(action) + switch (action.type) { + case EngineGen.keybase1NotifySimpleFSSimpleFSArchiveStatusChanged: + case EngineGen.chat1NotifyChatChatArchiveComplete: + case EngineGen.chat1NotifyChatChatArchiveProgress: + { + const {useArchiveState} = require('@/stores/archive') as typeof UseArchiveStateType + useArchiveState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1NotifyBadgesBadgeState: + { + const {useAutoResetState} = require('@/stores/autoreset') as typeof UseAutoResetStateType + useAutoResetState.getState().dispatch.onEngineIncomingImpl(action) + + const {badgeState} = action.payload.params + const {newDevices, revokedDevices} = badgeState + const hasValue = (newDevices?.length ?? 0) + (revokedDevices?.length ?? 0) > 0 + if (_devicesLoaded || hasValue) { + _devicesLoaded = true + const {useDevicesState} = require('@/stores/devices') as typeof UseDevicesStateType + useDevicesState.getState().dispatch.onEngineIncomingImpl(action) + } + + const badges = new Set(badgeState.newGitRepoGlobalUniqueIDs) + if (_gitLoaded || badges.size) { + _gitLoaded = true + const {useGitState} = require('@/stores/git') as typeof UseGitStateType + useGitState.getState().dispatch.onEngineIncomingImpl(action) + } + + const {useNotifState} = require('@/stores/notifications') as typeof UseNotificationsStateType + useNotifState.getState().dispatch.onEngineIncomingImpl(action) + + const {useTeamsState} = require('@/stores/teams') as typeof UseTeamsStateType + useTeamsState.getState().dispatch.onEngineIncomingImpl(action) + + const {useChatState} = require('@/stores/chat2') as typeof UseChatStateType + useChatState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.chat1ChatUiChatShowManageChannels: + case EngineGen.keybase1NotifyTeamTeamMetadataUpdate: + case EngineGen.chat1NotifyChatChatWelcomeMessageLoaded: + case EngineGen.keybase1NotifyTeamTeamTreeMembershipsPartial: + case EngineGen.keybase1NotifyTeamTeamTreeMembershipsDone: + case EngineGen.keybase1NotifyTeamTeamRoleMapChanged: + case EngineGen.keybase1NotifyTeamTeamChangedByID: + case EngineGen.keybase1NotifyTeamTeamDeleted: + case EngineGen.keybase1NotifyTeamTeamExit: + case EngineGen.keybase1GregorUIPushState: + { + const {useTeamsState} = require('@/stores/teams') as typeof UseTeamsStateType + useTeamsState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1NotifyFeaturedBotsFeaturedBotsUpdate: + { + const {useBotsState} = require('@/stores/bots') as typeof UseBotsStateType + useBotsState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1NotifyFSFSOverallSyncStatusChanged: + case EngineGen.keybase1NotifyFSFSSubscriptionNotifyPath: + case EngineGen.keybase1NotifyFSFSSubscriptionNotify: + { + const {useFSState} = require('@/stores/fs') as typeof UseFSStateType + useFSState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1NotifyAuditRootAuditError: + case EngineGen.keybase1NotifyAuditBoxAuditError: + { + const {useNotifState} = require('@/stores/notifications') as typeof UseNotificationsStateType + useNotifState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1HomeUIHomeUIRefresh: + case EngineGen.keybase1NotifyEmailAddressEmailAddressVerified: + { + const {usePeopleState} = require('@/stores/people') as typeof UsePeopleStateType + usePeopleState.getState().dispatch.onEngineIncomingImpl(action) + const emailAddress = action.payload.params?.emailAddress + if (emailAddress) { + storeRegistry.getState('settings-email').dispatch.notifyEmailVerified(emailAddress) + } + const {useSignupState} = require('@/stores/signup') as typeof UseSignupStateType + useSignupState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1SecretUiGetPassphrase: + { + const {usePinentryState} = require('@/stores/pinentry') as typeof UsePinentryStateType + usePinentryState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1NotifyUsersPasswordChanged: + { + const randomPW = action.payload.params.state === T.RPCGen.PassphraseState.random + storeRegistry.getState('settings-password').dispatch.notifyUsersPasswordChanged(randomPW) + } + break + case EngineGen.keybase1NotifyPhoneNumberPhoneNumbersChanged: { + const {list} = action.payload.params + storeRegistry + .getState('settings-phone') + .dispatch.notifyPhoneNumberPhoneNumbersChanged(list ?? undefined) + break + } + case EngineGen.keybase1NotifyEmailAddressEmailsChanged: { + const list = action.payload.params.list ?? [] + storeRegistry.getState('settings-email').dispatch.notifyEmailAddressEmailsChanged(list) + break + } + case EngineGen.chat1ChatUiChatInboxFailed: + case EngineGen.chat1NotifyChatChatSetConvSettings: + case EngineGen.chat1NotifyChatChatAttachmentUploadStart: + case EngineGen.chat1NotifyChatChatPromptUnfurl: + case EngineGen.chat1NotifyChatChatPaymentInfo: + case EngineGen.chat1NotifyChatChatRequestInfo: + case EngineGen.chat1NotifyChatChatAttachmentDownloadProgress: + case EngineGen.chat1NotifyChatChatAttachmentDownloadComplete: + case EngineGen.chat1NotifyChatChatAttachmentUploadProgress: + case EngineGen.chat1ChatUiChatCommandMarkdown: + case EngineGen.chat1ChatUiChatGiphyToggleResultWindow: + case EngineGen.chat1ChatUiChatCommandStatus: + case EngineGen.chat1ChatUiChatBotCommandsUpdateStatus: + case EngineGen.chat1ChatUiChatGiphySearchResults: + case EngineGen.chat1NotifyChatChatParticipantsInfo: + case EngineGen.chat1ChatUiChatMaybeMentionUpdate: + case EngineGen.chat1NotifyChatChatConvUpdate: + case EngineGen.chat1ChatUiChatCoinFlipStatus: + case EngineGen.chat1NotifyChatChatThreadsStale: + case EngineGen.chat1NotifyChatChatSubteamRename: + case EngineGen.chat1NotifyChatChatTLFFinalize: + case EngineGen.chat1NotifyChatChatIdentifyUpdate: + case EngineGen.chat1ChatUiChatInboxUnverified: + case EngineGen.chat1NotifyChatChatInboxSyncStarted: + case EngineGen.chat1NotifyChatChatInboxSynced: + case EngineGen.chat1ChatUiChatInboxLayout: + case EngineGen.chat1NotifyChatChatInboxStale: + case EngineGen.chat1ChatUiChatInboxConversation: + case EngineGen.chat1NotifyChatNewChatActivity: + case EngineGen.chat1NotifyChatChatTypingUpdate: + case EngineGen.chat1NotifyChatChatSetConvRetention: + case EngineGen.chat1NotifyChatChatSetTeamRetention: + { + const {useChatState} = require('@/stores/chat2') as typeof UseChatStateType + useChatState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1NotifyServiceHandleKeybaseLink: + { + const {link, deferred} = action.payload.params + if (deferred && !link.startsWith('keybase://team-invite-link/')) { + return + } + handleKeybaseLink(link) + } + break + case EngineGen.keybase1NotifyTeamAvatarUpdated: { + const {name} = action.payload.params + useAvatarState.getState().dispatch.updated(name) + break + } + case EngineGen.keybase1NotifyTrackingTrackingChanged: { + const {isTracking, username} = action.payload.params + useFollowerState.getState().dispatch.updateFollowing(username, isTracking) + const {useTrackerState} = require('@/stores/tracker2') as typeof UseTracker2StateType + useTrackerState.getState().dispatch.onEngineIncomingImpl(action) + break + } + case EngineGen.keybase1NotifyTrackingTrackingInfo: { + const {uid, followers: _newFollowers, followees: _newFollowing} = action.payload.params + if (useCurrentUserState.getState().uid !== uid) { + break + } + const newFollowers = new Set(_newFollowers) + const newFollowing = new Set(_newFollowing) + const {following: oldFollowing, followers: oldFollowers, dispatch} = useFollowerState.getState() + const following = isEqual(newFollowing, oldFollowing) ? oldFollowing : newFollowing + const followers = isEqual(newFollowers, oldFollowers) ? oldFollowers : newFollowers + dispatch.replace(followers, following) + break + } + case EngineGen.keybase1Identify3UiIdentify3Result: + case EngineGen.keybase1Identify3UiIdentify3ShowTracker: + case EngineGen.keybase1NotifyUsersUserChanged: + case EngineGen.keybase1NotifyTrackingNotifyUserBlocked: + case EngineGen.keybase1Identify3UiIdentify3UpdateRow: + case EngineGen.keybase1Identify3UiIdentify3UserReset: + case EngineGen.keybase1Identify3UiIdentify3UpdateUserCard: + case EngineGen.keybase1Identify3UiIdentify3Summary: + { + const {useTrackerState} = require('@/stores/tracker2') as typeof UseTracker2StateType + useTrackerState.getState().dispatch.onEngineIncomingImpl(action) + } + { + const {useUsersState} = require('@/stores/users') as typeof UseUsersStateType + useUsersState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1NotifyUsersIdentifyUpdate: + { + const {useUsersState} = require('@/stores/users') as typeof UseUsersStateType + useUsersState.getState().dispatch.onEngineIncomingImpl(action) + } + break + case EngineGen.keybase1RekeyUIRefresh: + case EngineGen.keybase1RekeyUIDelegateRekeyUI: + { + const {useUnlockFoldersState} = require('@/stores/unlock-folders') as typeof UseUnlockFoldersStateType + useUnlockFoldersState.getState().dispatch.onEngineIncomingImpl(action) + } + break + default: + } useConfigState.getState().dispatch.onEngineIncoming(action) - DeepLinksUtil.onEngineIncoming(action) - DevicesUtil.onEngineIncoming(action) - FollowerUtil.onEngineIncoming(action) - FSUtil.onEngineIncoming(action) - GitUtil.onEngineIncoming(action) - NotifUtil.onEngineIncoming(action) - PeopleUtil.onEngineIncoming(action) - PinentryUtil.onEngineIncoming(action) - SettingsUtil.onEngineIncoming(action) - SignupUtil.onEngineIncoming(action) - TeamsUtil.onEngineIncoming(action) - TrackerUtil.onEngineIncoming(action) - UnlockFoldersUtil.onEngineIncoming(action) - UsersUtil.onEngineIncoming(action) } diff --git a/shared/constants/notifications/util.tsx b/shared/constants/notifications/util.tsx index acc95a39dbf0..e69de29bb2d1 100644 --- a/shared/constants/notifications/util.tsx +++ b/shared/constants/notifications/util.tsx @@ -1,69 +0,0 @@ -import * as T from '../types' -import {ignorePromise} from '../utils' -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' -import {isMobile} from '../platform' -import logger from '@/logger' - -export const onEngineConnected = () => { - const f = async () => { - try { - await T.RPCGen.notifyCtlSetNotificationsRpcPromise({ - channels: { - allowChatNotifySkips: true, - app: true, - audit: true, - badges: true, - chat: true, - chatarchive: true, - chatattachments: true, - chatdev: false, - chatemoji: false, - chatemojicross: false, - chatkbfsedits: false, - deviceclone: false, - ephemeral: false, - favorites: false, - featuredBots: true, - kbfs: true, - kbfsdesktop: !isMobile, - kbfslegacy: false, - kbfsrequest: false, - kbfssubscription: true, - keyfamily: false, - notifysimplefs: true, - paperkeys: false, - pgp: true, - reachability: true, - runtimestats: true, - saltpack: true, - service: true, - session: true, - team: true, - teambot: false, - tracking: true, - users: true, - wallet: false, - }, - }) - } catch (error) { - if (error) { - logger.warn('error in toggling notifications: ', error) - } - } - } - ignorePromise(f()) -} - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyAuditRootAuditError: - case EngineGen.keybase1NotifyAuditBoxAuditError: - case EngineGen.keybase1NotifyBadgesBadgeState: - { - storeRegistry.getState('notifications').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/people/util.tsx b/shared/constants/people/util.tsx index 8deb5593c959..e69de29bb2d1 100644 --- a/shared/constants/people/util.tsx +++ b/shared/constants/people/util.tsx @@ -1,28 +0,0 @@ -import * as T from '../types' -import {ignorePromise} from '../utils' -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' - -export const onEngineConnected = () => { - const f = async () => { - try { - await T.RPCGen.delegateUiCtlRegisterHomeUIRpcPromise() - console.log('Registered home UI') - } catch (error) { - console.warn('Error in registering home UI:', error) - } - } - ignorePromise(f()) -} - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1HomeUIHomeUIRefresh: - case EngineGen.keybase1NotifyEmailAddressEmailAddressVerified: - { - storeRegistry.getState('people').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/pinentry/util.tsx b/shared/constants/pinentry/util.tsx deleted file mode 100644 index 5bc792128d6e..000000000000 --- a/shared/constants/pinentry/util.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import * as T from '../types' -import {ignorePromise} from '../utils' -import * as EngineGen from '@/actions/engine-gen-gen' -import {usePinentryState} from '../pinentry' -import logger from '@/logger' - -export const onEngineConnected = () => { - const f = async () => { - try { - await T.RPCGen.delegateUiCtlRegisterSecretUIRpcPromise() - logger.info('Registered secret ui') - } catch (error) { - logger.warn('error in registering secret ui: ', error) - } - } - ignorePromise(f()) -} - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1SecretUiGetPassphrase: - { - usePinentryState.getState().dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/platform-specific/kbfs-notifications.tsx b/shared/constants/platform-specific/kbfs-notifications.tsx index 6d5b97e4a18b..1ee3f17113f6 100644 --- a/shared/constants/platform-specific/kbfs-notifications.tsx +++ b/shared/constants/platform-specific/kbfs-notifications.tsx @@ -1,5 +1,5 @@ import {pathSep} from '@/constants/platform' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' import capitalize from 'lodash/capitalize' import * as T from '@/constants/types' import {parseFolderNameToUsers} from '@/util/kbfs' diff --git a/shared/constants/platform-specific/push.native.tsx b/shared/constants/platform-specific/push.native.tsx index 25f3ed270787..60d5fb4df93b 100644 --- a/shared/constants/platform-specific/push.native.tsx +++ b/shared/constants/platform-specific/push.native.tsx @@ -10,8 +10,8 @@ import { removeAllPendingNotificationRequests, } from 'react-native-kb' import {storeRegistry} from '../store-registry' -import {useConfigState} from '../config' -import {useLogoutState} from '../logout' +import {useConfigState} from '@/stores/config' +import {useLogoutState} from '@/stores/logout' type DataCommon = { userInteraction: boolean diff --git a/shared/constants/push.native.tsx b/shared/constants/push.native.tsx index 9e7995bfade6..7f115f028fe5 100644 --- a/shared/constants/push.native.tsx +++ b/shared/constants/push.native.tsx @@ -1,24 +1,24 @@ -import * as Tabs from './tabs' -import * as S from './strings' -import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from './utils' -import {navigateAppend, navUpToScreen, switchTab} from './router2/util' -import {storeRegistry} from './store-registry' -import {useConfigState} from './config' -import {useCurrentUserState} from './current-user' -import {useLogoutState} from './logout' -import {useWaitingState} from './waiting' +import * as Tabs from '@/constants/tabs' +import * as S from '@/constants/strings' +import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from '@/constants/utils' +import {navigateAppend, navUpToScreen, switchTab} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' +import {useLogoutState} from '@/stores/logout' +import {useWaitingState} from '@/stores/waiting' import * as Z from '@/util/zustand' import logger from '@/logger' -import * as T from './types' +import * as T from '@/constants/types' import {isDevApplePushToken} from '@/local-debug' -import {isIOS} from './platform' +import {isIOS} from '@/constants/platform' import { iosGetHasShownPushPrompt, checkPushPermissions, requestPushPermissions, removeAllPendingNotificationRequests, } from 'react-native-kb' -import {type Store, type State} from './push' +import {type Store, type State} from '@/constants/push' export const tokenType = isIOS ? (isDevApplePushToken ? 'appledev' : 'apple') : 'androidplay' diff --git a/shared/constants/rpc-utils.tsx b/shared/constants/rpc-utils.tsx index 5969509c5d03..8c5993554391 100644 --- a/shared/constants/rpc-utils.tsx +++ b/shared/constants/rpc-utils.tsx @@ -1,6 +1,12 @@ import * as T from './types' import {uint8ArrayToString} from 'uint8array-extras' -import {type Device} from './provision' + +type Device = { + deviceNumberOfType: number + id: T.Devices.DeviceID + name: string + type: T.Devices.DeviceType +} export const bodyToJSON = (body?: Uint8Array): unknown => { if (!body) return undefined @@ -27,4 +33,3 @@ export const rpcDeviceToDevice = (d: T.RPCGen.Device): Device => { throw new Error('Invalid device type detected: ' + type) } } - diff --git a/shared/constants/settings/util.tsx b/shared/constants/settings/util.tsx index 281dc0582fd5..b54c44d6f26e 100644 --- a/shared/constants/settings/util.tsx +++ b/shared/constants/settings/util.tsx @@ -1,6 +1,3 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' - export const traceInProgressKey = 'settings:traceInProgress' export const processorProfileInProgressKey = 'settings:processorProfileInProgress' @@ -47,17 +44,3 @@ export type SettingsTab = | typeof settingsCryptoTab | typeof settingsContactsTab | typeof settingsWhatsNewTab - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyEmailAddressEmailAddressVerified: - case EngineGen.keybase1NotifyUsersPasswordChanged: - case EngineGen.keybase1NotifyPhoneNumberPhoneNumbersChanged: - case EngineGen.keybase1NotifyEmailAddressEmailsChanged: - { - storeRegistry.getState('settings').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/signup/util.tsx b/shared/constants/signup/util.tsx deleted file mode 100644 index 7c58483bdb13..000000000000 --- a/shared/constants/signup/util.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyEmailAddressEmailAddressVerified: - { - storeRegistry.getState('signup').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/store-registry.tsx b/shared/constants/store-registry.tsx index 1d04affa5e76..d45249872caa 100644 --- a/shared/constants/store-registry.tsx +++ b/shared/constants/store-registry.tsx @@ -1,33 +1,36 @@ // used to allow non-circular cross-calls between stores // ONLY for zustand stores -import type * as T from './types' -import type * as TBType from './team-building' -import type * as ConvoStateType from './chat2/convostate' -import type {ConvoState} from './chat2/convostate' -import type {State as AutoResetState, useAutoResetState} from './autoreset' -import type {State as BotsState, useBotsState} from './bots' -import type {State as ChatState, useChatState} from './chat2' -import type {State as DaemonState, useDaemonState} from './daemon' -import type {State as DevicesState, useDevicesState} from './devices' -import type {State as FSState, useFSState} from './fs' -import type {State as GitState, useGitState} from './git' -import type {State as NotificationsState, useNotifState} from './notifications' -import type {State as PeopleState, usePeopleState} from './people' -import type {State as ProfileState, useProfileState} from './profile' -import type {State as ProvisionState, useProvisionState} from './provision' -import type {State as PushState, usePushState} from './push' -import type {State as RecoverPasswordState, useState as useRecoverPasswordState} from './recover-password' -import type {State as SettingsState, useSettingsState} from './settings' -import type {State as SettingsChatState, useSettingsChatState} from './settings-chat' -import type {State as SettingsContactsState, useSettingsContactsState} from './settings-contacts' -import type {State as SettingsEmailState, useSettingsEmailState} from './settings-email' -import type {State as SettingsPasswordState, usePWState} from './settings-password' -import type {State as SettingsPhoneState, useSettingsPhoneState} from './settings-phone' -import type {State as SignupState, useSignupState} from './signup' -import type {State as TeamsState, useTeamsState} from './teams' -import type {State as Tracker2State, useTrackerState} from './tracker2' -import type {State as UnlockFoldersState, useUnlockFoldersState} from './unlock-folders' -import type {State as UsersState, useUsersState} from './users' +import type * as T from '@/constants/types' +import type * as TBType from '@/stores/team-building' +import type * as ConvoStateType from '@/constants/chat2/convostate' +import type {ConvoState} from '@/constants/chat2/convostate' +import type {State as AutoResetState, useAutoResetState} from '@/stores/autoreset' +import type {State as BotsState, useBotsState} from '@/stores/bots' +import type {State as ChatState, useChatState} from '@/stores/chat2' +import type {State as DaemonState, useDaemonState} from '@/stores/daemon' +import type {State as DevicesState, useDevicesState} from '@/stores/devices' +import type {State as FSState, useFSState} from '@/stores/fs' +import type {State as GitState, useGitState} from '@/stores/git' +import type {State as NotificationsState, useNotifState} from '@/stores/notifications' +import type {State as PeopleState, usePeopleState} from '@/stores/people' +import type {State as ProfileState, useProfileState} from '@/stores/profile' +import type {State as ProvisionState, useProvisionState} from '@/stores/provision' +import type {State as PushState, usePushState} from '@/constants/push' +import type { + State as RecoverPasswordState, + useState as useRecoverPasswordState, +} from '@/stores/recover-password' +import type {State as SettingsState, useSettingsState} from '@/stores/settings' +import type {State as SettingsChatState, useSettingsChatState} from '@/stores/settings-chat' +import type {State as SettingsContactsState, useSettingsContactsState} from '@/stores/settings-contacts' +import type {State as SettingsEmailState, useSettingsEmailState} from '@/stores/settings-email' +import type {State as SettingsPasswordState, usePWState} from '@/stores/settings-password' +import type {State as SettingsPhoneState, useSettingsPhoneState} from '@/stores/settings-phone' +import type {State as SignupState, useSignupState} from '@/stores/signup' +import type {State as TeamsState, useTeamsState} from '@/stores/teams' +import type {State as Tracker2State, useTrackerState} from '@/stores/tracker2' +import type {State as UnlockFoldersState, useUnlockFoldersState} from '@/stores/unlock-folders' +import type {State as UsersState, useUsersState} from '@/stores/users' type StoreName = | 'autoreset' @@ -114,99 +117,99 @@ class StoreRegistry { /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return */ switch (storeName) { case 'autoreset': { - const {useAutoResetState} = require('./autoreset') + const {useAutoResetState} = require('@/stores/autoreset') return useAutoResetState } case 'bots': { - const {useBotsState} = require('./bots') + const {useBotsState} = require('@/stores/bots') return useBotsState } case 'chat': { - const {useChatState} = require('./chat2') + const {useChatState} = require('@/stores/chat2') return useChatState } case 'daemon': { - const {useDaemonState} = require('./daemon') + const {useDaemonState} = require('@/stores/daemon') return useDaemonState } case 'devices': { - const {useDevicesState} = require('./devices') + const {useDevicesState} = require('@/stores/devices') return useDevicesState } case 'fs': { - const {useFSState} = require('./fs') + const {useFSState} = require('@/stores/fs') return useFSState } case 'git': { - const {useGitState} = require('./git') + const {useGitState} = require('@/stores/git') return useGitState } case 'notifications': { - const {useNotifState} = require('./notifications') + const {useNotifState} = require('@/stores/notifications') return useNotifState } case 'people': { - const {usePeopleState} = require('./people') + const {usePeopleState} = require('@/stores/people') return usePeopleState } case 'profile': { - const {useProfileState} = require('./profile') + const {useProfileState} = require('@/stores/profile') return useProfileState } case 'provision': { - const {useProvisionState} = require('./provision') + const {useProvisionState} = require('@/stores/provision') return useProvisionState } case 'push': { - const {usePushState} = require('./push') + const {usePushState} = require('@/constants/push') return usePushState } case 'recover-password': { - const {useState} = require('./recover-password') + const {useState} = require('@/stores/recover-password') return useState } case 'settings': { - const {useSettingsState} = require('./settings') + const {useSettingsState} = require('@/stores/settings') return useSettingsState } case 'settings-chat': { - const {useSettingsChatState} = require('./settings-chat') + const {useSettingsChatState} = require('@/stores/settings-chat') return useSettingsChatState } case 'settings-contacts': { - const {useSettingsContactsState} = require('./settings-contacts') + const {useSettingsContactsState} = require('@/stores/settings-contacts') return useSettingsContactsState } case 'settings-email': { - const {useSettingsEmailState} = require('./settings-email') + const {useSettingsEmailState} = require('@/stores/settings-email') return useSettingsEmailState } case 'settings-password': { - const {usePWState} = require('./settings-password') + const {usePWState} = require('@/stores/settings-password') return usePWState } case 'settings-phone': { - const {useSettingsPhoneState} = require('./settings-phone') + const {useSettingsPhoneState} = require('@/stores/settings-phone') return useSettingsPhoneState } case 'signup': { - const {useSignupState} = require('./signup') + const {useSignupState} = require('@/stores/signup') return useSignupState } case 'teams': { - const {useTeamsState} = require('./teams') + const {useTeamsState} = require('@/stores/teams') return useTeamsState } case 'tracker2': { - const {useTrackerState} = require('./tracker2') + const {useTrackerState} = require('@/stores/tracker2') return useTrackerState } case 'unlock-folders': { - const {useUnlockFoldersState} = require('./unlock-folders') + const {useUnlockFoldersState} = require('@/stores/unlock-folders') return useUnlockFoldersState } case 'users': { - const {useUsersState} = require('./users') + const {useUsersState} = require('@/stores/users') return useUsersState } default: @@ -219,13 +222,13 @@ class StoreRegistry { } getTBStore(name: T.TB.AllowedNamespace): TBType.State { - const {createTBStore} = require('./team-building') as typeof TBType + const {createTBStore} = require('@/stores/team-building') as typeof TBType const store = createTBStore(name) return store.getState() } getConvoState(id: T.Chat.ConversationIDKey): ConvoState { - const {getConvoState} = require('./chat2/convostate') as typeof ConvoStateType + const {getConvoState} = require('@/constants/chat2/convostate') as typeof ConvoStateType return getConvoState(id) } } diff --git a/shared/constants/teams/util.tsx b/shared/constants/teams/util.tsx index 48167c472d34..ce11cc0f9c40 100644 --- a/shared/constants/teams/util.tsx +++ b/shared/constants/teams/util.tsx @@ -1,29 +1,6 @@ -import * as EngineGen from '@/actions/engine-gen-gen' import * as T from '../types' -import {storeRegistry} from '../store-registry' import invert from 'lodash/invert' -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.chat1ChatUiChatShowManageChannels: - case EngineGen.keybase1NotifyTeamTeamMetadataUpdate: - case EngineGen.chat1NotifyChatChatWelcomeMessageLoaded: - case EngineGen.keybase1NotifyTeamTeamTreeMembershipsPartial: - case EngineGen.keybase1NotifyTeamTeamTreeMembershipsDone: - case EngineGen.keybase1NotifyTeamTeamRoleMapChanged: - case EngineGen.keybase1NotifyTeamTeamChangedByID: - case EngineGen.keybase1NotifyTeamTeamDeleted: - case EngineGen.keybase1NotifyTeamTeamExit: - case EngineGen.keybase1NotifyBadgesBadgeState: - case EngineGen.keybase1GregorUIPushState: - { - storeRegistry.getState('teams').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} - export const makeRetentionPolicy = ( r?: Partial ): T.Retention.RetentionPolicy => ({ diff --git a/shared/constants/tracker2/util.tsx b/shared/constants/tracker2/util.tsx index e6adb67ec4c6..e69de29bb2d1 100644 --- a/shared/constants/tracker2/util.tsx +++ b/shared/constants/tracker2/util.tsx @@ -1,36 +0,0 @@ -import * as T from '../types' -import {ignorePromise} from '../utils' -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' -import logger from '@/logger' - -export const onEngineConnected = () => { - const f = async () => { - try { - await T.RPCGen.delegateUiCtlRegisterIdentify3UIRpcPromise() - logger.info('Registered identify ui') - } catch (error) { - logger.warn('error in registering identify ui: ', error) - } - } - ignorePromise(f()) -} - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyTrackingTrackingChanged: - case EngineGen.keybase1Identify3UiIdentify3Result: - case EngineGen.keybase1Identify3UiIdentify3ShowTracker: - case EngineGen.keybase1NotifyUsersUserChanged: - case EngineGen.keybase1NotifyTrackingNotifyUserBlocked: - case EngineGen.keybase1Identify3UiIdentify3UpdateRow: - case EngineGen.keybase1Identify3UiIdentify3UserReset: - case EngineGen.keybase1Identify3UiIdentify3UpdateUserCard: - case EngineGen.keybase1Identify3UiIdentify3Summary: - { - storeRegistry.getState('tracker2').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/unlock-folders/util.tsx b/shared/constants/unlock-folders/util.tsx index 89d12305fd44..e69de29bb2d1 100644 --- a/shared/constants/unlock-folders/util.tsx +++ b/shared/constants/unlock-folders/util.tsx @@ -1,30 +0,0 @@ -import * as T from '../types' -import {ignorePromise} from '../utils' -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' -import logger from '@/logger' - -export const onEngineConnected = () => { - const f = async () => { - try { - await T.RPCGen.delegateUiCtlRegisterRekeyUIRpcPromise() - logger.info('Registered rekey ui') - } catch (error) { - logger.warn('error in registering rekey ui: ') - logger.debug('error in registering rekey ui: ', error) - } - } - ignorePromise(f()) -} - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1RekeyUIRefresh: - case EngineGen.keybase1RekeyUIDelegateRekeyUI: - { - storeRegistry.getState('unlock-folders').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/constants/users/util.tsx b/shared/constants/users/util.tsx index cd70c647ccb5..e69de29bb2d1 100644 --- a/shared/constants/users/util.tsx +++ b/shared/constants/users/util.tsx @@ -1,14 +0,0 @@ -import * as EngineGen from '@/actions/engine-gen-gen' -import {storeRegistry} from '../store-registry' - -export const onEngineIncoming = (action: EngineGen.Actions) => { - switch (action.type) { - case EngineGen.keybase1NotifyUsersIdentifyUpdate: - case EngineGen.keybase1NotifyTrackingNotifyUserBlocked: - { - storeRegistry.getState('users').dispatch.onEngineIncomingImpl(action) - } - break - default: - } -} diff --git a/shared/crypto/input.tsx b/shared/crypto/input.tsx index 575de4122740..2a04e94765a3 100644 --- a/shared/crypto/input.tsx +++ b/shared/crypto/input.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' -import * as Crypto from '@/constants/crypto' +import * as Crypto from '@/stores/crypto' import * as React from 'react' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' import type {IconType} from '@/common-adapters/icon.constants-gen' import capitalize from 'lodash/capitalize' import {pickFiles} from '@/util/pick-files' diff --git a/shared/crypto/operations/decrypt.tsx b/shared/crypto/operations/decrypt.tsx index 4f553f9e7b06..61060317259c 100644 --- a/shared/crypto/operations/decrypt.tsx +++ b/shared/crypto/operations/decrypt.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Crypto from '@/constants/crypto' +import * as Crypto from '@/stores/crypto' import * as Kb from '@/common-adapters' import * as React from 'react' import {Input, DragAndDrop, InputActionsBar, OperationBanner} from '../input' diff --git a/shared/crypto/operations/encrypt.tsx b/shared/crypto/operations/encrypt.tsx index 856c4b40cb0c..7be3f776cec8 100644 --- a/shared/crypto/operations/encrypt.tsx +++ b/shared/crypto/operations/encrypt.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Crypto from '@/constants/crypto' +import * as Crypto from '@/stores/crypto' import * as Kb from '@/common-adapters' import * as React from 'react' import Recipients from '../recipients' diff --git a/shared/crypto/operations/sign.tsx b/shared/crypto/operations/sign.tsx index 5ec68a46802e..7b0267c7f2a5 100644 --- a/shared/crypto/operations/sign.tsx +++ b/shared/crypto/operations/sign.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Crypto from '@/constants/crypto' +import * as Crypto from '@/stores/crypto' import * as React from 'react' import * as Kb from '@/common-adapters' import openURL from '@/util/open-url' diff --git a/shared/crypto/operations/verify.tsx b/shared/crypto/operations/verify.tsx index 3b64988b45a3..56decc162d9d 100644 --- a/shared/crypto/operations/verify.tsx +++ b/shared/crypto/operations/verify.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Crypto from '@/constants/crypto' +import * as Crypto from '@/stores/crypto' import * as Kb from '@/common-adapters' import * as React from 'react' import {Input, InputActionsBar, DragAndDrop, OperationBanner} from '../input' diff --git a/shared/crypto/output.tsx b/shared/crypto/output.tsx index d349ae39efe5..ca6efb87d482 100644 --- a/shared/crypto/output.tsx +++ b/shared/crypto/output.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import * as Crypto from '@/constants/crypto' +import * as Chat from '@/stores/chat2' +import * as Crypto from '@/stores/crypto' import * as Kb from '@/common-adapters' import * as Path from '@/util/path' import * as React from 'react' @@ -8,9 +8,9 @@ import capitalize from 'lodash/capitalize' import type * as T from '@/constants/types' import {pickFiles} from '@/util/pick-files' import type HiddenString from '@/util/hidden-string' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' -import {useConfigState} from '@/constants/config' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' +import {useConfigState} from '@/stores/config' type OutputProps = {operation: T.Crypto.Operations} type OutputActionsBarProps = {operation: T.Crypto.Operations} diff --git a/shared/crypto/recipients.tsx b/shared/crypto/recipients.tsx index a4ad222b2a2d..a7ac327df09f 100644 --- a/shared/crypto/recipients.tsx +++ b/shared/crypto/recipients.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Crypto from '@/constants/crypto' +import * as Crypto from '@/stores/crypto' import * as Kb from '@/common-adapters' const placeholder = 'Search people' diff --git a/shared/crypto/sub-nav/index.desktop.tsx b/shared/crypto/sub-nav/index.desktop.tsx index 7cd6cdfdd883..47e4b97a6486 100644 --- a/shared/crypto/sub-nav/index.desktop.tsx +++ b/shared/crypto/sub-nav/index.desktop.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import * as Kb from '@/common-adapters' -import * as Crypto from '@/constants/crypto' +import * as Crypto from '@/stores/crypto' import * as Common from '@/router-v2/common.desktop' import LeftNav from './left-nav.desktop' import { diff --git a/shared/crypto/sub-nav/index.native.tsx b/shared/crypto/sub-nav/index.native.tsx index c41261148096..f2ee824bec3b 100644 --- a/shared/crypto/sub-nav/index.native.tsx +++ b/shared/crypto/sub-nav/index.native.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Crypto from '@/constants/crypto' +import * as Crypto from '@/stores/crypto' import * as Kb from '@/common-adapters' import NavRow from './nav-row' diff --git a/shared/crypto/sub-nav/left-nav.desktop.tsx b/shared/crypto/sub-nav/left-nav.desktop.tsx index e44a26459acd..5dc1b78e412a 100644 --- a/shared/crypto/sub-nav/left-nav.desktop.tsx +++ b/shared/crypto/sub-nav/left-nav.desktop.tsx @@ -1,6 +1,6 @@ import type * as React from 'react' import * as Kb from '@/common-adapters' -import * as Crypto from '@/constants/crypto' +import * as Crypto from '@/stores/crypto' import NavRow from './nav-row' type Row = (typeof Crypto.Tabs)[number] & { diff --git a/shared/desktop/app/menu-bar.desktop.tsx b/shared/desktop/app/menu-bar.desktop.tsx index cbc76a7e902f..bca0da6b42de 100644 --- a/shared/desktop/app/menu-bar.desktop.tsx +++ b/shared/desktop/app/menu-bar.desktop.tsx @@ -8,7 +8,7 @@ import {menubar} from 'menubar' import {showDevTools, skipSecondaryDevtools} from '@/local-debug' import {getMainWindow} from './main-window.desktop' import {assetRoot, htmlPrefix} from './html-root.desktop' -import type {BadgeType} from '@/constants/notifications' +import type {BadgeType} from '@/stores/notifications' const getIcons = (iconType: BadgeType, badges: number) => { const size = isWindows ? 16 : 22 diff --git a/shared/desktop/remote/use-serialize-props.desktop.tsx b/shared/desktop/remote/use-serialize-props.desktop.tsx index 4bd25aacfdf1..3327ea8f6428 100644 --- a/shared/desktop/remote/use-serialize-props.desktop.tsx +++ b/shared/desktop/remote/use-serialize-props.desktop.tsx @@ -5,7 +5,7 @@ import * as React from 'react' import * as C from '@/constants' import KB2 from '@/util/electron.desktop' import isEqual from 'lodash/isEqual' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const {rendererNewProps} = KB2.functions diff --git a/shared/desktop/renderer/main.desktop.tsx b/shared/desktop/renderer/main.desktop.tsx index 640693e7a1bd..f216bfdfa816 100644 --- a/shared/desktop/renderer/main.desktop.tsx +++ b/shared/desktop/renderer/main.desktop.tsx @@ -3,7 +3,7 @@ import './globals.desktop' import {isDarwin, isWindows} from '@/constants/platform' import '@/util/why-did-you-render' import KB2, {waitOnKB2Loaded} from '@/util/electron.desktop' -import * as DarkMode from '@/constants/darkmode' +import * as DarkMode from '@/stores/darkmode' waitOnKB2Loaded(() => { const {setSystemSupported, setSystemDarkMode} = DarkMode.useDarkModeState.getState().dispatch diff --git a/shared/desktop/renderer/main2.desktop.tsx b/shared/desktop/renderer/main2.desktop.tsx index 806f02d32eae..9a4faab9139f 100644 --- a/shared/desktop/renderer/main2.desktop.tsx +++ b/shared/desktop/renderer/main2.desktop.tsx @@ -12,8 +12,8 @@ import {initDesktopStyles} from '@/styles/index.desktop' import {isWindows} from '@/constants/platform' import KB2 from '@/util/electron.desktop' import {ignorePromise} from '@/constants/utils' -import {useConfigState} from '@/constants/config' -import {usePinentryState} from '@/constants/pinentry' +import {useConfigState} from '@/stores/config' +import {usePinentryState} from '@/stores/pinentry' import * as T from '@/constants/types' import {RPCError} from '@/util/errors' import {switchTab} from '@/constants/router2/util' @@ -25,7 +25,7 @@ import {debugWarning} from '@/util/debug-warning' import type {default as NewMainType} from '../../app/main.desktop' import {setServiceDecoration} from '@/common-adapters/markdown/react' import ServiceDecoration from '@/common-adapters/markdown/service-decoration' -import {useDarkModeState} from '@/constants/darkmode' +import {useDarkModeState} from '@/stores/darkmode' import {initPlatformListener, onEngineIncoming} from '@/constants/init/index.desktop' setServiceDecoration(ServiceDecoration) diff --git a/shared/devices/add-device.tsx b/shared/devices/add-device.tsx index 3b5726f11013..e27c6efffcc5 100644 --- a/shared/devices/add-device.tsx +++ b/shared/devices/add-device.tsx @@ -1,8 +1,8 @@ import * as C from '@/constants' -import * as Devices from '@/constants/devices' +import * as Devices from '@/stores/devices' import * as React from 'react' import * as Kb from '@/common-adapters' -import {useProvisionState} from '@/constants/provision' +import {useProvisionState} from '@/stores/provision' type OwnProps = { highlight?: Array<'computer' | 'phone' | 'paper key'> diff --git a/shared/devices/device-icon.tsx b/shared/devices/device-icon.tsx index 0121619b3fd5..cc698e7fe61d 100644 --- a/shared/devices/device-icon.tsx +++ b/shared/devices/device-icon.tsx @@ -1,5 +1,5 @@ -import type * as Provision from '@/constants/provision' -import * as Devices from '@/constants/devices' +import type * as Provision from '@/stores/provision' +import * as Devices from '@/stores/devices' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import type {IconStyle} from '@/common-adapters/icon' diff --git a/shared/devices/device-page.tsx b/shared/devices/device-page.tsx index dff22308c890..f270c62a1b27 100644 --- a/shared/devices/device-page.tsx +++ b/shared/devices/device-page.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Devices from '@/constants/devices' +import * as Devices from '@/stores/devices' import * as Kb from '@/common-adapters' import * as React from 'react' import type * as T from '@/constants/types' diff --git a/shared/devices/device-revoke.tsx b/shared/devices/device-revoke.tsx index 0d4ead70adde..90e0850a35fe 100644 --- a/shared/devices/device-revoke.tsx +++ b/shared/devices/device-revoke.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import {useConfigState} from '@/constants/config' -import * as Devices from '@/constants/devices' +import {useConfigState} from '@/stores/config' +import * as Devices from '@/stores/devices' import * as Kb from '@/common-adapters' import * as React from 'react' import * as T from '@/constants/types' -import {settingsDevicesTab} from '@/constants/settings' -import {useCurrentUserState} from '@/constants/current-user' +import {settingsDevicesTab} from '@/stores/settings' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {deviceID: string} diff --git a/shared/devices/index.tsx b/shared/devices/index.tsx index ebef2b008e50..4df196248347 100644 --- a/shared/devices/index.tsx +++ b/shared/devices/index.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Devices from '@/constants/devices' +import * as Devices from '@/stores/devices' import * as Kb from '@/common-adapters' import * as React from 'react' import DeviceRow, {NewContext} from './row' diff --git a/shared/devices/nav-header.tsx b/shared/devices/nav-header.tsx index 2176976bb9c3..66506b11fbe8 100644 --- a/shared/devices/nav-header.tsx +++ b/shared/devices/nav-header.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' -import type * as DevicesType from '@/constants/devices' +import type * as DevicesType from '@/stores/devices' import * as Kb from '@/common-adapters' import * as React from 'react' export const HeaderTitle = () => { - const Devices = require('@/constants/devices') as typeof DevicesType + const Devices = require('@/stores/devices') as typeof DevicesType const numActive = Devices.useActiveDeviceCounts() const numRevoked = Devices.useRevokedDeviceCounts() return ( diff --git a/shared/devices/row.tsx b/shared/devices/row.tsx index 5a384bbb9d81..3817ce3ef759 100644 --- a/shared/devices/row.tsx +++ b/shared/devices/row.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Devices from '@/constants/devices' +import * as Devices from '@/stores/devices' import * as Kb from '@/common-adapters' import * as React from 'react' import DeviceIcon from './device-icon' diff --git a/shared/fs/banner/conflict-banner.tsx b/shared/fs/banner/conflict-banner.tsx index 09898a2b91e6..c39440d9d96c 100644 --- a/shared/fs/banner/conflict-banner.tsx +++ b/shared/fs/banner/conflict-banner.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import openUrl from '@/util/open-url' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type OwnProps = { path: T.FS.Path diff --git a/shared/fs/banner/public-reminder.tsx b/shared/fs/banner/public-reminder.tsx index 16783c602a96..717e78175cf4 100644 --- a/shared/fs/banner/public-reminder.tsx +++ b/shared/fs/banner/public-reminder.tsx @@ -1,8 +1,8 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type Props = { path: T.FS.Path diff --git a/shared/fs/banner/reset-banner.tsx b/shared/fs/banner/reset-banner.tsx index 91e09bfd1b13..ab2366b4175d 100644 --- a/shared/fs/banner/reset-banner.tsx +++ b/shared/fs/banner/reset-banner.tsx @@ -4,10 +4,10 @@ import * as T from '@/constants/types' import {folderNameWithoutUsers} from '@/util/kbfs' import * as Kb from '@/common-adapters' import * as RowTypes from '@/fs/browser/rows/types' -import {useTrackerState} from '@/constants/tracker2' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' -import {useProfileState} from '@/constants/profile' +import {useTrackerState} from '@/stores/tracker2' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' +import {useProfileState} from '@/stores/profile' type OwnProps = {path: T.FS.Path} diff --git a/shared/fs/banner/system-file-manager-integration-banner/container.tsx b/shared/fs/banner/system-file-manager-integration-banner/container.tsx index 02877de920b0..0114e131cbad 100644 --- a/shared/fs/banner/system-file-manager-integration-banner/container.tsx +++ b/shared/fs/banner/system-file-manager-integration-banner/container.tsx @@ -3,8 +3,8 @@ import * as C from '@/constants' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import * as Kbfs from '@/fs/common' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type OwnProps = {alwaysShow?: boolean} diff --git a/shared/fs/banner/system-file-manager-integration-banner/kext-permission-popup.tsx b/shared/fs/banner/system-file-manager-integration-banner/kext-permission-popup.tsx index 759aa1d2fe21..7898cf2ca82c 100644 --- a/shared/fs/banner/system-file-manager-integration-banner/kext-permission-popup.tsx +++ b/shared/fs/banner/system-file-manager-integration-banner/kext-permission-popup.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import * as C from '@/constants' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' const InstallSecurityPrefs = () => { const driverStatus = useFSState(s => s.sfmi.driverStatus) diff --git a/shared/fs/browser/destination-picker.tsx b/shared/fs/browser/destination-picker.tsx index 9a407bb950b8..b00bdd56608b 100644 --- a/shared/fs/browser/destination-picker.tsx +++ b/shared/fs/browser/destination-picker.tsx @@ -8,8 +8,8 @@ import NavHeaderTitle from '@/fs/nav-header/title' import Root from './root' import Rows from './rows/rows-container' import {OriginalOrCompressedButton} from '@/incoming-share' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type OwnProps = {index: number} diff --git a/shared/fs/browser/index.tsx b/shared/fs/browser/index.tsx index c4e8df63334d..b8dff985b6d0 100644 --- a/shared/fs/browser/index.tsx +++ b/shared/fs/browser/index.tsx @@ -10,8 +10,8 @@ import PublicReminder from '../banner/public-reminder' import Root from './root' import Rows from './rows/rows-container' import {asRows as resetBannerAsRows} from '../banner/reset-banner' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type OwnProps = {path: T.FS.Path} diff --git a/shared/fs/browser/offline.tsx b/shared/fs/browser/offline.tsx index 51f045b4fdba..3a3273e64ffe 100644 --- a/shared/fs/browser/offline.tsx +++ b/shared/fs/browser/offline.tsx @@ -1,8 +1,8 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import TopBar from '../top-bar' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type Props = { path: T.FS.Path diff --git a/shared/fs/browser/root.tsx b/shared/fs/browser/root.tsx index af39fbc45ea1..1a1cef90548c 100644 --- a/shared/fs/browser/root.tsx +++ b/shared/fs/browser/root.tsx @@ -5,9 +5,9 @@ import TlfType from './rows/tlf-type' import Tlf from './rows/tlf' import SfmiBanner from '../banner/system-file-manager-integration-banner/container' import {WrapRow} from './rows/rows' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' type Props = { destinationPickerIndex?: number diff --git a/shared/fs/browser/rows/editing.tsx b/shared/fs/browser/rows/editing.tsx index e6e19567d756..99ac037113a7 100644 --- a/shared/fs/browser/rows/editing.tsx +++ b/shared/fs/browser/rows/editing.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {rowStyles} from './common' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type Props = { editID: T.FS.EditID diff --git a/shared/fs/browser/rows/rows-container.tsx b/shared/fs/browser/rows/rows-container.tsx index 9c3852859b96..37019066d45d 100644 --- a/shared/fs/browser/rows/rows-container.tsx +++ b/shared/fs/browser/rows/rows-container.tsx @@ -4,9 +4,9 @@ import * as RowTypes from './types' import {sortRowItems, type SortableRowItem} from './sort' import Rows, {type Props} from './rows' import {asRows as topBarAsRow} from '../../top-bar' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = { path: T.FS.Path // path to the parent folder containering the rows, diff --git a/shared/fs/browser/rows/still.tsx b/shared/fs/browser/rows/still.tsx index c5b1655ff3b4..f0a2ad9abbef 100644 --- a/shared/fs/browser/rows/still.tsx +++ b/shared/fs/browser/rows/still.tsx @@ -4,8 +4,8 @@ import {useOpen} from '@/fs/common/use-open' import {rowStyles, StillCommon} from './common' import * as Kb from '@/common-adapters' import {LastModifiedLine, Filename} from '@/fs/common' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type OwnProps = { destinationPickerIndex?: number diff --git a/shared/fs/browser/rows/tlf-type.tsx b/shared/fs/browser/rows/tlf-type.tsx index 908334f54352..e60d181d6f39 100644 --- a/shared/fs/browser/rows/tlf-type.tsx +++ b/shared/fs/browser/rows/tlf-type.tsx @@ -1,6 +1,6 @@ import * as T from '@/constants/types' import {useOpen} from '@/fs/common/use-open' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' import {rowStyles, StillCommon} from './common' import * as Kb from '@/common-adapters' diff --git a/shared/fs/browser/rows/tlf.tsx b/shared/fs/browser/rows/tlf.tsx index 001ba2b64cdd..1092deddbaff 100644 --- a/shared/fs/browser/rows/tlf.tsx +++ b/shared/fs/browser/rows/tlf.tsx @@ -3,9 +3,9 @@ import {useOpen} from '@/fs/common/use-open' import {rowStyles, StillCommon} from './common' import * as Kb from '@/common-adapters' import {useFsPathMetadata, TlfInfoLine, Filename} from '@/fs/common' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' export type OwnProps = { destinationPickerIndex?: number diff --git a/shared/fs/common/errs-container.tsx b/shared/fs/common/errs-container.tsx index 7e86e484dd46..ae768869412a 100644 --- a/shared/fs/common/errs-container.tsx +++ b/shared/fs/common/errs-container.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as C from '@/constants' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' const ErrsContainer = () => { const {_errors, _dismiss} = useFSState( diff --git a/shared/fs/common/folder-view-filter-icon.tsx b/shared/fs/common/folder-view-filter-icon.tsx index a843e380bf81..135aff8989f2 100644 --- a/shared/fs/common/folder-view-filter-icon.tsx +++ b/shared/fs/common/folder-view-filter-icon.tsx @@ -1,8 +1,8 @@ import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import type * as Styles from '@/styles' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type Props = { onClick: () => void diff --git a/shared/fs/common/folder-view-filter.tsx b/shared/fs/common/folder-view-filter.tsx index 7cf7dc787a71..45e1c6d835da 100644 --- a/shared/fs/common/folder-view-filter.tsx +++ b/shared/fs/common/folder-view-filter.tsx @@ -3,8 +3,8 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as React from 'react' import debounce from 'lodash/debounce' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type Props = { onCancel?: () => void diff --git a/shared/fs/common/hooks.tsx b/shared/fs/common/hooks.tsx index be2ac0bcaa39..95edbb6d8778 100644 --- a/shared/fs/common/hooks.tsx +++ b/shared/fs/common/hooks.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import logger from '@/logger' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' const isPathItem = (path: T.FS.Path) => T.FS.getPathLevel(path) > 2 || FS.hasSpecialFileElement(path) diff --git a/shared/fs/common/item-icon.tsx b/shared/fs/common/item-icon.tsx index 303b8e533dc2..8b0d42789caf 100644 --- a/shared/fs/common/item-icon.tsx +++ b/shared/fs/common/item-icon.tsx @@ -1,8 +1,8 @@ import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import type {IconType} from '@/common-adapters/icon' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' export type Size = 96 | 48 | 32 | 16 type SizeString = '96' | '48' | '32' | '16' diff --git a/shared/fs/common/kbfs-path.tsx b/shared/fs/common/kbfs-path.tsx index bc000fb40d44..847405ef0104 100644 --- a/shared/fs/common/kbfs-path.tsx +++ b/shared/fs/common/kbfs-path.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' import PathInfo from './path-info' import PathItemInfo from './path-item-info' diff --git a/shared/fs/common/last-modified-line.tsx b/shared/fs/common/last-modified-line.tsx index 7a8d7893f508..a11c6be3625f 100644 --- a/shared/fs/common/last-modified-line.tsx +++ b/shared/fs/common/last-modified-line.tsx @@ -1,8 +1,8 @@ import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import {formatTimeForFS} from '@/util/timestamp' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' export type OwnProps = { path: T.FS.Path diff --git a/shared/fs/common/open-in-system-file-manager.tsx b/shared/fs/common/open-in-system-file-manager.tsx index 42758a5a7420..c45d43352971 100644 --- a/shared/fs/common/open-in-system-file-manager.tsx +++ b/shared/fs/common/open-in-system-file-manager.tsx @@ -3,7 +3,7 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import * as C from '@/constants' import SystemFileManagerIntegrationPopup from './sfmi-popup' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' type Props = {path: T.FS.Path} diff --git a/shared/fs/common/path-info.tsx b/shared/fs/common/path-info.tsx index 16e0f1ef9d51..25182ab0625a 100644 --- a/shared/fs/common/path-info.tsx +++ b/shared/fs/common/path-info.tsx @@ -1,8 +1,8 @@ import * as T from '@/constants/types' import {useFsPathInfo} from './hooks' import * as Kb from '@/common-adapters' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type PathInfoProps = { containerStyle?: Kb.Styles.StylesCrossPlatform diff --git a/shared/fs/common/path-item-action/choose-view.tsx b/shared/fs/common/path-item-action/choose-view.tsx index 7029ddf85d26..23421a3c10cd 100644 --- a/shared/fs/common/path-item-action/choose-view.tsx +++ b/shared/fs/common/path-item-action/choose-view.tsx @@ -2,7 +2,7 @@ import * as T from '@/constants/types' import type {FloatingMenuProps} from './types' import Menu from './menu-container' import Confirm from './confirm' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' type OwnProps = { floatingMenuProps: FloatingMenuProps diff --git a/shared/fs/common/path-item-action/confirm-delete.tsx b/shared/fs/common/path-item-action/confirm-delete.tsx index fbc3d3afe1aa..d47af5f53184 100644 --- a/shared/fs/common/path-item-action/confirm-delete.tsx +++ b/shared/fs/common/path-item-action/confirm-delete.tsx @@ -2,8 +2,8 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import * as C from '@/constants' import * as React from 'react' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' export type Props = { onBack: () => void diff --git a/shared/fs/common/path-item-action/confirm.tsx b/shared/fs/common/path-item-action/confirm.tsx index 73e19306d67c..c3fb1a363ea6 100644 --- a/shared/fs/common/path-item-action/confirm.tsx +++ b/shared/fs/common/path-item-action/confirm.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import * as T from '@/constants/types' import type {FloatingMenuProps} from './types' import * as Kb from '@/common-adapters' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type OwnProps = { floatingMenuProps: FloatingMenuProps diff --git a/shared/fs/common/path-item-action/index.tsx b/shared/fs/common/path-item-action/index.tsx index 46087ca280e2..00c24879ddbb 100644 --- a/shared/fs/common/path-item-action/index.tsx +++ b/shared/fs/common/path-item-action/index.tsx @@ -4,8 +4,8 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import ChooseView from './choose-view' import type {SizeType} from '@/common-adapters/icon' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' export type ClickableProps = { onClick: () => void diff --git a/shared/fs/common/path-item-action/layout.tsx b/shared/fs/common/path-item-action/layout.tsx index ec63a3a52b64..89a91060c446 100644 --- a/shared/fs/common/path-item-action/layout.tsx +++ b/shared/fs/common/path-item-action/layout.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as T from '@/constants/types' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' export type Layout = { archive: boolean diff --git a/shared/fs/common/path-item-action/menu-container.tsx b/shared/fs/common/path-item-action/menu-container.tsx index 996f366ea73c..9a7e2f751dd5 100644 --- a/shared/fs/common/path-item-action/menu-container.tsx +++ b/shared/fs/common/path-item-action/menu-container.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as Kbfs from '@/fs/common/hooks' import * as React from 'react' @@ -8,9 +8,9 @@ import * as Util from '@/util/kbfs' import Header from './header' import type {FloatingMenuProps} from './types' import {getRootLayout, getShareLayout} from './layout' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = { floatingMenuProps: FloatingMenuProps diff --git a/shared/fs/common/path-item-info.tsx b/shared/fs/common/path-item-info.tsx index 75d4bc69fb06..bd9d22d388f1 100644 --- a/shared/fs/common/path-item-info.tsx +++ b/shared/fs/common/path-item-info.tsx @@ -6,8 +6,8 @@ import ItemIcon from './item-icon' import CommaSeparatedName from './comma-separated-name' import {pluralize} from '@/util/string' import {useFsChildren, useFsPathMetadata, useFsOnlineStatus, useFsSoftError} from './hooks' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type Props = { containerStyle?: Kb.Styles.StylesCrossPlatform diff --git a/shared/fs/common/path-status-icon-container.tsx b/shared/fs/common/path-status-icon-container.tsx index 9a1440a507e2..0e6cb624b358 100644 --- a/shared/fs/common/path-status-icon-container.tsx +++ b/shared/fs/common/path-status-icon-container.tsx @@ -1,8 +1,8 @@ import * as T from '@/constants/types' import * as C from '@/constants' import PathStatusIcon from './path-status-icon' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type OwnPropsPathItem = { path: T.FS.Path diff --git a/shared/fs/common/refresh-driver-status-on-mount.tsx b/shared/fs/common/refresh-driver-status-on-mount.tsx index 9ce3cc4d12d5..c4739b49fa67 100644 --- a/shared/fs/common/refresh-driver-status-on-mount.tsx +++ b/shared/fs/common/refresh-driver-status-on-mount.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' const RefreshDriverStatusOnMount = () => { const refreshDriverStatusDesktop = useFSState(s => s.dispatch.dynamic.refreshDriverStatusDesktop) diff --git a/shared/fs/common/sfmi-popup.tsx b/shared/fs/common/sfmi-popup.tsx index 9fbf8764643b..33aa3bbe952b 100644 --- a/shared/fs/common/sfmi-popup.tsx +++ b/shared/fs/common/sfmi-popup.tsx @@ -3,7 +3,7 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import {useFuseClosedSourceConsent} from './hooks' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' type Props = { mode: 'Icon' | 'Button' diff --git a/shared/fs/common/tlf-info-line-container.tsx b/shared/fs/common/tlf-info-line-container.tsx index 8b84d8962edd..09803b935e53 100644 --- a/shared/fs/common/tlf-info-line-container.tsx +++ b/shared/fs/common/tlf-info-line-container.tsx @@ -1,8 +1,8 @@ import * as T from '@/constants/types' import TlfInfoLine from './tlf-info-line' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' export type OwnProps = { path: T.FS.Path diff --git a/shared/fs/common/upload-button.tsx b/shared/fs/common/upload-button.tsx index 593688df6905..c335b8e84126 100644 --- a/shared/fs/common/upload-button.tsx +++ b/shared/fs/common/upload-button.tsx @@ -3,8 +3,8 @@ import * as T from '@/constants/types' import * as C from '@/constants' import * as Kb from '@/common-adapters' import type * as Styles from '@/styles' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type OwnProps = { path: T.FS.Path diff --git a/shared/fs/common/use-open.tsx b/shared/fs/common/use-open.tsx index 0e15b1719686..74a9ea2be194 100644 --- a/shared/fs/common/use-open.tsx +++ b/shared/fs/common/use-open.tsx @@ -1,8 +1,8 @@ import * as C from '@/constants' import * as T from '@/constants/types' import {useSafeNavigation} from '@/util/safe-navigation' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type Props = { path: T.FS.Path diff --git a/shared/fs/filepreview/bare-preview.tsx b/shared/fs/filepreview/bare-preview.tsx index bcbe04f750c7..f9d95b402178 100644 --- a/shared/fs/filepreview/bare-preview.tsx +++ b/shared/fs/filepreview/bare-preview.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' import Footer from '../footer/footer' import View from './view' import * as Kbfs from '../common' diff --git a/shared/fs/filepreview/default-view.tsx b/shared/fs/filepreview/default-view.tsx index 41d252be7d54..70b01d0109ac 100644 --- a/shared/fs/filepreview/default-view.tsx +++ b/shared/fs/filepreview/default-view.tsx @@ -3,8 +3,8 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import {PathItemAction, LastModifiedLine, ItemIcon, type ClickableProps} from '../common' import {hasShare} from '../common/path-item-action/layout' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' type OwnProps = {path: T.FS.Path} diff --git a/shared/fs/filepreview/view.tsx b/shared/fs/filepreview/view.tsx index 2765510266e7..aad5f4757683 100644 --- a/shared/fs/filepreview/view.tsx +++ b/shared/fs/filepreview/view.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as T from '@/constants/types' import DefaultView from './default-view' @@ -7,8 +7,8 @@ import TextView from './text-view' import AVView from './av-view' import PdfView from './pdf-view' import * as Kb from '@/common-adapters' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' type Props = { path: T.FS.Path diff --git a/shared/fs/footer/download.tsx b/shared/fs/footer/download.tsx index 3d2177cbd799..062e69bc0a46 100644 --- a/shared/fs/footer/download.tsx +++ b/shared/fs/footer/download.tsx @@ -4,8 +4,8 @@ import * as C from '@/constants' import * as T from '@/constants/types' import DownloadWrapper from './download-wrapper' import {formatDurationFromNowTo} from '@/util/timestamp' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' export type Props = { downloadID: string diff --git a/shared/fs/footer/downloads.tsx b/shared/fs/footer/downloads.tsx index 7983b96c0020..bee401a9f534 100644 --- a/shared/fs/footer/downloads.tsx +++ b/shared/fs/footer/downloads.tsx @@ -2,7 +2,7 @@ import * as Kb from '@/common-adapters' import * as C from '@/constants' import * as Kbfs from '../common' import Download from './download' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' const Mobile = () => { Kbfs.useFsDownloadStatus() diff --git a/shared/fs/footer/proof-broken.tsx b/shared/fs/footer/proof-broken.tsx index 186b5106bb28..852d5b5f925d 100644 --- a/shared/fs/footer/proof-broken.tsx +++ b/shared/fs/footer/proof-broken.tsx @@ -1,7 +1,7 @@ import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' -import * as FS from '@/constants/fs' -import {useUsersState} from '@/constants/users' +import * as FS from '@/stores/fs' +import {useUsersState} from '@/stores/users' type Props = {path: T.FS.Path} diff --git a/shared/fs/footer/upload-container.tsx b/shared/fs/footer/upload-container.tsx index 73bfd3b2d3ef..31193f51a235 100644 --- a/shared/fs/footer/upload-container.tsx +++ b/shared/fs/footer/upload-container.tsx @@ -2,8 +2,8 @@ import * as T from '@/constants/types' import Upload from './upload' import {useUploadCountdown} from './use-upload-countdown' import * as C from '@/constants' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' // NOTE flip this to show a button to debug the upload banner animations. const enableDebugUploadBanner = false as boolean diff --git a/shared/fs/index.tsx b/shared/fs/index.tsx index 304ce8342ced..78fa22597830 100644 --- a/shared/fs/index.tsx +++ b/shared/fs/index.tsx @@ -5,8 +5,8 @@ import Browser from './browser' import {NormalPreview} from './filepreview' import * as Kbfs from './common' import * as SimpleScreens from './simple-screens' -import {useFSState} from '@/constants/fs' -import * as FS from '@/constants/fs' +import {useFSState} from '@/stores/fs' +import * as FS from '@/stores/fs' type ChooseComponentProps = { emitBarePreview: () => void diff --git a/shared/fs/nav-header/actions.tsx b/shared/fs/nav-header/actions.tsx index 497c67488b7f..014b0c7e1331 100644 --- a/shared/fs/nav-header/actions.tsx +++ b/shared/fs/nav-header/actions.tsx @@ -3,8 +3,8 @@ import * as T from '@/constants/types' import * as React from 'react' import * as Kb from '@/common-adapters' import * as Kbfs from '../common' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' type Props = { onTriggerFilterMobile: () => void diff --git a/shared/fs/nav-header/main-banner.tsx b/shared/fs/nav-header/main-banner.tsx index 73150635e474..4c24a1390ca4 100644 --- a/shared/fs/nav-header/main-banner.tsx +++ b/shared/fs/nav-header/main-banner.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' type Props = { onRetry: () => void diff --git a/shared/fs/nav-header/mobile-header.tsx b/shared/fs/nav-header/mobile-header.tsx index 1364d912bc1c..3868d0e25ba9 100644 --- a/shared/fs/nav-header/mobile-header.tsx +++ b/shared/fs/nav-header/mobile-header.tsx @@ -5,8 +5,8 @@ import * as Kbfs from '../common' import type * as T from '@/constants/types' import Actions from './actions' import MainBanner from './main-banner' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' /* * diff --git a/shared/fs/nav-header/title.tsx b/shared/fs/nav-header/title.tsx index a1419632345f..1bcb3e156a77 100644 --- a/shared/fs/nav-header/title.tsx +++ b/shared/fs/nav-header/title.tsx @@ -3,7 +3,7 @@ import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import * as Kbfs from '../common' import {useSafeNavigation} from '@/util/safe-navigation' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' type Props = { path: T.FS.Path diff --git a/shared/fs/routes.tsx b/shared/fs/routes.tsx index f96c5d4f17c3..f9d6796ef092 100644 --- a/shared/fs/routes.tsx +++ b/shared/fs/routes.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as T from '@/constants/types' import * as C from '@/constants' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' import {Actions, MainBanner, MobileHeader, Title} from './nav-header' const FsRoot = React.lazy(async () => import('.')) diff --git a/shared/fs/top-bar/loading.tsx b/shared/fs/top-bar/loading.tsx index 1aee292386c8..214ecb0a9539 100644 --- a/shared/fs/top-bar/loading.tsx +++ b/shared/fs/top-bar/loading.tsx @@ -1,8 +1,8 @@ import * as T from '@/constants/types' import * as C from '@/constants' import * as Kb from '@/common-adapters' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' // The behavior is to only show spinner when user first time lands on a screen // and when don't have the data that drives it yet. Since RPCs happen diff --git a/shared/fs/top-bar/sort.tsx b/shared/fs/top-bar/sort.tsx index f2057895d10f..30db41b3f6be 100644 --- a/shared/fs/top-bar/sort.tsx +++ b/shared/fs/top-bar/sort.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as T from '@/constants/types' import * as React from 'react' import * as Kb from '@/common-adapters' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' type OwnProps = { path: T.FS.Path diff --git a/shared/fs/top-bar/sync-toggle.tsx b/shared/fs/top-bar/sync-toggle.tsx index 437300313c8d..cdc1e573a46d 100644 --- a/shared/fs/top-bar/sync-toggle.tsx +++ b/shared/fs/top-bar/sync-toggle.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as T from '@/constants/types' import * as React from 'react' import * as Kb from '@/common-adapters' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' type OwnProps = { tlfPath: T.FS.Path diff --git a/shared/git/delete-repo.tsx b/shared/git/delete-repo.tsx index 88b1804a1f83..1be08287171f 100644 --- a/shared/git/delete-repo.tsx +++ b/shared/git/delete-repo.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as React from 'react' -import * as Git from '@/constants/git' +import * as Git from '@/stores/git' type OwnProps = {id: string} diff --git a/shared/git/index.tsx b/shared/git/index.tsx index 168a9715ed72..aaf29607752f 100644 --- a/shared/git/index.tsx +++ b/shared/git/index.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Git from '@/constants/git' +import * as Git from '@/stores/git' import * as Kb from '@/common-adapters' import * as React from 'react' import Row, {NewContext} from './row' diff --git a/shared/git/nav-header.tsx b/shared/git/nav-header.tsx index 5dafe65dd6ca..26d239bb94c9 100644 --- a/shared/git/nav-header.tsx +++ b/shared/git/nav-header.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Git from '@/constants/git' +import * as Git from '@/stores/git' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/git/new-repo.tsx b/shared/git/new-repo.tsx index fd7ded7e79f5..2672731dc6a7 100644 --- a/shared/git/new-repo.tsx +++ b/shared/git/new-repo.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as Git from '@/constants/git' -import * as Teams from '@/constants/teams' +import * as Git from '@/stores/git' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as React from 'react' diff --git a/shared/git/row.tsx b/shared/git/row.tsx index 4402b545eb79..7151506dfb61 100644 --- a/shared/git/row.tsx +++ b/shared/git/row.tsx @@ -1,13 +1,13 @@ import * as C from '@/constants' -import * as Git from '@/constants/git' -import * as Teams from '@/constants/teams' +import * as Git from '@/stores/git' +import * as Teams from '@/stores/teams' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import * as React from 'react' import openURL from '@/util/open-url' -import {useTrackerState} from '@/constants/tracker2' -import * as FS from '@/constants/fs' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import * as FS from '@/stores/fs' +import {useCurrentUserState} from '@/stores/current-user' export const NewContext = React.createContext>(new Set()) diff --git a/shared/git/select-channel.tsx b/shared/git/select-channel.tsx index a2cee7e5f3cb..a4b40c3af1af 100644 --- a/shared/git/select-channel.tsx +++ b/shared/git/select-channel.tsx @@ -1,5 +1,5 @@ -import * as Git from '@/constants/git' -import * as Teams from '@/constants/teams' +import * as Git from '@/stores/git' +import * as Teams from '@/stores/teams' import {useSafeNavigation} from '@/util/safe-navigation' import * as Kb from '@/common-adapters' import * as React from 'react' diff --git a/shared/incoming-share/index.tsx b/shared/incoming-share/index.tsx index 610c72636a1c..331def063e5f 100644 --- a/shared/incoming-share/index.tsx +++ b/shared/incoming-share/index.tsx @@ -4,10 +4,10 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import * as FsCommon from '@/fs/common' import {MobileSendToChat} from '../chat/send-to-chat' -import {settingsFeedbackTab} from '@/constants/settings' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' -import {useConfigState} from '@/constants/config' +import {settingsFeedbackTab} from '@/stores/settings' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' +import {useConfigState} from '@/stores/config' export const OriginalOrCompressedButton = ({incomingShareItems}: IncomingShareProps) => { const originalTotalSize = incomingShareItems.reduce((bytes, item) => bytes + (item.originalSize ?? 0), 0) diff --git a/shared/login/index.tsx b/shared/login/index.tsx index cd680fd69a09..1c052d3559d0 100644 --- a/shared/login/index.tsx +++ b/shared/login/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import {useConfigState} from '@/constants/config' -import {useDaemonState} from '@/constants/daemon' +import {useConfigState} from '@/stores/config' +import {useDaemonState} from '@/stores/daemon' const Loading = React.lazy(async () => import('./loading')) const Relogin = React.lazy(async () => import('./relogin/container')) diff --git a/shared/login/join-or-login.tsx b/shared/login/join-or-login.tsx index 543fb0be1d2c..0e4b0c267713 100644 --- a/shared/login/join-or-login.tsx +++ b/shared/login/join-or-login.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' import * as React from 'react' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import * as Kb from '@/common-adapters' import {InfoIcon} from '@/signup/common' -import {useSignupState} from '@/constants/signup' -import {useProvisionState} from '@/constants/provision' +import {useSignupState} from '@/stores/signup' +import {useProvisionState} from '@/stores/provision' const Intro = () => { const justDeletedSelf = useConfigState(s => s.justDeletedSelf) diff --git a/shared/login/loading.tsx b/shared/login/loading.tsx index 7d48b3dec130..41237f127c88 100644 --- a/shared/login/loading.tsx +++ b/shared/login/loading.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' -import {useDaemonState} from '@/constants/daemon' +import {useDaemonState} from '@/stores/daemon' const SplashContainer = () => { const failedReason = useDaemonState(s => s.handshakeFailedReason) diff --git a/shared/login/recover-password/device-selector.tsx b/shared/login/recover-password/device-selector.tsx index 150fb2d21f5a..e73f81372b15 100644 --- a/shared/login/recover-password/device-selector.tsx +++ b/shared/login/recover-password/device-selector.tsx @@ -1,5 +1,5 @@ import SelectOtherDevice from '@/provision/select-other-device' -import {useState as useRecoverState} from '@/constants/recover-password' +import {useState as useRecoverState} from '@/stores/recover-password' const RecoverPasswordDeviceSelector = () => { const devices = useRecoverState(s => s.devices) diff --git a/shared/login/recover-password/error-modal.tsx b/shared/login/recover-password/error-modal.tsx index efe62179c6c4..14cb7f80d1e5 100644 --- a/shared/login/recover-password/error-modal.tsx +++ b/shared/login/recover-password/error-modal.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import {useState as useRecoverState} from '@/constants/recover-password' -import {useConfigState} from '@/constants/config' +import {useState as useRecoverState} from '@/stores/recover-password' +import {useConfigState} from '@/stores/config' const styles = Kb.Styles.styleSheetCreate(() => ({ padding: { diff --git a/shared/login/recover-password/error.tsx b/shared/login/recover-password/error.tsx index 789cbf323102..c38307524d2e 100644 --- a/shared/login/recover-password/error.tsx +++ b/shared/login/recover-password/error.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import type {ButtonType} from '@/common-adapters/button' import {SignupScreen} from '@/signup/common' -import {useState as useRecoverState} from '@/constants/recover-password' -import {useConfigState} from '@/constants/config' +import {useState as useRecoverState} from '@/stores/recover-password' +import {useConfigState} from '@/stores/config' const ConnectedError = () => { const loggedIn = useConfigState(s => s.loggedIn) diff --git a/shared/login/recover-password/explain-device.tsx b/shared/login/recover-password/explain-device.tsx index 06890c97dab8..f9bd16930337 100644 --- a/shared/login/recover-password/explain-device.tsx +++ b/shared/login/recover-password/explain-device.tsx @@ -3,7 +3,7 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import type {ButtonType} from '@/common-adapters/button' import {SignupScreen} from '@/signup/common' -import {useState as useRecoverState} from '@/constants/recover-password' +import {useState as useRecoverState} from '@/stores/recover-password' const ConnectedExplainDevice = () => { const ed = useRecoverState(s => s.explainedDevice) diff --git a/shared/login/recover-password/paper-key.tsx b/shared/login/recover-password/paper-key.tsx index 5e2a332af6d9..9d1983af7a1d 100644 --- a/shared/login/recover-password/paper-key.tsx +++ b/shared/login/recover-password/paper-key.tsx @@ -3,7 +3,7 @@ import * as Kb from '@/common-adapters' import * as React from 'react' import type {ButtonType} from '@/common-adapters/button' import {SignupScreen} from '@/signup/common' -import {useState as useRecoverState} from '@/constants/recover-password' +import {useState as useRecoverState} from '@/stores/recover-password' const PaperKey = () => { const error = useRecoverState(s => s.paperKeyError) diff --git a/shared/login/recover-password/password.tsx b/shared/login/recover-password/password.tsx index 452ca011543a..2e61426b7edc 100644 --- a/shared/login/recover-password/password.tsx +++ b/shared/login/recover-password/password.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import {UpdatePassword} from '@/settings/password' -import {useState as useRecoverState} from '@/constants/recover-password' +import {useState as useRecoverState} from '@/stores/recover-password' const Password = () => { const error = useRecoverState(s => s.passwordError) diff --git a/shared/login/recover-password/prompt-reset-shared.tsx b/shared/login/recover-password/prompt-reset-shared.tsx index da223aa06338..dff66e082417 100644 --- a/shared/login/recover-password/prompt-reset-shared.tsx +++ b/shared/login/recover-password/prompt-reset-shared.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' -import * as AutoReset from '@/constants/autoreset' +import * as AutoReset from '@/stores/autoreset' import * as React from 'react' import * as Kb from '@/common-adapters' import {useSafeNavigation} from '@/util/safe-navigation' import * as T from '@/constants/types' import {SignupScreen} from '@/signup/common' import type {ButtonType} from '@/common-adapters/button' -import {useState as useRecoverState} from '@/constants/recover-password' +import {useState as useRecoverState} from '@/stores/recover-password' export type Props = { resetPassword?: boolean diff --git a/shared/login/relogin/container.tsx b/shared/login/relogin/container.tsx index 2e80b7856bc6..ee18a0195aa3 100644 --- a/shared/login/relogin/container.tsx +++ b/shared/login/relogin/container.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' import * as React from 'react' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import Login from '.' import sortBy from 'lodash/sortBy' -import {useState as useRecoverState} from '@/constants/recover-password' -import {useSignupState} from '@/constants/signup' -import {useProvisionState} from '@/constants/provision' +import {useState as useRecoverState} from '@/stores/recover-password' +import {useSignupState} from '@/stores/signup' +import {useProvisionState} from '@/stores/provision' const needPasswordError = 'passphrase cannot be empty' diff --git a/shared/login/reset/confirm.tsx b/shared/login/reset/confirm.tsx index 5ce7f9b7d53e..e8a22339520d 100644 --- a/shared/login/reset/confirm.tsx +++ b/shared/login/reset/confirm.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' -import * as AutoReset from '@/constants/autoreset' +import * as AutoReset from '@/stores/autoreset' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import {useState as useRecoverState} from '@/constants/recover-password' +import {useState as useRecoverState} from '@/stores/recover-password' const ConfirmReset = () => { const hasWallet = AutoReset.useAutoResetState(s => s.hasWallet) diff --git a/shared/login/reset/modal.tsx b/shared/login/reset/modal.tsx index 3aa3e2b5ef66..9e3e48bd8db4 100644 --- a/shared/login/reset/modal.tsx +++ b/shared/login/reset/modal.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as AutoReset from '@/constants/autoreset' +import * as AutoReset from '@/stores/autoreset' import * as React from 'react' import * as Kb from '@/common-adapters' import {formatDurationForAutoreset} from '@/util/timestamp' diff --git a/shared/login/reset/password-enter.tsx b/shared/login/reset/password-enter.tsx index c749c5f801e6..010a4cdaf290 100644 --- a/shared/login/reset/password-enter.tsx +++ b/shared/login/reset/password-enter.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as AutoReset from '@/constants/autoreset' +import * as AutoReset from '@/stores/autoreset' import * as React from 'react' import * as Kb from '@/common-adapters' import {SignupScreen} from '@/signup/common' diff --git a/shared/login/reset/password-known.tsx b/shared/login/reset/password-known.tsx index c606206718b4..f955e6b7d183 100644 --- a/shared/login/reset/password-known.tsx +++ b/shared/login/reset/password-known.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as AutoReset from '@/constants/autoreset' +import * as AutoReset from '@/stores/autoreset' import * as React from 'react' import * as Kb from '@/common-adapters' import {SignupScreen} from '@/signup/common' diff --git a/shared/login/reset/waiting.tsx b/shared/login/reset/waiting.tsx index 9dea7f219397..adf2b26d7ace 100644 --- a/shared/login/reset/waiting.tsx +++ b/shared/login/reset/waiting.tsx @@ -3,7 +3,7 @@ import * as Kb from '@/common-adapters' import {SignupScreen} from '@/signup/common' import {addTicker, removeTicker} from '@/util/second-timer' import * as C from '@/constants' -import * as AutoReset from '@/constants/autoreset' +import * as AutoReset from '@/stores/autoreset' import {useSafeNavigation} from '@/util/safe-navigation' import {formatDurationForAutoreset as formatDuration} from '@/util/timestamp' diff --git a/shared/login/signup/error.tsx b/shared/login/signup/error.tsx index f646b1337698..04ff47e90e7b 100644 --- a/shared/login/signup/error.tsx +++ b/shared/login/signup/error.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import {Wrapper, ContinueButton} from './common' -import {useSignupState} from '@/constants/signup' +import {useSignupState} from '@/stores/signup' const ConnectedSignupError = () => { const error = useSignupState(s => s.signupError) diff --git a/shared/menubar/chat-container.desktop.tsx b/shared/menubar/chat-container.desktop.tsx index e00fdc6bc561..6bcff1bb9438 100644 --- a/shared/menubar/chat-container.desktop.tsx +++ b/shared/menubar/chat-container.desktop.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as R from '@/constants/remote' import * as RemoteGen from '../actions/remote-gen' import * as Kb from '@/common-adapters' diff --git a/shared/menubar/files-container.desktop.tsx b/shared/menubar/files-container.desktop.tsx index 773a166b515b..aea7e75c0361 100644 --- a/shared/menubar/files-container.desktop.tsx +++ b/shared/menubar/files-container.desktop.tsx @@ -1,4 +1,4 @@ -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as R from '@/constants/remote' import * as T from '@/constants/types' import * as RemoteGen from '../actions/remote-gen' @@ -6,7 +6,7 @@ import * as FsUtil from '@/util/kbfs' import * as TimestampUtil from '@/util/timestamp' import {FilesPreview} from './files.desktop' import type {DeserializeProps} from './remote-serializer.desktop' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' const FilesContainer = (p: Pick) => { const {remoteTlfUpdates} = p diff --git a/shared/menubar/remote-container.desktop.tsx b/shared/menubar/remote-container.desktop.tsx index fa658dbb9793..ed5a78d8ee00 100644 --- a/shared/menubar/remote-container.desktop.tsx +++ b/shared/menubar/remote-container.desktop.tsx @@ -1,14 +1,14 @@ import * as React from 'react' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import Menubar from './index.desktop' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import type {DeserializeProps} from './remote-serializer.desktop' import {useAvatarState} from '@/common-adapters/avatar/store' -import {useUsersState} from '@/constants/users' -import {useFollowerState} from '@/constants/followers' -import {useCurrentUserState} from '@/constants/current-user' -import {useDaemonState} from '@/constants/daemon' -import {useDarkModeState} from '@/constants/darkmode' +import {useUsersState} from '@/stores/users' +import {useFollowerState} from '@/stores/followers' +import {useCurrentUserState} from '@/stores/current-user' +import {useDaemonState} from '@/stores/daemon' +import {useDarkModeState} from '@/stores/darkmode' const RemoteContainer = (d: DeserializeProps) => { const {avatarRefreshCounter, badgeMap, daemonHandshakeState, darkMode, diskSpaceStatus, endEstimate} = d diff --git a/shared/menubar/remote-proxy.desktop.tsx b/shared/menubar/remote-proxy.desktop.tsx index c32e0a8c65e7..4e79d95e0e4e 100644 --- a/shared/menubar/remote-proxy.desktop.tsx +++ b/shared/menubar/remote-proxy.desktop.tsx @@ -1,7 +1,7 @@ // A mirror of the remote menubar windows. import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useConfigState} from '@/constants/config' +import * as Chat from '@/stores/chat2' +import {useConfigState} from '@/stores/config' import * as T from '@/constants/types' import * as React from 'react' import KB2 from '@/util/electron.desktop' @@ -10,16 +10,16 @@ import {intersect} from '@/util/set' import {mapFilterByKey} from '@/util/map' import {serialize, type ProxyProps, type RemoteTlfUpdates} from './remote-serializer.desktop' import {useAvatarState} from '@/common-adapters/avatar/store' -import type * as NotifConstants from '@/constants/notifications' +import type * as NotifConstants from '@/stores/notifications' import {useColorScheme} from 'react-native' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' -import {useFollowerState} from '@/constants/followers' -import {useUsersState} from '@/constants/users' -import {useNotifState} from '@/constants/notifications' -import {useCurrentUserState} from '@/constants/current-user' -import {useDaemonState} from '@/constants/daemon' -import {useDarkModeState} from '@/constants/darkmode' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' +import {useFollowerState} from '@/stores/followers' +import {useUsersState} from '@/stores/users' +import {useNotifState} from '@/stores/notifications' +import {useCurrentUserState} from '@/stores/current-user' +import {useDaemonState} from '@/stores/daemon' +import {useDarkModeState} from '@/stores/darkmode' const {showTray} = KB2.functions diff --git a/shared/people/announcement.tsx b/shared/people/announcement.tsx index 7a6e55dd442c..8e44e7145ec9 100644 --- a/shared/people/announcement.tsx +++ b/shared/people/announcement.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' import openURL from '@/util/open-url' import * as Kb from '@/common-adapters' import PeopleItem from './item' import * as Settings from '@/constants/settings/util' -import {usePeopleState} from '@/constants/people' +import {usePeopleState} from '@/stores/people' type OwnProps = { appLink?: T.RPCGen.AppLinkType diff --git a/shared/people/container.tsx b/shared/people/container.tsx index e1301cfc5f60..3016d4fe3cce 100644 --- a/shared/people/container.tsx +++ b/shared/people/container.tsx @@ -2,10 +2,10 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' import People from '.' -import {useSignupState} from '@/constants/signup' -import {useProfileState} from '@/constants/profile' -import {usePeopleState, getPeopleDataWaitingKey} from '@/constants/people' -import {useCurrentUserState} from '@/constants/current-user' +import {useSignupState} from '@/stores/signup' +import {useProfileState} from '@/stores/profile' +import {usePeopleState, getPeopleDataWaitingKey} from '@/stores/people' +import {useCurrentUserState} from '@/stores/current-user' const waitToRefresh = 1000 * 60 * 5 diff --git a/shared/people/index.shared.tsx b/shared/people/index.shared.tsx index 66edb1f66e6d..e51585aa6339 100644 --- a/shared/people/index.shared.tsx +++ b/shared/people/index.shared.tsx @@ -7,8 +7,8 @@ import FollowNotification from './follow-notification' import FollowSuggestions from './follow-suggestions' import type {Props} from '.' import Todo from './todo' -import {useSignupState} from '@/constants/signup' -import {usePeopleState} from '@/constants/people' +import {useSignupState} from '@/stores/signup' +import {usePeopleState} from '@/stores/people' // import WotTask from './wot-task' const itemToComponent: (item: T.Immutable, props: Props) => React.ReactNode = ( diff --git a/shared/people/routes.tsx b/shared/people/routes.tsx index 1a73b36b39b9..f6c42a6f7051 100644 --- a/shared/people/routes.tsx +++ b/shared/people/routes.tsx @@ -3,7 +3,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import peopleTeamBuilder from '../team-building/page' import ProfileSearch from '../profile/search' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' const HeaderAvatar = () => { const myUsername = useCurrentUserState(s => s.username) diff --git a/shared/people/todo.tsx b/shared/people/todo.tsx index 512f1545b35f..87cafea4576a 100644 --- a/shared/people/todo.tsx +++ b/shared/people/todo.tsx @@ -1,18 +1,18 @@ import * as C from '@/constants' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as React from 'react' import openURL from '@/util/open-url' import type * as T from '@/constants/types' import type {IconType} from '@/common-adapters/icon.constants-gen' import PeopleItem, {type TaskButton} from './item' import * as Kb from '@/common-adapters' -import {useSettingsPhoneState} from '@/constants/settings-phone' -import {useSettingsEmailState} from '@/constants/settings-email' +import {useSettingsPhoneState} from '@/stores/settings-phone' +import {useSettingsEmailState} from '@/stores/settings-email' import {settingsAccountTab, settingsGitTab} from '@/constants/settings/util' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' -import {usePeopleState, todoTypes} from '@/constants/people' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' +import {usePeopleState, todoTypes} from '@/stores/people' +import {useCurrentUserState} from '@/stores/current-user' type TodoOwnProps = { badged: boolean diff --git a/shared/pinentry/remote-container.desktop.tsx b/shared/pinentry/remote-container.desktop.tsx index 97f0967a1e16..316f528a9e14 100644 --- a/shared/pinentry/remote-container.desktop.tsx +++ b/shared/pinentry/remote-container.desktop.tsx @@ -3,7 +3,7 @@ import * as RemoteGen from '../actions/remote-gen' import * as R from '@/constants/remote' import Pinentry from './index.desktop' import type {DeserializeProps} from './remote-serializer.desktop' -import {useDarkModeState} from '@/constants/darkmode' +import {useDarkModeState} from '@/stores/darkmode' const RemoteContainer = (d: DeserializeProps) => { const {darkMode, ...rest} = d diff --git a/shared/pinentry/remote-proxy.desktop.tsx b/shared/pinentry/remote-proxy.desktop.tsx index 587043c04c1d..ea897586694b 100644 --- a/shared/pinentry/remote-proxy.desktop.tsx +++ b/shared/pinentry/remote-proxy.desktop.tsx @@ -6,7 +6,7 @@ import useBrowserWindow from '../desktop/remote/use-browser-window.desktop' import useSerializeProps from '../desktop/remote/use-serialize-props.desktop' import {serialize, type ProxyProps} from './remote-serializer.desktop' import {useColorScheme} from 'react-native' -import {usePinentryState} from '@/constants/pinentry' +import {usePinentryState} from '@/stores/pinentry' const windowOpts = {height: 230, width: 440} diff --git a/shared/pinentry/remote-serializer.desktop.tsx b/shared/pinentry/remote-serializer.desktop.tsx index 96f859f93cce..ca291a3014af 100644 --- a/shared/pinentry/remote-serializer.desktop.tsx +++ b/shared/pinentry/remote-serializer.desktop.tsx @@ -1,5 +1,5 @@ import * as T from '@/constants/types' -import type * as Constants from '@/constants/pinentry' +import type * as Constants from '@/stores/pinentry' import {produce} from 'immer' export type ProxyProps = { diff --git a/shared/profile/add-to-team.tsx b/shared/profile/add-to-team.tsx index a19e220412bc..26ca7d22b19e 100644 --- a/shared/profile/add-to-team.tsx +++ b/shared/profile/add-to-team.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import type * as T from '@/constants/types' import {FloatingRolePicker, sendNotificationFooter} from '@/teams/role-picker' import * as Kb from '@/common-adapters' diff --git a/shared/profile/confirm-or-pending.tsx b/shared/profile/confirm-or-pending.tsx index e0a49954bb5a..f33f9325224e 100644 --- a/shared/profile/confirm-or-pending.tsx +++ b/shared/profile/confirm-or-pending.tsx @@ -1,4 +1,4 @@ -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {subtitle} from '@/util/platforms' diff --git a/shared/profile/edit-avatar/hooks.tsx b/shared/profile/edit-avatar/hooks.tsx index 68e576fc94fb..2455064629a1 100644 --- a/shared/profile/edit-avatar/hooks.tsx +++ b/shared/profile/edit-avatar/hooks.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' -import * as Teams from '@/constants/teams' +import {useProfileState} from '@/stores/profile' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import type {Props} from '.' diff --git a/shared/profile/edit-profile.tsx b/shared/profile/edit-profile.tsx index 61bb397bab2a..c153a4866cf4 100644 --- a/shared/profile/edit-profile.tsx +++ b/shared/profile/edit-profile.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as React from 'react' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' +import {useCurrentUserState} from '@/stores/current-user' const Container = () => { const username = useCurrentUserState(s => s.username) diff --git a/shared/profile/generic/enter-username.tsx b/shared/profile/generic/enter-username.tsx index 41fee450433c..550411e67338 100644 --- a/shared/profile/generic/enter-username.tsx +++ b/shared/profile/generic/enter-username.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import openURL from '@/util/open-url' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/profile/generic/proofs-list.tsx b/shared/profile/generic/proofs-list.tsx index 20c8dae21a8a..ffbfa6fe9f16 100644 --- a/shared/profile/generic/proofs-list.tsx +++ b/shared/profile/generic/proofs-list.tsx @@ -5,8 +5,8 @@ import type * as T from '@/constants/types' import {SiteIcon} from './shared' import {makeInsertMatcher} from '@/util/string' import {useColorScheme} from 'react-native' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' const Container = () => { const _proofSuggestions = useTrackerState(s => s.proofSuggestions) diff --git a/shared/profile/generic/result.tsx b/shared/profile/generic/result.tsx index db0e0b49a419..765700b8b568 100644 --- a/shared/profile/generic/result.tsx +++ b/shared/profile/generic/result.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' import {SiteIcon} from './shared' diff --git a/shared/profile/pgp/finished/index.desktop.tsx b/shared/profile/pgp/finished/index.desktop.tsx index 89e7f6c192cb..22e9341df3e8 100644 --- a/shared/profile/pgp/finished/index.desktop.tsx +++ b/shared/profile/pgp/finished/index.desktop.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as React from 'react' import * as Kb from '@/common-adapters' import Modal from '@/profile/modal' diff --git a/shared/profile/pgp/generate/index.desktop.tsx b/shared/profile/pgp/generate/index.desktop.tsx index ed1be8203b1a..b144be1e0b6b 100644 --- a/shared/profile/pgp/generate/index.desktop.tsx +++ b/shared/profile/pgp/generate/index.desktop.tsx @@ -1,6 +1,6 @@ import * as Kb from '@/common-adapters' import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import Modal from '@/profile/modal' export default function Generate() { diff --git a/shared/profile/pgp/info/index.desktop.tsx b/shared/profile/pgp/info/index.desktop.tsx index af9859070160..8da249f27ec5 100644 --- a/shared/profile/pgp/info/index.desktop.tsx +++ b/shared/profile/pgp/info/index.desktop.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' import Modal from '@/profile/modal' diff --git a/shared/profile/post-proof.tsx b/shared/profile/post-proof.tsx index ddcc5b7e3b1c..7f52f1b555be 100644 --- a/shared/profile/post-proof.tsx +++ b/shared/profile/post-proof.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as React from 'react' import * as Kb from '@/common-adapters' import {subtitle} from '@/util/platforms' import openUrl from '@/util/open-url' import Modal from './modal' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const Container = () => { const platform = useProfileState(s => s.platform) diff --git a/shared/profile/prove-enter-username.tsx b/shared/profile/prove-enter-username.tsx index f64207564d86..5bd8cc0d1398 100644 --- a/shared/profile/prove-enter-username.tsx +++ b/shared/profile/prove-enter-username.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as React from 'react' import * as Kb from '@/common-adapters' import Modal from './modal' diff --git a/shared/profile/prove-website-choice.tsx b/shared/profile/prove-website-choice.tsx index 7eabba0143a9..ff6e664c9f14 100644 --- a/shared/profile/prove-website-choice.tsx +++ b/shared/profile/prove-website-choice.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' import Modal from './modal' diff --git a/shared/profile/revoke.tsx b/shared/profile/revoke.tsx index 5fa5097c28f8..aa34864f41ae 100644 --- a/shared/profile/revoke.tsx +++ b/shared/profile/revoke.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' import capitalize from 'lodash/capitalize' import {subtitle as platformSubtitle} from '@/util/platforms' diff --git a/shared/profile/showcase-team-offer.tsx b/shared/profile/showcase-team-offer.tsx index 0041a0725477..12c43db82598 100644 --- a/shared/profile/showcase-team-offer.tsx +++ b/shared/profile/showcase-team-offer.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import type * as T from '@/constants/types' import {useTeamsSubscribe} from '@/teams/subscriber' -import {useTrackerState} from '@/constants/tracker2' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useCurrentUserState} from '@/stores/current-user' const Container = () => { const waiting = C.useWaitingState(s => s.counts) diff --git a/shared/profile/user/actions/index.tsx b/shared/profile/user/actions/index.tsx index 5695e6e9051c..ff79f621c55e 100644 --- a/shared/profile/user/actions/index.tsx +++ b/shared/profile/user/actions/index.tsx @@ -4,11 +4,11 @@ import * as Kb from '@/common-adapters' import * as React from 'react' import FollowButton from './follow-button' import ChatButton from '@/chat/chat-button' -import {useBotsState} from '@/constants/bots' -import {useTrackerState} from '@/constants/tracker2' -import * as FS from '@/constants/fs' -import {useFollowerState} from '@/constants/followers' -import {useCurrentUserState} from '@/constants/current-user' +import {useBotsState} from '@/stores/bots' +import {useTrackerState} from '@/stores/tracker2' +import * as FS from '@/stores/fs' +import {useFollowerState} from '@/stores/followers' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {username: string} diff --git a/shared/profile/user/friend.tsx b/shared/profile/user/friend.tsx index ef0815a24d86..462965aaa940 100644 --- a/shared/profile/user/friend.tsx +++ b/shared/profile/user/friend.tsx @@ -1,6 +1,6 @@ -import {useProfileState} from '@/constants/profile' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' -import {useUsersState} from '@/constants/users' +import {useUsersState} from '@/stores/users' type OwnProps = { username: string diff --git a/shared/profile/user/hooks.tsx b/shared/profile/user/hooks.tsx index 0a2a49b3017e..b3848ac98bbd 100644 --- a/shared/profile/user/hooks.tsx +++ b/shared/profile/user/hooks.tsx @@ -2,10 +2,10 @@ import * as C from '@/constants' import type * as T from '@/constants/types' import {type BackgroundColorType} from '.' import {useColorScheme} from 'react-native' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' -import {useFollowerState} from '@/constants/followers' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' +import {useFollowerState} from '@/stores/followers' +import {useCurrentUserState} from '@/stores/current-user' const headerBackgroundColorType = ( state: T.Tracker.DetailsState, diff --git a/shared/profile/user/teams/index.tsx b/shared/profile/user/teams/index.tsx index 7cbc8c427ee2..f78cfca43e24 100644 --- a/shared/profile/user/teams/index.tsx +++ b/shared/profile/user/teams/index.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import * as React from 'react' import OpenMeta from './openmeta' import {default as TeamInfo, type Props as TIProps} from './teaminfo' -import {useTrackerState} from '@/constants/tracker2' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {username: string} diff --git a/shared/provision/code-page/container.tsx b/shared/provision/code-page/container.tsx index bc731a76d534..a33c2113e0da 100644 --- a/shared/provision/code-page/container.tsx +++ b/shared/provision/code-page/container.tsx @@ -1,13 +1,13 @@ import * as C from '@/constants' -import * as Devices from '@/constants/devices' +import * as Devices from '@/stores/devices' import * as React from 'react' import * as Kb from '@/common-adapters' import QRImage from './qr-image' import QRScan from './qr-scan' import Troubleshooting from '../troubleshooting' import type * as T from '@/constants/types' -import {useCurrentUserState} from '@/constants/current-user' -import {type Device, useProvisionState} from '@/constants/provision' +import {useCurrentUserState} from '@/stores/current-user' +import {type Device, useProvisionState} from '@/stores/provision' const CodePageContainer = () => { const {deviceID, storeDeviceName} = useCurrentUserState( diff --git a/shared/provision/code-page/qr-scan/hooks.tsx b/shared/provision/code-page/qr-scan/hooks.tsx index bf1687854d0b..c6515c36c5d4 100644 --- a/shared/provision/code-page/qr-scan/hooks.tsx +++ b/shared/provision/code-page/qr-scan/hooks.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useProvisionState} from '@/constants/provision' +import {useProvisionState} from '@/stores/provision' const useQR = () => { const submitTextCode = useProvisionState(s => s.dispatch.dynamic.submitTextCode) diff --git a/shared/provision/code-page/qr-scan/not-authorized.tsx b/shared/provision/code-page/qr-scan/not-authorized.tsx index ee5774db4a22..35f641e2827a 100644 --- a/shared/provision/code-page/qr-scan/not-authorized.tsx +++ b/shared/provision/code-page/qr-scan/not-authorized.tsx @@ -1,5 +1,5 @@ import * as Kb from '@/common-adapters' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const QRScanNotAuthorized = () => { const onOpenSettings = useConfigState(s => s.dispatch.dynamic.openAppSettings) diff --git a/shared/provision/error.tsx b/shared/provision/error.tsx index 93125fdfb30b..a5cafc24ae99 100644 --- a/shared/provision/error.tsx +++ b/shared/provision/error.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as AutoReset from '@/constants/autoreset' +import * as AutoReset from '@/stores/autoreset' import * as Kb from '@/common-adapters' import type * as React from 'react' import LoginContainer from '../login/forms/container' import openURL from '@/util/open-url' import * as T from '@/constants/types' -import {useProvisionState} from '@/constants/provision' +import {useProvisionState} from '@/stores/provision' const Wrapper = (p: {onBack: () => void; children: React.ReactNode}) => ( diff --git a/shared/provision/forgot-username.tsx b/shared/provision/forgot-username.tsx index 9b01068677b6..ad746c8e7579 100644 --- a/shared/provision/forgot-username.tsx +++ b/shared/provision/forgot-username.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' import {SignupScreen, errorBanner} from '../signup/common' -import {useSettingsPhoneState} from '@/constants/settings-phone' -import {useProvisionState} from '@/constants/provision' +import {useSettingsPhoneState} from '@/stores/settings-phone' +import {useProvisionState} from '@/stores/provision' const ForgotUsername = () => { const defaultCountry = useSettingsPhoneState(s => s.defaultCountry) diff --git a/shared/provision/paper-key.tsx b/shared/provision/paper-key.tsx index 8fb1972d6f6a..0ae84be9dc0d 100644 --- a/shared/provision/paper-key.tsx +++ b/shared/provision/paper-key.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as React from 'react' import {SignupScreen, errorBanner} from '../signup/common' -import {useProvisionState} from '@/constants/provision' +import {useProvisionState} from '@/stores/provision' const Container = () => { const error = useProvisionState(s => s.error) diff --git a/shared/provision/password.tsx b/shared/provision/password.tsx index 3d1f2adddff5..3bef094b69fc 100644 --- a/shared/provision/password.tsx +++ b/shared/provision/password.tsx @@ -3,8 +3,8 @@ import * as Kb from '@/common-adapters' import * as React from 'react' import UserCard from '../login/user-card' import {SignupScreen, errorBanner} from '../signup/common' -import {useState as useRecoverState} from '@/constants/recover-password' -import {useProvisionState} from '@/constants/provision' +import {useState as useRecoverState} from '@/stores/recover-password' +import {useProvisionState} from '@/stores/provision' const Password = () => { const error = useProvisionState(s => s.error) diff --git a/shared/provision/select-other-device-connected.tsx b/shared/provision/select-other-device-connected.tsx index 6f1baa6a45cc..69499e1c7547 100644 --- a/shared/provision/select-other-device-connected.tsx +++ b/shared/provision/select-other-device-connected.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' -import * as AutoReset from '@/constants/autoreset' +import * as AutoReset from '@/stores/autoreset' import * as React from 'react' import {useSafeSubmit} from '@/util/safe-submit' import SelectOtherDevice from './select-other-device' -import {useProvisionState} from '@/constants/provision' +import {useProvisionState} from '@/stores/provision' const SelectOtherDeviceContainer = () => { const devices = useProvisionState(s => s.devices) diff --git a/shared/provision/select-other-device.tsx b/shared/provision/select-other-device.tsx index b39e8c25308e..3ac49ebaba69 100644 --- a/shared/provision/select-other-device.tsx +++ b/shared/provision/select-other-device.tsx @@ -2,7 +2,7 @@ import * as Kb from '@/common-adapters' import * as React from 'react' import DeviceIcon from '../devices/device-icon' import {SignupScreen} from '../signup/common' -import {type Device} from '@/constants/provision' +import {type Device} from '@/stores/provision' type Props = { passwordRecovery?: boolean diff --git a/shared/provision/set-public-name.tsx b/shared/provision/set-public-name.tsx index d25bc7c81f22..3b5d7ba52058 100644 --- a/shared/provision/set-public-name.tsx +++ b/shared/provision/set-public-name.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' -import * as Devices from '@/constants/devices' +import * as Devices from '@/stores/devices' import {useSafeSubmit} from '@/util/safe-submit' import * as Kb from '@/common-adapters' import * as React from 'react' import debounce from 'lodash/debounce' import {SignupScreen, errorBanner} from '../signup/common' -import * as Provision from '@/constants/provision' +import * as Provision from '@/stores/provision' const SetPublicName = () => { const devices = Provision.useProvisionState(s => s.devices) diff --git a/shared/provision/troubleshooting.tsx b/shared/provision/troubleshooting.tsx index 0f00a0cc0e8b..e7aa4f2318c7 100644 --- a/shared/provision/troubleshooting.tsx +++ b/shared/provision/troubleshooting.tsx @@ -1,9 +1,9 @@ import * as React from 'react' import * as C from '@/constants' -import * as Devices from '@/constants/devices' +import * as Devices from '@/stores/devices' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' -import {useProvisionState} from '@/constants/provision' +import {useProvisionState} from '@/stores/provision' type Props = { mode: 'QR' | 'text' onCancel: () => void diff --git a/shared/provision/username-or-email.tsx b/shared/provision/username-or-email.tsx index abf8e1800685..fd06d797850d 100644 --- a/shared/provision/username-or-email.tsx +++ b/shared/provision/username-or-email.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as AutoReset from '@/constants/autoreset' -import {useSignupState} from '@/constants/signup' +import * as AutoReset from '@/stores/autoreset' +import {useSignupState} from '@/stores/signup' import {useSafeSubmit} from '@/util/safe-submit' import * as T from '@/constants/types' import * as React from 'react' @@ -8,7 +8,7 @@ import type {RPCError} from '@/util/errors' import * as Kb from '@/common-adapters' import UserCard from '@/login/user-card' import {SignupScreen, errorBanner} from '@/signup/common' -import {useProvisionState} from '@/constants/provision' +import {useProvisionState} from '@/stores/provision' type OwnProps = {fromReset?: boolean; username?: string} diff --git a/shared/router-v2/account-switcher/index.tsx b/shared/router-v2/account-switcher/index.tsx index 7ed7d926f309..fa570869a785 100644 --- a/shared/router-v2/account-switcher/index.tsx +++ b/shared/router-v2/account-switcher/index.tsx @@ -1,15 +1,15 @@ import * as C from '@/constants' import './account-switcher.css' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import * as Kb from '@/common-adapters' import * as React from 'react' import type * as T from '@/constants/types' import {settingsLogOutTab} from '@/constants/settings/util' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' -import {useUsersState} from '@/constants/users' -import {useCurrentUserState} from '@/constants/current-user' -import {useProvisionState} from '@/constants/provision' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' +import {useUsersState} from '@/stores/users' +import {useCurrentUserState} from '@/stores/current-user' +import {useProvisionState} from '@/stores/provision' const prepareAccountRows = ( accountRows: ReadonlyArray, diff --git a/shared/router-v2/common.native.tsx b/shared/router-v2/common.native.tsx index af2f2056c052..8037a3caaedc 100644 --- a/shared/router-v2/common.native.tsx +++ b/shared/router-v2/common.native.tsx @@ -3,7 +3,7 @@ import * as Kb from '@/common-adapters' import {TabActions, type NavigationContainerRef} from '@react-navigation/core' import type {HeaderOptions} from '@react-navigation/elements' import {HeaderLeftArrowCanGoBack} from '@/common-adapters/header-hoc' -import type {NavState} from '@/constants/router2' +import type {NavState} from '@/stores/router2' export const headerDefaultStyle = { get backgroundColor() { diff --git a/shared/router-v2/header/index.desktop.tsx b/shared/router-v2/header/index.desktop.tsx index 2a46eb9be1c3..892c4fbde2a4 100644 --- a/shared/router-v2/header/index.desktop.tsx +++ b/shared/router-v2/header/index.desktop.tsx @@ -6,7 +6,7 @@ import {IconWithPopupDesktop as WhatsNewIconWithPopup} from '@/whats-new/icon' import * as ReactIs from 'react-is' import KB2 from '@/util/electron.desktop' import shallowEqual from 'shallowequal' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const {closeWindow, minimizeWindow, toggleMaximizeWindow} = KB2.functions diff --git a/shared/router-v2/header/syncing-folders.tsx b/shared/router-v2/header/syncing-folders.tsx index 578aa416f544..722a91e2bb98 100644 --- a/shared/router-v2/header/syncing-folders.tsx +++ b/shared/router-v2/header/syncing-folders.tsx @@ -1,9 +1,9 @@ import * as C from '@/constants' -import * as Constants from '@/constants/fs' +import * as Constants from '@/stores/fs' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import PieSlice from '@/fs/common/pie-slice' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' type OwnProps = { negative?: boolean diff --git a/shared/router-v2/hooks.native.tsx b/shared/router-v2/hooks.native.tsx index bce95fef44e4..ade3784a1414 100644 --- a/shared/router-v2/hooks.native.tsx +++ b/shared/router-v2/hooks.native.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useConfigState} from '@/constants/config' +import * as Chat from '@/stores/chat2' +import {useConfigState} from '@/stores/config' import * as Tabs from '@/constants/tabs' import * as React from 'react' import {handleAppLink} from '@/constants/deeplinks' diff --git a/shared/router-v2/router.desktop.tsx b/shared/router-v2/router.desktop.tsx index 3173b32abf55..51816647e878 100644 --- a/shared/router-v2/router.desktop.tsx +++ b/shared/router-v2/router.desktop.tsx @@ -1,6 +1,6 @@ import * as Common from './common.desktop' import * as C from '@/constants' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import * as Kb from '@/common-adapters' import * as React from 'react' import * as Shared from './router.shared' @@ -15,8 +15,8 @@ import {createNativeStackNavigator} from '@react-navigation/native-stack' import {modalRoutes, routes, loggedOutRoutes, tabRoots} from './routes' import {registerDebugClear} from '@/util/debug' import type {RootParamList} from '@/router-v2/route-params' -import {useCurrentUserState} from '@/constants/current-user' -import {useDaemonState} from '@/constants/daemon' +import {useCurrentUserState} from '@/stores/current-user' +import {useDaemonState} from '@/stores/daemon' import type {NativeStackNavigationOptions} from '@react-navigation/native-stack' import './router.css' diff --git a/shared/router-v2/router.native.tsx b/shared/router-v2/router.native.tsx index f807285c2920..b6b3cf21b97c 100644 --- a/shared/router-v2/router.native.tsx +++ b/shared/router-v2/router.native.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Constants from '@/constants/router2' -import {useConfigState} from '@/constants/config' -import {useDarkModeState} from '@/constants/darkmode' +import * as Constants from '@/stores/router2' +import {useConfigState} from '@/stores/config' +import {useDarkModeState} from '@/stores/darkmode' import * as Kb from '@/common-adapters' import * as React from 'react' import * as Shared from './router.shared' @@ -20,7 +20,7 @@ import * as Hooks from './hooks.native' import * as TabBar from './tab-bar.native' import type {RootParamList} from '@/router-v2/route-params' import {useColorScheme} from 'react-native' -import {useDaemonState} from '@/constants/daemon' +import {useDaemonState} from '@/stores/daemon' if (module.hot) { module.hot.accept('', () => {}) diff --git a/shared/router-v2/router.shared.tsx b/shared/router-v2/router.shared.tsx index 7a88668f6157..e0bb7847af68 100644 --- a/shared/router-v2/router.shared.tsx +++ b/shared/router-v2/router.shared.tsx @@ -4,8 +4,8 @@ import * as React from 'react' import {Splash} from '../login/loading' import type {Theme} from '@react-navigation/native' import {colors, darkColors, themed} from '@/styles/colors' -import {useFSState} from '@/constants/fs' -import {useDarkModeState} from '@/constants/darkmode' +import {useFSState} from '@/stores/fs' +import {useDarkModeState} from '@/stores/darkmode' export const SimpleLoading = React.memo(function SimpleLoading() { return ( diff --git a/shared/router-v2/tab-bar.desktop.tsx b/shared/router-v2/tab-bar.desktop.tsx index 843f25c36ead..a9cceadc90c8 100644 --- a/shared/router-v2/tab-bar.desktop.tsx +++ b/shared/router-v2/tab-bar.desktop.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import * as Kbfs from '@/fs/common' import * as Platforms from '@/constants/platform' import * as T from '@/constants/types' @@ -14,12 +14,12 @@ import {isLinux} from '@/constants/platform' import KB2 from '@/util/electron.desktop' import './tab-bar.css' import {settingsLogOutTab} from '@/constants/settings/util' -import {useTrackerState} from '@/constants/tracker2' -import {useFSState} from '@/constants/fs' -import {useProfileState} from '@/constants/profile' -import {useNotifState} from '@/constants/notifications' -import {useCurrentUserState} from '@/constants/current-user' -import {useProvisionState} from '@/constants/provision' +import {useTrackerState} from '@/stores/tracker2' +import {useFSState} from '@/stores/fs' +import {useProfileState} from '@/stores/profile' +import {useNotifState} from '@/stores/notifications' +import {useCurrentUserState} from '@/stores/current-user' +import {useProvisionState} from '@/stores/provision' const {hideWindow, ctlQuit} = KB2.functions diff --git a/shared/router-v2/tab-bar.native.tsx b/shared/router-v2/tab-bar.native.tsx index 71bb34a5ff8f..3a136f6a74fd 100644 --- a/shared/router-v2/tab-bar.native.tsx +++ b/shared/router-v2/tab-bar.native.tsx @@ -7,7 +7,7 @@ import {View} from 'react-native' import {useSafeAreaFrame} from 'react-native-safe-area-context' import {useColorScheme} from 'react-native' import {usePushState} from '@/constants/push' -import {useNotifState} from '@/constants/notifications' +import {useNotifState} from '@/stores/notifications' const settingsTabChildren = [Tabs.gitTab, Tabs.devicesTab, Tabs.settingsTab] as const const tabs = C.isTablet ? Tabs.tabletTabs : Tabs.phoneTabs diff --git a/shared/settings/account/add-modals.tsx b/shared/settings/account/add-modals.tsx index f5736b62172a..5d203251e85d 100644 --- a/shared/settings/account/add-modals.tsx +++ b/shared/settings/account/add-modals.tsx @@ -6,8 +6,8 @@ import {EnterEmailBody} from '@/signup/email' import {EnterPhoneNumberBody} from '@/signup/phone-number' import VerifyBody from '@/signup/phone-number/verify-body' import {e164ToDisplay} from '@/util/phone-numbers' -import {useSettingsPhoneState} from '@/constants/settings-phone' -import {useSettingsEmailState} from '@/constants/settings-email' +import {useSettingsPhoneState} from '@/stores/settings-phone' +import {useSettingsEmailState} from '@/stores/settings-email' export const Email = () => { const nav = useSafeNavigation() diff --git a/shared/settings/account/confirm-delete.tsx b/shared/settings/account/confirm-delete.tsx index cec9eaa58255..1b4fa2d6f9aa 100644 --- a/shared/settings/account/confirm-delete.tsx +++ b/shared/settings/account/confirm-delete.tsx @@ -2,8 +2,8 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as PhoneUtil from '@/util/phone-numbers' import {useSafeNavigation} from '@/util/safe-navigation' -import {useSettingsPhoneState} from '@/constants/settings-phone' -import {useSettingsEmailState} from '@/constants/settings-email' +import {useSettingsPhoneState} from '@/stores/settings-phone' +import {useSettingsEmailState} from '@/stores/settings-email' type OwnProps = { address: string diff --git a/shared/settings/account/email-phone-row.tsx b/shared/settings/account/email-phone-row.tsx index b3b7f6e32a3d..1eec1a6336e7 100644 --- a/shared/settings/account/email-phone-row.tsx +++ b/shared/settings/account/email-phone-row.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import {useSettingsPhoneState} from '@/constants/settings-phone' -import {useSettingsEmailState} from '@/constants/settings-email' +import {useSettingsPhoneState} from '@/stores/settings-phone' +import {useSettingsEmailState} from '@/stores/settings-email' const addSpacer = (into: string, add: string) => { return into + (into.length ? ' • ' : '') + add diff --git a/shared/settings/account/index.tsx b/shared/settings/account/index.tsx index 1cc8a39c9352..c45c1d9725b0 100644 --- a/shared/settings/account/index.tsx +++ b/shared/settings/account/index.tsx @@ -2,10 +2,10 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import type * as React from 'react' import EmailPhoneRow from './email-phone-row' -import {usePWState} from '@/constants/settings-password' -import {useSettingsPhoneState} from '@/constants/settings-phone' -import {useSettingsEmailState} from '@/constants/settings-email' -import {useSettingsState, settingsPasswordTab} from '@/constants/settings' +import {usePWState} from '@/stores/settings-password' +import {useSettingsPhoneState} from '@/stores/settings-phone' +import {useSettingsEmailState} from '@/stores/settings-email' +import {useSettingsState, settingsPasswordTab} from '@/stores/settings' export const SettingsSection = ({children}: {children: React.ReactNode}) => ( diff --git a/shared/settings/advanced.tsx b/shared/settings/advanced.tsx index 06bec08d7338..1f57db34d60b 100644 --- a/shared/settings/advanced.tsx +++ b/shared/settings/advanced.tsx @@ -3,10 +3,10 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import * as React from 'react' import {ProxySettings} from './proxy' -import {useSettingsState, traceInProgressKey, processorProfileInProgressKey} from '@/constants/settings' -import {usePWState} from '@/constants/settings-password' -import {useFSState} from '@/constants/fs' -import {useConfigState} from '@/constants/config' +import {useSettingsState, traceInProgressKey, processorProfileInProgressKey} from '@/stores/settings' +import {usePWState} from '@/stores/settings-password' +import {useFSState} from '@/stores/fs' +import {useConfigState} from '@/stores/config' let initialUseNativeFrame: boolean | undefined diff --git a/shared/settings/archive/index.tsx b/shared/settings/archive/index.tsx index 3ec5cf413eee..b69fa85c4fbf 100644 --- a/shared/settings/archive/index.tsx +++ b/shared/settings/archive/index.tsx @@ -3,9 +3,9 @@ import * as C from '@/constants' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {formatTimeForConversationList, formatTimeForChat} from '@/util/timestamp' -import {useArchiveState} from '@/constants/archive' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import {useArchiveState} from '@/stores/archive' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' const ChatJob = React.memo(function ChatJob(p: {index: number; id: string}) { const {id, index} = p diff --git a/shared/settings/archive/modal.tsx b/shared/settings/archive/modal.tsx index d74739fcb969..fad4d4c0141b 100644 --- a/shared/settings/archive/modal.tsx +++ b/shared/settings/archive/modal.tsx @@ -4,9 +4,9 @@ import * as C from '@/constants' import type * as T from '@/constants/types' import {pickSave} from '@/util/pick-files' import * as FsCommon from '@/fs/common' -import {useArchiveState} from '@/constants/archive' -import {settingsArchiveTab} from '@/constants/settings' -import {useCurrentUserState} from '@/constants/current-user' +import {useArchiveState} from '@/stores/archive' +import {settingsArchiveTab} from '@/stores/settings' +import {useCurrentUserState} from '@/stores/current-user' import {getConvoState} from '@/constants/chat2/convostate' type Props = diff --git a/shared/settings/chat.tsx b/shared/settings/chat.tsx index 5a0fc327fbe0..1759ee2dbaa1 100644 --- a/shared/settings/chat.tsx +++ b/shared/settings/chat.tsx @@ -1,13 +1,13 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as T from '@/constants/types' import * as React from 'react' import Group from './group' -import {useSettingsChatState as useSettingsChatState} from '@/constants/settings-chat' -import {useSettingsNotifState} from '@/constants/settings-notifications' -import {useSettingsState} from '@/constants/settings' -import {useConfigState} from '@/constants/config' +import {useSettingsChatState as useSettingsChatState} from '@/stores/settings-chat' +import {useSettingsNotifState} from '@/stores/settings-notifications' +import {useSettingsState} from '@/stores/settings' +import {useConfigState} from '@/stores/config' const emptyList = new Array() diff --git a/shared/settings/contacts-joined.tsx b/shared/settings/contacts-joined.tsx index 0650fa5d2e47..994dcd5a5a85 100644 --- a/shared/settings/contacts-joined.tsx +++ b/shared/settings/contacts-joined.tsx @@ -4,9 +4,9 @@ import type * as T from '@/constants/types' import {useSafeNavigation} from '@/util/safe-navigation' import * as React from 'react' import UnconnectedFollowButton from '@/profile/user/actions/follow-button' -import {useSettingsContactsState} from '@/constants/settings-contacts' -import {useTrackerState} from '@/constants/tracker2' -import {useFollowerState} from '@/constants/followers' +import {useSettingsContactsState} from '@/stores/settings-contacts' +import {useTrackerState} from '@/stores/tracker2' +import {useFollowerState} from '@/stores/followers' const renderItem = (_: number, item: T.RPCGen.ProcessedContact) => diff --git a/shared/settings/db-nuke.confirm.tsx b/shared/settings/db-nuke.confirm.tsx index 5c4b71083a5d..d286b5367ddd 100644 --- a/shared/settings/db-nuke.confirm.tsx +++ b/shared/settings/db-nuke.confirm.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import {useSettingsState} from '@/constants/settings' +import {useSettingsState} from '@/stores/settings' const DbNukeConfirm = () => { const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) diff --git a/shared/settings/delete-confirm/check-passphrase.native.tsx b/shared/settings/delete-confirm/check-passphrase.native.tsx index a861c09207b8..00010f8bf4db 100644 --- a/shared/settings/delete-confirm/check-passphrase.native.tsx +++ b/shared/settings/delete-confirm/check-passphrase.native.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' import {useSafeNavigation} from '@/util/safe-navigation' -import {useSettingsState} from '@/constants/settings' +import {useSettingsState} from '@/stores/settings' const CheckPassphraseMobile = () => { const [password, setPassword] = React.useState('') diff --git a/shared/settings/delete-confirm/index.tsx b/shared/settings/delete-confirm/index.tsx index 1a4a243a2ca5..e946c68aa858 100644 --- a/shared/settings/delete-confirm/index.tsx +++ b/shared/settings/delete-confirm/index.tsx @@ -2,9 +2,9 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' import {useSafeNavigation} from '@/util/safe-navigation' -import {usePWState} from '@/constants/settings-password' -import {useSettingsState} from '@/constants/settings' -import {useCurrentUserState} from '@/constants/current-user' +import {usePWState} from '@/stores/settings-password' +import {useSettingsState} from '@/stores/settings' +import {useCurrentUserState} from '@/stores/current-user' type CheckboxesProps = { checkData: boolean diff --git a/shared/settings/disable-cert-pinning-modal.tsx b/shared/settings/disable-cert-pinning-modal.tsx index b84956f0114d..8fe63caf18c2 100644 --- a/shared/settings/disable-cert-pinning-modal.tsx +++ b/shared/settings/disable-cert-pinning-modal.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import {useSettingsState} from '@/constants/settings' +import {useSettingsState} from '@/stores/settings' const DisableCertPinningModal = () => { const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) diff --git a/shared/settings/display.tsx b/shared/settings/display.tsx index b95ba9a6e786..f7ab52aafed4 100644 --- a/shared/settings/display.tsx +++ b/shared/settings/display.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import logger from '@/logger' -import {useConfigState} from '@/constants/config' -import * as DarkMode from '@/constants/darkmode' +import {useConfigState} from '@/stores/config' +import * as DarkMode from '@/stores/darkmode' const Display = () => { const allowAnimatedEmojis = useConfigState(s => s.allowAnimatedEmojis) diff --git a/shared/settings/feedback/container.desktop.tsx b/shared/settings/feedback/container.desktop.tsx index 83933ea0ad0d..5ebef2dcdd73 100644 --- a/shared/settings/feedback/container.desktop.tsx +++ b/shared/settings/feedback/container.desktop.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import Feedback from '.' import type {Props} from './container' import {useSendFeedback} from './shared' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const Container = (ownProps: Props) => { const {sendFeedback, error} = useSendFeedback() diff --git a/shared/settings/feedback/container.native.tsx b/shared/settings/feedback/container.native.tsx index b88db320114e..45a5ca45867c 100644 --- a/shared/settings/feedback/container.native.tsx +++ b/shared/settings/feedback/container.native.tsx @@ -1,5 +1,5 @@ -import {useConfigState} from '@/constants/config' -import {useCurrentUserState} from '@/constants/current-user' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' import * as Kb from '@/common-adapters' import * as React from 'react' import Feedback from '.' diff --git a/shared/settings/files/hooks.tsx b/shared/settings/files/hooks.tsx index 7cd0b2d730c2..e8e29a846900 100644 --- a/shared/settings/files/hooks.tsx +++ b/shared/settings/files/hooks.tsx @@ -1,6 +1,6 @@ import {defaultNotificationThreshold} from '.' import * as C from '@/constants' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' const useFiles = () => { const {areSettingsLoading, setSpaceAvailableNotificationThreshold, spaceAvailableNotificationThreshold} = diff --git a/shared/settings/files/index.desktop.tsx b/shared/settings/files/index.desktop.tsx index c8abd4d17097..02c9475c612e 100644 --- a/shared/settings/files/index.desktop.tsx +++ b/shared/settings/files/index.desktop.tsx @@ -6,8 +6,8 @@ import * as Kbfs from '@/fs/common' import RefreshDriverStatusOnMount from '@/fs/common/refresh-driver-status-on-mount' import RefreshSettings from './refresh-settings' import useFiles from './hooks' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' type Props = ReturnType export const allowedNotificationThresholds = [100 * 1024 ** 2, 1024 ** 3, 3 * 1024 ** 3, 10 * 1024 ** 3] diff --git a/shared/settings/files/index.native.tsx b/shared/settings/files/index.native.tsx index 66ecd2edf2f0..bbec8c0123d0 100644 --- a/shared/settings/files/index.native.tsx +++ b/shared/settings/files/index.native.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import useFiles from './hooks' -import * as FS from '@/constants/fs' -import {useFSState} from '@/constants/fs' +import * as FS from '@/stores/fs' +import {useFSState} from '@/stores/fs' type Props = ReturnType export const allowedNotificationThresholds = [100 * 1024 ** 2, 1024 ** 3, 3 * 1024 ** 3, 10 * 1024 ** 3] diff --git a/shared/settings/files/refresh-settings.tsx b/shared/settings/files/refresh-settings.tsx index aa4da1e72b56..383484e7b579 100644 --- a/shared/settings/files/refresh-settings.tsx +++ b/shared/settings/files/refresh-settings.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import {useFSState} from '@/constants/fs' +import {useFSState} from '@/stores/fs' const RefreshSettings = () => { const refresh = useFSState(s => s.dispatch.loadSettings) diff --git a/shared/settings/group.tsx b/shared/settings/group.tsx index 839ad9fa16b1..fefd140db264 100644 --- a/shared/settings/group.tsx +++ b/shared/settings/group.tsx @@ -1,5 +1,5 @@ import * as Kb from '@/common-adapters' -import type {NotificationsSettingsState} from '@/constants/settings-notifications' +import type {NotificationsSettingsState} from '@/stores/settings-notifications' type GroupProps = { allowEdit: boolean diff --git a/shared/settings/invites/index.desktop.tsx b/shared/settings/invites/index.desktop.tsx index 0636b633ea3b..c9dd76394d51 100644 --- a/shared/settings/invites/index.desktop.tsx +++ b/shared/settings/invites/index.desktop.tsx @@ -1,11 +1,11 @@ import * as Kb from '@/common-adapters' -import type {AcceptedInvite, PendingInvite} from '@/constants/settings-invites' +import type {AcceptedInvite, PendingInvite} from '@/stores/settings-invites' import * as React from 'react' import SubHeading from '../subheading' import * as dateFns from 'date-fns' import * as C from '@/constants' -import {useProfileState} from '@/constants/profile' -import {useState as useSettingsInvitesState} from '@/constants/settings-invites' +import {useProfileState} from '@/stores/profile' +import {useState as useSettingsInvitesState} from '@/stores/settings-invites' // Like intersperse but takes a function to define the separator function intersperseFn( diff --git a/shared/settings/logout.tsx b/shared/settings/logout.tsx index b5d765d9287c..c61c62e3656e 100644 --- a/shared/settings/logout.tsx +++ b/shared/settings/logout.tsx @@ -3,9 +3,9 @@ import {useSafeSubmit} from '@/util/safe-submit' import * as C from '@/constants' import * as Kb from '@/common-adapters' import {UpdatePassword} from './password' -import {usePWState} from '@/constants/settings-password' -import {useSettingsState} from '@/constants/settings' -import {useLogoutState} from '@/constants/logout' +import {usePWState} from '@/stores/settings-password' +import {useSettingsState} from '@/stores/settings' +import {useLogoutState} from '@/stores/logout' const LogoutContainer = () => { const {checkPassword, checkPasswordIsCorrect, resetCheckPassword} = useSettingsState( diff --git a/shared/settings/manage-contacts.tsx b/shared/settings/manage-contacts.tsx index fa5f9f6a3764..aca33a0abc2f 100644 --- a/shared/settings/manage-contacts.tsx +++ b/shared/settings/manage-contacts.tsx @@ -2,9 +2,9 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' import {SettingsSection} from './account' -import {useSettingsContactsState} from '@/constants/settings-contacts' -import {settingsFeedbackTab} from '@/constants/settings' -import {useConfigState} from '@/constants/config' +import {useSettingsContactsState} from '@/stores/settings-contacts' +import {settingsFeedbackTab} from '@/stores/settings' +import {useConfigState} from '@/stores/config' const enabledDescription = 'Your phone contacts are being synced on this device.' const disabledDescription = 'Import your phone contacts and start encrypted chats with your friends.' diff --git a/shared/settings/notifications/hooks.tsx b/shared/settings/notifications/hooks.tsx index 210c1149d735..a3c0aecc59fd 100644 --- a/shared/settings/notifications/hooks.tsx +++ b/shared/settings/notifications/hooks.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import {useSettingsEmailState} from '@/constants/settings-email' -import {useSettingsNotifState} from '@/constants/settings-notifications' -import {useSettingsState, settingsAccountTab} from '@/constants/settings' +import {useSettingsEmailState} from '@/stores/settings-email' +import {useSettingsNotifState} from '@/stores/settings-notifications' +import {useSettingsState, settingsAccountTab} from '@/stores/settings' const useNotifications = () => { const _groups = useSettingsNotifState(s => s.groups) diff --git a/shared/settings/notifications/index.desktop.tsx b/shared/settings/notifications/index.desktop.tsx index 003323b3e450..2b245d4fd6d7 100644 --- a/shared/settings/notifications/index.desktop.tsx +++ b/shared/settings/notifications/index.desktop.tsx @@ -1,8 +1,8 @@ import {Reloadable} from '@/common-adapters' import * as C from '@/constants' import Render from './render' -import {useSettingsNotifState} from '@/constants/settings-notifications' -import {useSettingsState} from '@/constants/settings' +import {useSettingsNotifState} from '@/stores/settings-notifications' +import {useSettingsState} from '@/stores/settings' const Notifications = () => { const loadSettings = useSettingsState(s => s.dispatch.loadSettings) diff --git a/shared/settings/notifications/index.native.tsx b/shared/settings/notifications/index.native.tsx index 50eb9263f81a..b4e429461668 100644 --- a/shared/settings/notifications/index.native.tsx +++ b/shared/settings/notifications/index.native.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import Notifications from './render' import {Reloadable} from '@/common-adapters' -import {useSettingsNotifState} from '@/constants/settings-notifications' -import {useSettingsState} from '@/constants/settings' +import {useSettingsNotifState} from '@/stores/settings-notifications' +import {useSettingsState} from '@/stores/settings' import {usePushState} from '@/constants/push' const MobileNotifications = () => { diff --git a/shared/settings/password.tsx b/shared/settings/password.tsx index afea9f8392ed..f9c157c2641b 100644 --- a/shared/settings/password.tsx +++ b/shared/settings/password.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import * as C from '@/constants' -import {usePWState} from '@/constants/settings-password' +import {usePWState} from '@/stores/settings-password' type Props = { error: string diff --git a/shared/settings/proxy.tsx b/shared/settings/proxy.tsx index 06975d317b3d..3239af09aba9 100644 --- a/shared/settings/proxy.tsx +++ b/shared/settings/proxy.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import {useSettingsState} from '@/constants/settings' +import {useSettingsState} from '@/stores/settings' const useConnect = () => { const allowTlsMitmToggle = useSettingsState(s => s.didToggleCertificatePinning) diff --git a/shared/settings/root-desktop-tablet.tsx b/shared/settings/root-desktop-tablet.tsx index 7b29c0799c0d..8c76227cdd56 100644 --- a/shared/settings/root-desktop-tablet.tsx +++ b/shared/settings/root-desktop-tablet.tsx @@ -6,7 +6,7 @@ import LeftNav from './sub-nav/left-nav' import {useNavigationBuilder, TabRouter, createNavigatorFactory} from '@react-navigation/core' import type {TypedNavigator, NavigatorTypeBagBase, StaticConfig} from '@react-navigation/native' import {sharedNewRoutes} from './routes' -import {settingsAccountTab} from '@/constants/settings' +import {settingsAccountTab} from '@/stores/settings' const settingsSubRoutes = { ...sharedNewRoutes, diff --git a/shared/settings/root-phone.tsx b/shared/settings/root-phone.tsx index 0ed12c417a3b..379ad5fbc252 100644 --- a/shared/settings/root-phone.tsx +++ b/shared/settings/root-phone.tsx @@ -1,16 +1,16 @@ import * as C from '@/constants' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import {keybaseFM} from '@/constants/whats-new' +import {keybaseFM} from '@/stores/whats-new' import SettingsItem from './sub-nav/settings-item' import WhatsNewIcon from '../whats-new/icon' import noop from 'lodash/noop' -import {useSettingsContactsState} from '@/constants/settings-contacts' -import * as Settings from '@/constants/settings' +import {useSettingsContactsState} from '@/stores/settings-contacts' +import * as Settings from '@/stores/settings' import {usePushState} from '@/constants/push' -import {useNotifState} from '@/constants/notifications' +import {useNotifState} from '@/stores/notifications' const PerfRow = () => { const [toSubmit, setToSubmit] = React.useState('') diff --git a/shared/settings/sub-nav/left-nav.tsx b/shared/settings/sub-nav/left-nav.tsx index 12ecd1a074d8..57ca3a5fbf13 100644 --- a/shared/settings/sub-nav/left-nav.tsx +++ b/shared/settings/sub-nav/left-nav.tsx @@ -3,10 +3,10 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import WhatsNewIcon from '@/whats-new/icon' import SettingsItem from './settings-item' -import {keybaseFM} from '@/constants/whats-new' -import * as Settings from '@/constants/settings' +import {keybaseFM} from '@/stores/whats-new' +import * as Settings from '@/stores/settings' import {usePushState} from '@/constants/push' -import {useNotifState} from '@/constants/notifications' +import {useNotifState} from '@/stores/notifications' type Props = { onClick: (s: string) => void diff --git a/shared/signup/common.tsx b/shared/signup/common.tsx index 60286f6c65e2..19603764cd7e 100644 --- a/shared/signup/common.tsx +++ b/shared/signup/common.tsx @@ -3,7 +3,7 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import {type Props as ButtonProps} from '@/common-adapters/button' import openURL from '@/util/open-url' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' type InfoIconProps = { invisible?: boolean diff --git a/shared/signup/device-name.tsx b/shared/signup/device-name.tsx index 8abc7478d70d..d53ddce22c04 100644 --- a/shared/signup/device-name.tsx +++ b/shared/signup/device-name.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as React from 'react' import {SignupScreen, errorBanner} from './common' -import * as Provision from '@/constants/provision' -import {useSignupState} from '@/constants/signup' +import * as Provision from '@/stores/provision' +import {useSignupState} from '@/stores/signup' const ConnectedEnterDevicename = () => { const error = useSignupState(s => s.devicenameError) diff --git a/shared/signup/email.tsx b/shared/signup/email.tsx index 1593cf89c1e0..0f6f33bef3b6 100644 --- a/shared/signup/email.tsx +++ b/shared/signup/email.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' import {SignupScreen, errorBanner} from './common' -import {useSettingsEmailState} from '@/constants/settings-email' -import {useSignupState} from '@/constants/signup' +import {useSettingsEmailState} from '@/stores/settings-email' +import {useSignupState} from '@/stores/signup' import {usePushState} from '@/constants/push' const ConnectedEnterEmail = () => { diff --git a/shared/signup/feedback.tsx b/shared/signup/feedback.tsx index 51c2ac8ace23..1bc404e8c6a3 100644 --- a/shared/signup/feedback.tsx +++ b/shared/signup/feedback.tsx @@ -4,7 +4,7 @@ import * as React from 'react' import FeedbackForm from '../settings/feedback/index' import {SignupScreen, errorBanner} from './common' import {useSendFeedback} from '../settings/feedback/shared' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const SignupFeedback = () => { const {error: sendError, sendFeedback: onSendFeedback} = useSendFeedback() diff --git a/shared/signup/phone-number/index.tsx b/shared/signup/phone-number/index.tsx index 9467647febbe..03ef62e70146 100644 --- a/shared/signup/phone-number/index.tsx +++ b/shared/signup/phone-number/index.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' import {SignupScreen, errorBanner} from '../common' -import {useSettingsPhoneState} from '@/constants/settings-phone' +import {useSettingsPhoneState} from '@/stores/settings-phone' type BodyProps = { autoFocus?: boolean diff --git a/shared/signup/phone-number/verify.tsx b/shared/signup/phone-number/verify.tsx index 1e58e3fde7aa..b3368353a527 100644 --- a/shared/signup/phone-number/verify.tsx +++ b/shared/signup/phone-number/verify.tsx @@ -4,7 +4,7 @@ import * as Kb from '@/common-adapters' import {SignupScreen} from '../common' import {e164ToDisplay} from '@/util/phone-numbers' import VerifyBody from './verify-body' -import {useSettingsPhoneState} from '@/constants/settings-phone' +import {useSettingsPhoneState} from '@/stores/settings-phone' const Container = () => { const error = useSettingsPhoneState(s => (s.verificationState === 'error' ? s.error : '')) diff --git a/shared/signup/username.tsx b/shared/signup/username.tsx index b22cfb0705fb..8f6da6fca45d 100644 --- a/shared/signup/username.tsx +++ b/shared/signup/username.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as React from 'react' import {SignupScreen, errorBanner} from './common' -import {useSignupState} from '@/constants/signup' -import {useProvisionState} from '@/constants/provision' +import {useSignupState} from '@/stores/signup' +import {useProvisionState} from '@/stores/provision' const ConnectedEnterUsername = () => { const error = useSignupState(s => s.usernameError) diff --git a/shared/constants/archive/index.tsx b/shared/stores/archive.tsx similarity index 98% rename from shared/constants/archive/index.tsx rename to shared/stores/archive.tsx index dd132f0e3133..450e6b3ec185 100644 --- a/shared/constants/archive/index.tsx +++ b/shared/stores/archive.tsx @@ -1,11 +1,11 @@ -import * as T from '../types' +import * as T from '../constants/types' import * as Z from '@/util/zustand' -import {ignorePromise} from '../utils' +import {ignorePromise} from '../constants/utils' import * as EngineGen from '@/actions/engine-gen-gen' import {pathToRPCPath} from '@/constants/fs/util' import {formatTimeForPopup} from '@/util/timestamp' import {uint8ArrayToHex} from 'uint8array-extras' -import {isMobile} from '../platform' +import {isMobile} from '../constants/platform' type ChatJob = { id: string diff --git a/shared/constants/autoreset/index.tsx b/shared/stores/autoreset.tsx similarity index 92% rename from shared/constants/autoreset/index.tsx rename to shared/stores/autoreset.tsx index f1d7ed2efaa5..af4e33076267 100644 --- a/shared/constants/autoreset/index.tsx +++ b/shared/stores/autoreset.tsx @@ -1,12 +1,12 @@ import * as Z from '@/util/zustand' -import {ignorePromise} from '../utils' -import * as S from '../strings' +import {ignorePromise} from '@/constants/utils' +import * as S from '@/constants/strings' import * as T from '@/constants/types' import * as EngineGen from '@/actions/engine-gen-gen' import logger from '@/logger' import {RPCError} from '@/util/errors' -import {navigateAppend, navUpToScreen} from '../router2/util' -import {storeRegistry} from '../store-registry' +import {navigateAppend, navUpToScreen} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' type Store = T.Immutable<{ active: boolean @@ -62,7 +62,7 @@ export const useAutoResetState = Z.createZustand((set, get) => { switch (error.code) { case T.RPCGen.StatusCode.scnosession: // We got logged out because we were revoked (which might have been - // becase the reset was completed and this device wasn't notified). + // because the reset was completed and this device wasn't notified). return undefined case T.RPCGen.StatusCode.scnotfound: // "User not in autoreset queue." @@ -140,10 +140,7 @@ export const useAutoResetState = Z.createZustand((set, get) => { s.endTime = params.endTime * 1000 }) } - navigateAppend( - {props: {pipelineStarted: !params.needVerify}, selected: 'resetWaiting'}, - true - ) + navigateAppend({props: {pipelineStarted: !params.needVerify}, selected: 'resetWaiting'}, true) }, }, params: { diff --git a/shared/constants/bots/index.tsx b/shared/stores/bots.tsx similarity index 91% rename from shared/constants/bots/index.tsx rename to shared/stores/bots.tsx index beb76b45a4d4..e922a4538206 100644 --- a/shared/constants/bots/index.tsx +++ b/shared/stores/bots.tsx @@ -1,8 +1,8 @@ -import * as T from '../types' +import * as T from '@/constants/types' import * as EngineGen from '@/actions/engine-gen-gen' import * as Z from '@/util/zustand' -import {ignorePromise, RPCError, isNetworkErr} from '../utils' -import * as S from '../strings' +import {ignorePromise, RPCError, isNetworkErr} from '@/constants/utils' +import * as S from '@/constants/strings' import logger from '@/logger' type BotSearchResults = { @@ -183,4 +183,17 @@ export const useBotsState = Z.createZustand((set, get) => { } }) -export {getFeaturedSorted} from './util' +export const getFeaturedSorted = ( + featuredBotsMap: ReadonlyMap +): Array => { + const featured = [...featuredBotsMap.values()] + featured.sort((a: T.RPCGen.FeaturedBot, b: T.RPCGen.FeaturedBot) => { + if (a.rank < b.rank) { + return 1 + } else if (a.rank > b.rank) { + return -1 + } + return 0 + }) + return featured +} diff --git a/shared/constants/chat2/index.tsx b/shared/stores/chat2.tsx similarity index 98% rename from shared/constants/chat2/index.tsx rename to shared/stores/chat2.tsx index 79cc8a00fedf..18936b18c5c4 100644 --- a/shared/constants/chat2/index.tsx +++ b/shared/stores/chat2.tsx @@ -1,27 +1,27 @@ -import * as T from '../types' -import {ignorePromise, timeoutPromise, type ViewPropsToPageProps} from '../utils' -import * as Tabs from '../tabs' +import * as T from '@/constants/types' +import {ignorePromise, timeoutPromise, type ViewPropsToPageProps} from '@/constants/utils' +import * as Tabs from '@/constants/tabs' import * as EngineGen from '@/actions/engine-gen-gen' -import type * as ConfigConstants from '../config' -import * as Message from './message' -import * as Router2 from '../router2' -import * as TeamConstants from '../teams/util' +import type * as ConfigConstants from '@/stores/config' +import * as Message from '@/constants/chat2/message' +import * as Router2 from '@/stores/router2' +import * as TeamConstants from '@/constants/teams/util' import logger from '@/logger' import {RPCError} from '@/util/errors' -import * as Meta from './meta' -import {isMobile, isPhone} from '../platform' +import * as Meta from '@/constants/chat2/meta' +import {isMobile, isPhone} from '@/constants/platform' import * as Z from '@/util/zustand' -import * as Common from './common' -import {clearChatStores, chatStores} from './convostate' +import * as Common from '@/constants/chat2/common' +import {clearChatStores, chatStores} from '@/constants/chat2/convostate' import {uint8ArrayToString} from 'uint8array-extras' import isEqual from 'lodash/isEqual' -import {bodyToJSON} from '../rpc-utils' -import {navigateAppend, navUpToScreen, switchTab} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {useConfigState} from '../config' -import {useCurrentUserState} from '../current-user' -import {useWaitingState} from '../waiting' -import * as S from '../strings' +import {bodyToJSON} from '@/constants/rpc-utils' +import {navigateAppend, navUpToScreen, switchTab} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' +import {useWaitingState} from '@/stores/waiting' +import * as S from '@/constants/strings' const defaultTopReacjis = [ {name: ':+1:'}, @@ -1966,7 +1966,7 @@ export const useChatState = Z.createZustand((set, get) => { } }) -import {type ChatProviderProps, ProviderScreen} from './convostate' +import {type ChatProviderProps, ProviderScreen} from '@/constants/chat2/convostate' import type {GetOptionsRet} from '@/constants/types/router2' export function makeChatScreen>( @@ -1992,10 +1992,10 @@ export function makeChatScreen>( } } -export * from './convostate' -export * from './common' -export * from './meta' -export * from './message' +export * from '@/constants/chat2/convostate' +export * from '@/constants/chat2/common' +export * from '@/constants/chat2/meta' +export * from '@/constants/chat2/message' export { noConversationIDKey, @@ -2003,4 +2003,4 @@ export { pendingErrorConversationIDKey, isValidConversationIDKey, dummyConversationIDKey, -} from '../types/chat2/common' +} from '@/constants/types/chat2/common' diff --git a/shared/constants/config/index.tsx b/shared/stores/config.tsx similarity index 98% rename from shared/constants/config/index.tsx rename to shared/stores/config.tsx index 9d52e0338fc9..d1a2498cbe20 100644 --- a/shared/constants/config/index.tsx +++ b/shared/stores/config.tsx @@ -1,18 +1,18 @@ -import * as T from '../types' -import {ignorePromise, timeoutPromise} from '../utils' -import {waitingKeyConfigLogin} from '../strings' +import * as T from '@/constants/types' +import {ignorePromise, timeoutPromise} from '@/constants/utils' +import {waitingKeyConfigLogin} from '@/constants/strings' import * as EngineGen from '@/actions/engine-gen-gen' import * as Stats from '@/engine/stats' import * as Z from '@/util/zustand' -import {noConversationIDKey} from '../types/chat2/common' +import {noConversationIDKey} from '@/constants/types/chat2/common' import isEqual from 'lodash/isEqual' import logger from '@/logger' -import type {Tab} from '../tabs' +import type {Tab} from '@/constants/tabs' import {RPCError, convertToError, isEOFError, isErrorTransient, niceError} from '@/util/errors' -import {defaultUseNativeFrame, isMobile} from '../platform' +import {defaultUseNativeFrame, isMobile} from '@/constants/platform' import {type CommonResponseHandler} from '@/engine/types' -import {invalidPasswordErrorString} from './util' -import {navigateAppend} from '../router2/util' +import {invalidPasswordErrorString} from '@/constants/config/util' +import {navigateAppend} from '@/constants/router2/util' type Store = T.Immutable<{ active: boolean diff --git a/shared/constants/crypto/index.tsx b/shared/stores/crypto.tsx similarity index 98% rename from shared/constants/crypto/index.tsx rename to shared/stores/crypto.tsx index 1d0a1de56944..881fb2f59a11 100644 --- a/shared/constants/crypto/index.tsx +++ b/shared/stores/crypto.tsx @@ -1,15 +1,15 @@ import * as Z from '@/util/zustand' -import {ignorePromise} from '../utils' -import {isMobile} from '../platform' -import {waitingKeyCrypto} from '../strings' +import {ignorePromise} from '@/constants/utils' +import {isMobile} from '@/constants/platform' +import {waitingKeyCrypto} from '@/constants/strings' import HiddenString from '@/util/hidden-string' import logger from '@/logger' -import * as T from '../types' +import * as T from '@/constants/types' import {RPCError} from '@/util/errors' -import {navigateAppend} from '../router2/util' -import {useCurrentUserState} from '../current-user' -import {Operations} from './util' -export * from './util' +import {navigateAppend} from '@/constants/router2/util' +import {useCurrentUserState} from '@/stores/current-user' +import {Operations} from '@/constants/crypto/util' +export * from '@/constants/crypto/util' type CommonStore = { bytesComplete: number diff --git a/shared/constants/current-user/index.tsx b/shared/stores/current-user.tsx similarity index 96% rename from shared/constants/current-user/index.tsx rename to shared/stores/current-user.tsx index 76b8a2caa8be..aaba7e2cc2cd 100644 --- a/shared/constants/current-user/index.tsx +++ b/shared/stores/current-user.tsx @@ -1,4 +1,4 @@ -import type * as T from '../types' +import type * as T from '@/constants/types' import * as Z from '@/util/zustand' // This store has no dependencies on other stores and is safe to import directly from other stores. diff --git a/shared/constants/daemon/index.tsx b/shared/stores/daemon.tsx similarity index 98% rename from shared/constants/daemon/index.tsx rename to shared/stores/daemon.tsx index f87e335f757b..340fcd3949e5 100644 --- a/shared/constants/daemon/index.tsx +++ b/shared/stores/daemon.tsx @@ -1,8 +1,8 @@ import logger from '@/logger' -import {ignorePromise} from '../utils' -import * as T from '../types' +import {ignorePromise} from '@/constants/utils' +import * as T from '@/constants/types' import * as Z from '@/util/zustand' -import {maxHandshakeTries} from '../values' +import {maxHandshakeTries} from '@/constants/values' // Load accounts, this call can be slow so we attempt to continue w/o waiting if we determine we're logged in // normally this wouldn't be worth it but this is startup diff --git a/shared/constants/darkmode/index.tsx b/shared/stores/darkmode.tsx similarity index 97% rename from shared/constants/darkmode/index.tsx rename to shared/stores/darkmode.tsx index fa4d7a445ed1..c616904f1e4e 100644 --- a/shared/constants/darkmode/index.tsx +++ b/shared/stores/darkmode.tsx @@ -1,7 +1,7 @@ -import * as T from '../types' +import * as T from '@/constants/types' import * as Z from '@/util/zustand' import {Appearance} from 'react-native' -import {isMobile} from '../platform' +import {isMobile} from '@/constants/platform' export type DarkModePreference = 'system' | 'alwaysDark' | 'alwaysLight' diff --git a/shared/constants/devices/index.tsx b/shared/stores/devices.tsx similarity index 96% rename from shared/constants/devices/index.tsx rename to shared/stores/devices.tsx index 61608a6b712f..a8404ad69f98 100644 --- a/shared/constants/devices/index.tsx +++ b/shared/stores/devices.tsx @@ -1,8 +1,8 @@ import * as React from 'react' import * as Z from '@/util/zustand' -import * as S from '../strings' -import {ignorePromise, updateImmerMap} from '../utils' -import * as T from '../types' +import * as S from '@/constants/strings' +import {ignorePromise, updateImmerMap} from '@/constants/utils' +import * as T from '@/constants/types' import * as EngineGen from '@/actions/engine-gen-gen' import debounce from 'lodash/debounce' diff --git a/shared/constants/followers/index.tsx b/shared/stores/followers.tsx similarity index 99% rename from shared/constants/followers/index.tsx rename to shared/stores/followers.tsx index f276f03786e9..b403722e07af 100644 --- a/shared/constants/followers/index.tsx +++ b/shared/stores/followers.tsx @@ -1,6 +1,5 @@ import * as T from '@/constants/types' import * as Z from '@/util/zustand' - // This store has no dependencies on other stores and is safe to import directly from other stores. type Store = T.Immutable<{ followers: Set diff --git a/shared/constants/fs/index.tsx b/shared/stores/fs.tsx similarity index 98% rename from shared/constants/fs/index.tsx rename to shared/stores/fs.tsx index f3d94d5b13f5..ace4730a19c4 100644 --- a/shared/constants/fs/index.tsx +++ b/shared/stores/fs.tsx @@ -1,9 +1,9 @@ import * as EngineGen from '@/actions/engine-gen-gen' -import {ignorePromise, timeoutPromise} from '../utils' -import * as S from '../strings' -import {requestPermissionsToWrite} from '../platform-specific' -import * as Tabs from '../tabs' -import * as T from '../types' +import {ignorePromise, timeoutPromise} from '@/constants/utils' +import * as S from '@/constants/strings' +import {requestPermissionsToWrite} from '@/constants/platform-specific' +import * as Tabs from '@/constants/tabs' +import * as T from '@/constants/types' import * as Z from '@/util/zustand' import NotifyPopup from '@/util/notify-popup' import {RPCError} from '@/util/errors' @@ -11,13 +11,13 @@ import logger from '@/logger' import {tlfToPreferredOrder} from '@/util/kbfs' import isObject from 'lodash/isObject' import isEqual from 'lodash/isEqual' -import {navigateAppend, navigateUp} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {useConfigState} from '../config' -import {useCurrentUserState} from '../current-user' -import * as Util from './util' +import {navigateAppend, navigateUp} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' +import * as Util from '@/constants/fs/util' -export * from './util' +export * from '@/constants/fs/util' const subscriptionDeduplicateIntervalSecond = 1 @@ -1598,7 +1598,7 @@ export const useFSState = Z.createZustand((set, get) => { }) }, setupSubscriptions: async () => { - const initPlatformSpecific = await import('./platform-specific') + const initPlatformSpecific = await import('../constants/fs/platform-specific') initPlatformSpecific.default() }, showIncomingShare: initialDestinationParentPath => { diff --git a/shared/constants/git/index.tsx b/shared/stores/git.tsx similarity index 96% rename from shared/constants/git/index.tsx rename to shared/stores/git.tsx index 297dc32a67f4..9ea6dbc1d2c6 100644 --- a/shared/constants/git/index.tsx +++ b/shared/stores/git.tsx @@ -1,12 +1,12 @@ -import * as S from '../strings' -import * as T from '../types' -import {ignorePromise} from '../utils' +import * as S from '@/constants/strings' +import * as T from '@/constants/types' +import {ignorePromise} from '@/constants/utils' import * as EngineGen from '@/actions/engine-gen-gen' import * as dateFns from 'date-fns' import * as Z from '@/util/zustand' import debounce from 'lodash/debounce' -import {navigateAppend} from '../router2/util' -import {useConfigState} from '../config' +import {navigateAppend} from '@/constants/router2/util' +import {useConfigState} from '@/stores/config' const parseRepos = (results: ReadonlyArray) => { const errors: Array = [] diff --git a/shared/constants/logout/index.tsx b/shared/stores/logout.tsx similarity index 91% rename from shared/constants/logout/index.tsx rename to shared/stores/logout.tsx index 82a3c99c749f..1f4983b4fa0d 100644 --- a/shared/constants/logout/index.tsx +++ b/shared/stores/logout.tsx @@ -1,12 +1,12 @@ import logger from '@/logger' -import {ignorePromise, timeoutPromise} from '../utils' +import {ignorePromise, timeoutPromise} from '@/constants/utils' import * as T from '@/constants/types' // normally util.container but it re-exports from us so break the cycle import * as Z from '@/util/zustand' -import {settingsPasswordTab} from '../settings' -import {navigateAppend} from '../router2/util' -import {isMobile} from '../platform' -import * as Tabs from '../tabs' +import {settingsPasswordTab} from '@/constants/settings/util' +import {navigateAppend} from '@/constants/router2/util' +import {isMobile} from '@/constants/platform' +import * as Tabs from '@/constants/tabs' // This store has no dependencies on other stores and is safe to import directly from other stores. type Store = T.Immutable<{ diff --git a/shared/constants/notifications/index.tsx b/shared/stores/notifications.tsx similarity index 95% rename from shared/constants/notifications/index.tsx rename to shared/stores/notifications.tsx index de0802fff654..3fcbeab6cb8c 100644 --- a/shared/constants/notifications/index.tsx +++ b/shared/stores/notifications.tsx @@ -1,12 +1,12 @@ import * as Z from '@/util/zustand' import * as EngineGen from '@/actions/engine-gen-gen' -import type * as T from '../types' -import {isMobile} from '../platform' +import type * as T from '@/constants/types' +import {isMobile} from '@/constants/platform' import isEqual from 'lodash/isEqual' -import * as Tabs from '../tabs' -import {storeRegistry} from '../store-registry' -import {useConfigState} from '../config' -import {useCurrentUserState} from '../current-user' +import * as Tabs from '@/constants/tabs' +import {storeRegistry} from '@/constants/store-registry' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' export type BadgeType = 'regular' | 'update' | 'error' | 'uploading' export type NotificationKeys = 'kbfsUploading' | 'outOfSpace' diff --git a/shared/constants/people/index.tsx b/shared/stores/people.tsx similarity index 98% rename from shared/constants/people/index.tsx rename to shared/stores/people.tsx index 7599680c75f4..27a6a2746e2d 100644 --- a/shared/constants/people/index.tsx +++ b/shared/stores/people.tsx @@ -1,17 +1,17 @@ import * as EngineGen from '@/actions/engine-gen-gen' -import {ignorePromise} from '../utils' +import {ignorePromise} from '@/constants/utils' import * as Z from '@/util/zustand' import invert from 'lodash/invert' import isEqual from 'lodash/isEqual' import logger from '@/logger' -import * as T from '../types' +import * as T from '@/constants/types' import type {IconType} from '@/common-adapters/icon.constants-gen' // do NOT pull in all of common-adapters -import {isMobile} from '../platform' +import {isMobile} from '@/constants/platform' import type {e164ToDisplay as e164ToDisplayType} from '@/util/phone-numbers' import debounce from 'lodash/debounce' -import {useConfigState} from '../config' -import {useFollowerState} from '../followers' -import {RPCError, isNetworkErr} from '../utils' +import {useConfigState} from '@/stores/config' +import {useFollowerState} from '@/stores/followers' +import {RPCError, isNetworkErr} from '@/constants/utils' // set this to true to have all todo items + a contact joined notification show up all the time const debugTodo = false as boolean diff --git a/shared/constants/pinentry/index.tsx b/shared/stores/pinentry.tsx similarity index 97% rename from shared/constants/pinentry/index.tsx rename to shared/stores/pinentry.tsx index 45caef2e55d3..8ad874ff5cf1 100644 --- a/shared/constants/pinentry/index.tsx +++ b/shared/stores/pinentry.tsx @@ -1,9 +1,9 @@ import * as Z from '@/util/zustand' import * as EngineGen from '@/actions/engine-gen-gen' -import * as T from '../types' +import * as T from '@/constants/types' import logger from '@/logger' import {invalidPasswordErrorString} from '@/constants/config/util' -import {wrapErrors} from '../utils' +import {wrapErrors} from '@/constants/utils' // This store has no dependencies on other stores and is safe to import directly from other stores. export type Store = T.Immutable<{ diff --git a/shared/constants/profile/index.tsx b/shared/stores/profile.tsx similarity index 97% rename from shared/constants/profile/index.tsx rename to shared/stores/profile.tsx index d99952fa3cdb..8d1f42ea1fef 100644 --- a/shared/constants/profile/index.tsx +++ b/shared/stores/profile.tsx @@ -1,16 +1,16 @@ -import * as T from '../types' -import {generateGUIID, ignorePromise, wrapErrors} from '../utils' -import * as S from '../strings' +import * as T from '@/constants/types' +import {generateGUIID, ignorePromise, wrapErrors} from '@/constants/utils' +import * as S from '@/constants/strings' import * as Validators from '@/util/simple-validators' import * as Z from '@/util/zustand' import logger from '@/logger' import openURL from '@/util/open-url' import {RPCError} from '@/util/errors' import {fixCrop} from '@/util/crop' -import {clearModals, navigateAppend, navigateUp} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {useCurrentUserState} from '../current-user' -import {navToProfile} from '../router2/util' +import {clearModals, navigateAppend, navigateUp} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useCurrentUserState} from '@/stores/current-user' +import {navToProfile} from '@/constants/router2/util' type ProveGenericParams = { logoBlack: T.Tracker.SiteIconSet @@ -599,9 +599,7 @@ export const useProfileState = Z.createZustand((set, get) => { }) const f = async () => { await T.RPCGen.proveCheckProofRpcPromise({sigID}, S.waitingKeyProfile) - storeRegistry - .getState('tracker2') - .dispatch.showUser(useCurrentUserState.getState().username, false) + storeRegistry.getState('tracker2').dispatch.showUser(useCurrentUserState.getState().username, false) } ignorePromise(f()) }, @@ -649,9 +647,7 @@ export const useProfileState = Z.createZustand((set, get) => { }, submitRevokeProof: proofId => { const f = async () => { - const you = storeRegistry - .getState('tracker2') - .getDetails(useCurrentUserState.getState().username) + const you = storeRegistry.getState('tracker2').getDetails(useCurrentUserState.getState().username) if (!you.assertions) return const proof = [...you.assertions.values()].find(a => a.sigID === proofId) if (!proof) return diff --git a/shared/constants/provision/index.tsx b/shared/stores/provision.tsx similarity index 98% rename from shared/constants/provision/index.tsx rename to shared/stores/provision.tsx index e948638d1e95..b30d9a3d5e05 100644 --- a/shared/constants/provision/index.tsx +++ b/shared/stores/provision.tsx @@ -1,15 +1,15 @@ -import * as T from '../types' -import {ignorePromise, wrapErrors} from '../utils' -import {waitingKeyProvision, waitingKeyProvisionForgotUsername} from '../strings' +import * as T from '@/constants/types' +import {ignorePromise, wrapErrors} from '@/constants/utils' +import {waitingKeyProvision, waitingKeyProvisionForgotUsername} from '@/constants/strings' import * as Z from '@/util/zustand' import {RPCError} from '@/util/errors' -import {isMobile} from '../platform' +import {isMobile} from '@/constants/platform' import {type CommonResponseHandler} from '@/engine/types' import isEqual from 'lodash/isEqual' -import {rpcDeviceToDevice} from '../rpc-utils' +import {rpcDeviceToDevice} from '@/constants/rpc-utils' import {invalidPasswordErrorString} from '@/constants/config/util' -import {clearModals, navigateAppend} from '../router2/util' -import {useWaitingState} from '../waiting' +import {clearModals, navigateAppend} from '@/constants/router2/util' +import {useWaitingState} from '@/stores/waiting' export type Device = { deviceNumberOfType: number diff --git a/shared/constants/recover-password/index.tsx b/shared/stores/recover-password.tsx similarity index 94% rename from shared/constants/recover-password/index.tsx rename to shared/stores/recover-password.tsx index 8a642f8b9487..464bb2e1aa87 100644 --- a/shared/constants/recover-password/index.tsx +++ b/shared/stores/recover-password.tsx @@ -1,14 +1,14 @@ -import * as T from '../types' -import {ignorePromise, wrapErrors} from '../utils' -import {waitingKeyRecoverPassword} from '../strings' +import * as T from '@/constants/types' +import {ignorePromise, wrapErrors} from '@/constants/utils' +import {waitingKeyRecoverPassword} from '@/constants/strings' import * as Z from '@/util/zustand' import logger from '@/logger' import {RPCError} from '@/util/errors' -import {type Device} from '../provision' -import {rpcDeviceToDevice} from '../rpc-utils' -import {clearModals, navigateAppend, navigateUp} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {useConfigState} from '../config' +import {type Device} from '@/stores/provision' +import {rpcDeviceToDevice} from '@/constants/rpc-utils' +import {clearModals, navigateAppend, navigateUp} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useConfigState} from '@/stores/config' type Store = T.Immutable<{ devices: Array @@ -225,9 +225,7 @@ export const useState = Z.createZustand((set, get) => { s.error = msg }) navigateAppend( - useConfigState.getState().loggedIn - ? 'recoverPasswordErrorModal' - : 'recoverPasswordError', + useConfigState.getState().loggedIn ? 'recoverPasswordErrorModal' : 'recoverPasswordError', true ) } diff --git a/shared/constants/router2/index.tsx b/shared/stores/router2.tsx similarity index 94% rename from shared/constants/router2/index.tsx rename to shared/stores/router2.tsx index 24c72281cad0..69864067988b 100644 --- a/shared/constants/router2/index.tsx +++ b/shared/stores/router2.tsx @@ -1,9 +1,9 @@ -import type * as T from '../types' +import type * as T from '@/constants/types' import * as Z from '@/util/zustand' -import * as Tabs from '../tabs' +import * as Tabs from '@/constants/tabs' import type {RouteKeys} from '@/router-v2/route-params' -import {storeRegistry} from '../store-registry' -import * as Util from './util' +import {storeRegistry} from '@/constants/store-registry' +import * as Util from '@/constants/router2/util' export { type NavState, @@ -21,8 +21,8 @@ export { getRouteLoggedIn, useSafeFocusEffect, makeScreen, -} from './util' -export type {PathParam, Navigator} from './util' +} from '@/constants/router2/util' +export type {PathParam, Navigator} from '@/constants/router2/util' type Store = T.Immutable<{ navState?: unknown diff --git a/shared/constants/settings-chat/index.tsx b/shared/stores/settings-chat.tsx similarity index 95% rename from shared/constants/settings-chat/index.tsx rename to shared/stores/settings-chat.tsx index 615ba7a1981f..71e6af5aca23 100644 --- a/shared/constants/settings-chat/index.tsx +++ b/shared/stores/settings-chat.tsx @@ -1,8 +1,8 @@ -import * as T from '../types' -import {ignorePromise} from '../utils' -import * as S from '../strings' +import * as T from '@/constants/types' +import {ignorePromise} from '@/constants/utils' +import * as S from '@/constants/strings' import * as Z from '@/util/zustand' -import {useConfigState} from '../config' +import {useConfigState} from '@/stores/config' export type ChatUnfurlState = { unfurlMode?: T.RPCChat.UnfurlMode diff --git a/shared/constants/settings-contacts.d.ts b/shared/stores/settings-contacts.d.ts similarity index 95% rename from shared/constants/settings-contacts.d.ts rename to shared/stores/settings-contacts.d.ts index 3f48c273c201..0ab05a739542 100644 --- a/shared/constants/settings-contacts.d.ts +++ b/shared/stores/settings-contacts.d.ts @@ -1,4 +1,4 @@ -import type * as T from './types' +import type * as T from '../constants/types' import type {UseBoundStore, StoreApi} from 'zustand' type PermissionStatus = 'granted' | 'denied' | 'undetermined' | 'unknown' diff --git a/shared/constants/settings-contacts.desktop.tsx b/shared/stores/settings-contacts.desktop.tsx similarity index 100% rename from shared/constants/settings-contacts.desktop.tsx rename to shared/stores/settings-contacts.desktop.tsx diff --git a/shared/constants/settings-contacts.native.tsx b/shared/stores/settings-contacts.native.tsx similarity index 95% rename from shared/constants/settings-contacts.native.tsx rename to shared/stores/settings-contacts.native.tsx index 971a5bfdfab5..786e6d0710ab 100644 --- a/shared/constants/settings-contacts.native.tsx +++ b/shared/stores/settings-contacts.native.tsx @@ -1,19 +1,19 @@ import * as Contacts from 'expo-contacts' -import {ignorePromise} from './utils' -import {importContactsWaitingKey} from './strings' -import * as T from './types' +import {ignorePromise} from '../constants/utils' +import {importContactsWaitingKey} from '../constants/strings' +import * as T from '../constants/types' import * as Z from '@/util/zustand' import {addNotificationRequest} from 'react-native-kb' import logger from '@/logger' import type {Store, State} from './settings-contacts' import {RPCError} from '@/util/errors' import {getDefaultCountryCode} from 'react-native-kb' -import {getE164} from './settings-phone' +import {getE164} from '@/util/phone-numbers' import {pluralize} from '@/util/string' -import {navigateAppend} from './router2/util' -import {useConfigState} from './config' -import {useCurrentUserState} from './current-user' -import {useWaitingState} from './waiting' +import {navigateAppend} from '@/constants/router2/util' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' +import {useWaitingState} from '@/stores/waiting' const importContactsConfigKey = (username: string) => `ui.importContacts.${username}` diff --git a/shared/constants/settings-email/index.tsx b/shared/stores/settings-email.tsx similarity index 97% rename from shared/constants/settings-email/index.tsx rename to shared/stores/settings-email.tsx index 7cb1d649961a..935f43208173 100644 --- a/shared/constants/settings-email/index.tsx +++ b/shared/stores/settings-email.tsx @@ -1,7 +1,7 @@ import * as Z from '@/util/zustand' -import {addEmailWaitingKey} from '../strings' -import {ignorePromise} from '../utils' -import * as T from '../types' +import {addEmailWaitingKey} from '@/constants/strings' +import {ignorePromise} from '@/constants/utils' +import * as T from '@/constants/types' import {isValidEmail} from '@/util/simple-validators' import {RPCError} from '@/util/errors' import logger from '@/logger' diff --git a/shared/constants/settings-invites/index.tsx b/shared/stores/settings-invites.tsx similarity index 95% rename from shared/constants/settings-invites/index.tsx rename to shared/stores/settings-invites.tsx index c6b6edc8e582..75cf71ef468f 100644 --- a/shared/constants/settings-invites/index.tsx +++ b/shared/stores/settings-invites.tsx @@ -1,11 +1,11 @@ import * as Z from '@/util/zustand' -import {ignorePromise} from '../utils' -import {waitingKeySettingsGeneric} from '../strings' +import {ignorePromise} from '@/constants/utils' +import {waitingKeySettingsGeneric} from '@/constants/strings' import {RPCError} from '@/util/errors' import logger from '@/logger' import trim from 'lodash/trim' -import * as T from '../types' -import {navigateAppend} from '../router2/util' +import * as T from '@/constants/types' +import {navigateAppend} from '@/constants/router2/util' type InviteBase = { id: string diff --git a/shared/constants/settings-notifications/index.tsx b/shared/stores/settings-notifications.tsx similarity index 97% rename from shared/constants/settings-notifications/index.tsx rename to shared/stores/settings-notifications.tsx index f93adaae9fdc..c22a90a587f0 100644 --- a/shared/constants/settings-notifications/index.tsx +++ b/shared/stores/settings-notifications.tsx @@ -1,10 +1,10 @@ import * as Z from '@/util/zustand' -import * as S from '../strings' -import {isAndroidNewerThanN} from '../platform' -import {ignorePromise, timeoutPromise} from '../utils' +import * as S from '@/constants/strings' +import {isAndroidNewerThanN} from '@/constants/platform' +import {ignorePromise, timeoutPromise} from '@/constants/utils' import {RPCError} from '@/util/errors' import logger from '@/logger' -import * as T from '../types' +import * as T from '@/constants/types' const securityGroup = 'security' const soundGroup = 'sound' diff --git a/shared/constants/settings-password/index.tsx b/shared/stores/settings-password.tsx similarity index 94% rename from shared/constants/settings-password/index.tsx rename to shared/stores/settings-password.tsx index 40123b264cd8..138097633658 100644 --- a/shared/constants/settings-password/index.tsx +++ b/shared/stores/settings-password.tsx @@ -1,11 +1,11 @@ import * as Z from '@/util/zustand' -import {ignorePromise} from '../utils' -import {waitingKeySettingsGeneric} from '../strings' +import {ignorePromise} from '@/constants/utils' +import {waitingKeySettingsGeneric} from '@/constants/strings' import logger from '@/logger' import {RPCError} from '@/util/errors' -import * as T from '../types' -import {navigateUp} from '../router2/util' -import {useLogoutState} from '../logout' +import * as T from '@/constants/types' +import {navigateUp} from '@/constants/router2/util' +import {useLogoutState} from '@/stores/logout' type Store = T.Immutable<{ error: string diff --git a/shared/constants/settings-phone/index.tsx b/shared/stores/settings-phone.tsx similarity index 88% rename from shared/constants/settings-phone/index.tsx rename to shared/stores/settings-phone.tsx index cc19e82aa27d..a70f161aa1f0 100644 --- a/shared/constants/settings-phone/index.tsx +++ b/shared/stores/settings-phone.tsx @@ -1,15 +1,10 @@ -import * as T from '../types' -import * as S from '../strings' -import {ignorePromise} from '../utils' +import * as T from '@/constants/types' +import * as S from '@/constants/strings' +import {ignorePromise} from '@/constants/utils' import * as Z from '@/util/zustand' import logger from '@/logger' import {RPCError} from '@/util/errors' -import type { - e164ToDisplay as e164ToDisplayType, - phoneUtil as phoneUtilType, - ValidationResult as ValidationResultType, - PhoneNumberFormat as PhoneNumberFormatType, -} from '@/util/phone-numbers' +import type {e164ToDisplay as e164ToDisplayType} from '@/util/phone-numbers' export const makePhoneRow = (): PhoneRow => ({ displayNumber: '', @@ -19,25 +14,6 @@ export const makePhoneRow = (): PhoneRow => ({ verified: false, }) -// Get phone number in e.164, or null if we can't parse it. -export const getE164 = (phoneNumber: string, countryCode?: string) => { - const {phoneUtil, ValidationResult, PhoneNumberFormat} = require('@/util/phone-numbers') as { - phoneUtil: typeof phoneUtilType - ValidationResult: typeof ValidationResultType - PhoneNumberFormat: typeof PhoneNumberFormatType - } - try { - const parsed = countryCode ? phoneUtil.parse(phoneNumber, countryCode) : phoneUtil.parse(phoneNumber) - const reason = phoneUtil.isPossibleNumberWithReason(parsed) - if (reason !== ValidationResult.IS_POSSIBLE) { - return null - } - return phoneUtil.format(parsed, PhoneNumberFormat.E164) - } catch { - return null - } -} - const toPhoneRow = (p: T.RPCGen.UserPhoneNumber) => { const {e164ToDisplay} = require('@/util/phone-numbers') as {e164ToDisplay: typeof e164ToDisplayType} return { diff --git a/shared/constants/settings/index.tsx b/shared/stores/settings.tsx similarity index 79% rename from shared/constants/settings/index.tsx rename to shared/stores/settings.tsx index 16ffc111cdcf..73fbe751a5f8 100644 --- a/shared/constants/settings/index.tsx +++ b/shared/stores/settings.tsx @@ -1,21 +1,20 @@ -import * as T from '../types' -import {ignorePromise, timeoutPromise} from '../utils' -import * as S from '../strings' -import {androidIsTestDevice, pprofDir} from '../platform' -import * as EngineGen from '@/actions/engine-gen-gen' +import * as T from '@/constants/types' +import {ignorePromise, timeoutPromise} from '@/constants/utils' +import * as S from '@/constants/strings' +import {androidIsTestDevice, pprofDir} from '@/constants/platform' import openURL from '@/util/open-url' import * as Z from '@/util/zustand' import {RPCError} from '@/util/errors' -import * as Tabs from '../tabs' +import * as Tabs from '@/constants/tabs' import logger from '@/logger' -import {clearModals, navigateAppend, switchTab} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {useConfigState} from '../config' -import {useCurrentUserState} from '../current-user' -import {useWaitingState} from '../waiting' -import {processorProfileInProgressKey, traceInProgressKey} from './util' +import {clearModals, navigateAppend, switchTab} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' +import {useWaitingState} from '@/stores/waiting' +import {processorProfileInProgressKey, traceInProgressKey} from '@/constants/settings/util' -export * from './util' +export * from '@/constants/settings/util' type Store = T.Immutable<{ checkPasswordIsCorrect?: boolean @@ -40,7 +39,6 @@ export interface State extends Store { loadProxyData: () => void loadSettings: () => void loginBrowserViaWebAuthToken: () => void - onEngineIncomingImpl: (action: EngineGen.Actions) => void processorProfile: (durationSeconds: number) => void resetCheckPassword: () => void resetState: 'default' @@ -173,34 +171,6 @@ export const useSettingsState = Z.createZustand(set => { } ignorePromise(f()) }, - onEngineIncomingImpl: action => { - switch (action.type) { - case EngineGen.keybase1NotifyEmailAddressEmailAddressVerified: - logger.info('email verified') - storeRegistry - .getState('settings-email') - .dispatch.notifyEmailVerified(action.payload.params.emailAddress) - break - case EngineGen.keybase1NotifyUsersPasswordChanged: { - const randomPW = action.payload.params.state === T.RPCGen.PassphraseState.random - storeRegistry.getState('settings-password').dispatch.notifyUsersPasswordChanged(randomPW) - break - } - case EngineGen.keybase1NotifyPhoneNumberPhoneNumbersChanged: { - const {list} = action.payload.params - storeRegistry - .getState('settings-phone') - .dispatch.notifyPhoneNumberPhoneNumbersChanged(list ?? undefined) - break - } - case EngineGen.keybase1NotifyEmailAddressEmailsChanged: { - const list = action.payload.params.list ?? [] - storeRegistry.getState('settings-email').dispatch.notifyEmailAddressEmailsChanged(list) - break - } - default: - } - }, processorProfile: profileDurationSeconds => { const f = async () => { await T.RPCGen.pprofLogProcessorProfileRpcPromise({ diff --git a/shared/constants/signup/index.tsx b/shared/stores/signup.tsx similarity index 96% rename from shared/constants/signup/index.tsx rename to shared/stores/signup.tsx index dfa015b6319a..2a0058d0f5cf 100644 --- a/shared/constants/signup/index.tsx +++ b/shared/stores/signup.tsx @@ -1,16 +1,16 @@ -import * as Platforms from '../platform' -import {ignorePromise} from '../utils' -import * as S from '../strings' +import * as Platforms from '@/constants/platform' +import {ignorePromise} from '@/constants/utils' +import * as S from '@/constants/strings' import * as EngineGen from '@/actions/engine-gen-gen' -import * as T from '../types' +import * as T from '@/constants/types' import * as Z from '@/util/zustand' import logger from '@/logger' import trim from 'lodash/trim' import {RPCError} from '@/util/errors' import {isValidEmail, isValidName, isValidUsername} from '@/util/simple-validators' -import {navigateAppend, navigateUp} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {useConfigState} from '../config' +import {navigateAppend, navigateUp} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useConfigState} from '@/stores/config' type Store = T.Immutable<{ devicename: string diff --git a/shared/constants/team-building/index.tsx b/shared/stores/team-building.tsx similarity index 97% rename from shared/constants/team-building/index.tsx rename to shared/stores/team-building.tsx index ddef3357d5dc..4db76d25466f 100644 --- a/shared/constants/team-building/index.tsx +++ b/shared/stores/team-building.tsx @@ -1,6 +1,6 @@ -import * as T from '../types' -import {ignorePromise} from '../utils' -import * as Router2 from '../router2' +import * as T from '@/constants/types' +import {ignorePromise} from '@/constants/utils' +import * as Router2 from '@/stores/router2' import * as React from 'react' import * as Z from '@/util/zustand' import logger from '@/logger' @@ -11,11 +11,11 @@ import {serviceIdFromString} from '@/util/platforms' import {type StoreApi, type UseBoundStore, useStore} from 'zustand' import {validateEmailAddress} from '@/util/email-address' import {registerDebugClear} from '@/util/debug' -import {searchWaitingKey} from './utils' -import {navigateUp} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {useCryptoState} from '../crypto' -export {allServices, selfToUser, searchWaitingKey} from './utils' +import {searchWaitingKey} from '@/constants/team-building/utils' +import {navigateUp} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useCryptoState} from '@/stores/crypto' +export {allServices, selfToUser, searchWaitingKey} from '@/constants/team-building/utils' type Store = T.Immutable<{ namespace: T.TB.AllowedNamespace diff --git a/shared/constants/teams/index.tsx b/shared/stores/teams.tsx similarity index 99% rename from shared/constants/teams/index.tsx rename to shared/stores/teams.tsx index 30ffecf7f3a7..27fbb2f9fac0 100644 --- a/shared/constants/teams/index.tsx +++ b/shared/stores/teams.tsx @@ -1,6 +1,6 @@ -import * as S from '../strings' -import {ignorePromise, wrapErrors} from '../utils' -import * as T from '../types' +import * as S from '@/constants/strings' +import {ignorePromise, wrapErrors} from '@/constants/utils' +import * as T from '@/constants/types' import * as EngineGen from '@/actions/engine-gen-gen' import { getVisibleScreen, @@ -9,21 +9,21 @@ import { navigateUp, navUpToScreen, navToProfile, -} from '../router2/util' +} from '@/constants/router2/util' import * as Z from '@/util/zustand' import invert from 'lodash/invert' import logger from '@/logger' import openSMS from '@/util/sms' import {RPCError, logError} from '@/util/errors' -import {isMobile, isPhone} from '../platform' +import {isMobile, isPhone} from '@/constants/platform' import {mapGetEnsureValue} from '@/util/map' -import {bodyToJSON} from '../rpc-utils' +import {bodyToJSON} from '@/constants/rpc-utils' import {fixCrop} from '@/util/crop' -import {storeRegistry} from '../store-registry' -import {useConfigState} from '../config' -import {useCurrentUserState} from '../current-user' -import * as Util from './util' -import {getTab} from '../router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' +import * as Util from '@/constants/teams/util' +import {getTab} from '@/constants/router2/util' export { baseRetentionPolicies, @@ -33,7 +33,7 @@ export { teamRoleByEnum, retentionPolicyToServiceRetentionPolicy, userIsRoleInTeamWithInfo, -} from './util' +} from '@/constants/teams/util' export const teamRoleTypes = ['reader', 'writer', 'admin', 'owner'] as const diff --git a/shared/constants/tracker2/index.tsx b/shared/stores/tracker2.tsx similarity index 98% rename from shared/constants/tracker2/index.tsx rename to shared/stores/tracker2.tsx index 82d96edd041e..1fa1152e9c29 100644 --- a/shared/constants/tracker2/index.tsx +++ b/shared/stores/tracker2.tsx @@ -1,14 +1,14 @@ -import * as S from '../strings' +import * as S from '@/constants/strings' import * as EngineGen from '@/actions/engine-gen-gen' -import {generateGUIID, ignorePromise} from '../utils' +import {generateGUIID, ignorePromise} from '@/constants/utils' import * as Z from '@/util/zustand' import logger from '@/logger' -import * as T from '../types' +import * as T from '@/constants/types' import {RPCError} from '@/util/errors' import {mapGetEnsureValue} from '@/util/map' -import {navigateAppend, navigateUp} from '../router2/util' -import {storeRegistry} from '../store-registry' -import {useCurrentUserState} from '../current-user' +import {navigateAppend, navigateUp} from '@/constants/router2/util' +import {storeRegistry} from '@/constants/store-registry' +import {useCurrentUserState} from '@/stores/current-user' export const noDetails: T.Tracker.Details = { assertions: new Map(), diff --git a/shared/constants/unlock-folders/index.tsx b/shared/stores/unlock-folders.tsx similarity index 95% rename from shared/constants/unlock-folders/index.tsx rename to shared/stores/unlock-folders.tsx index 9cc11c3b8352..d8fa1d8dd573 100644 --- a/shared/constants/unlock-folders/index.tsx +++ b/shared/stores/unlock-folders.tsx @@ -1,9 +1,9 @@ import * as EngineGen from '@/actions/engine-gen-gen' -import * as T from '../types' +import * as T from '@/constants/types' import * as Z from '@/util/zustand' import logger from '@/logger' import {getEngine} from '@/engine/require' -import {useConfigState, type State as ConfigStore} from '../config' +import {useConfigState, type State as ConfigStore} from '@/stores/config' type Store = T.Immutable<{ devices: ConfigStore['unlockFoldersDevices'] diff --git a/shared/constants/users/index.tsx b/shared/stores/users.tsx similarity index 96% rename from shared/constants/users/index.tsx rename to shared/stores/users.tsx index 642c3c0f3ec9..618264f110ac 100644 --- a/shared/constants/users/index.tsx +++ b/shared/stores/users.tsx @@ -1,11 +1,11 @@ import * as EngineGen from '@/actions/engine-gen-gen' import * as Z from '@/util/zustand' import logger from '@/logger' -import * as T from '../types' +import * as T from '@/constants/types' import {mapGetEnsureValue} from '@/util/map' -import {ignorePromise} from '../utils' -import {RPCError, isNetworkErr} from '../utils' -import * as S from '../strings' +import {ignorePromise} from '@/constants/utils' +import {RPCError, isNetworkErr} from '@/constants/utils' +import * as S from '@/constants/strings' type Store = T.Immutable<{ blockMap: Map diff --git a/shared/constants/waiting/index.tsx b/shared/stores/waiting.tsx similarity index 98% rename from shared/constants/waiting/index.tsx rename to shared/stores/waiting.tsx index c98dd7515a17..effcb51b5006 100644 --- a/shared/constants/waiting/index.tsx +++ b/shared/stores/waiting.tsx @@ -1,5 +1,5 @@ import type {RPCError} from '@/util/errors' -import type * as T from '../types' +import type * as T from '@/constants/types' import * as Z from '@/util/zustand' // This store has no dependencies on other stores and is safe to import directly from other stores. diff --git a/shared/constants/wallets/index.tsx b/shared/stores/wallets.tsx similarity index 86% rename from shared/constants/wallets/index.tsx rename to shared/stores/wallets.tsx index 3843d7919ea1..e340fd2cf383 100644 --- a/shared/constants/wallets/index.tsx +++ b/shared/stores/wallets.tsx @@ -1,10 +1,10 @@ -import * as T from '../types' -import {ignorePromise} from '../utils' +import * as T from '@/constants/types' +import {ignorePromise} from '@/constants/utils' import * as Z from '@/util/zustand' -import {loadAccountsWaitingKey} from './utils' -import {useConfigState} from '../config' +import {loadAccountsWaitingKey} from '@/constants/wallets/utils' +import {useConfigState} from '@/stores/config' -export {loadAccountsWaitingKey} from './utils' +export {loadAccountsWaitingKey} from '@/constants/wallets/utils' export type Account = { accountID: string diff --git a/shared/constants/whats-new/index.tsx b/shared/stores/whats-new.tsx similarity index 92% rename from shared/constants/whats-new/index.tsx rename to shared/stores/whats-new.tsx index 4a2d0bddcac0..2944a3685655 100644 --- a/shared/constants/whats-new/index.tsx +++ b/shared/stores/whats-new.tsx @@ -1,9 +1,9 @@ -import type * as T from '../types' +import type * as T from '@/constants/types' import * as Z from '@/util/zustand' import {uint8ArrayToString} from 'uint8array-extras' -import {noVersion, getSeenVersions} from './utils' +import {noVersion, getSeenVersions} from '@/constants/whats-new/utils' -export {currentVersion, lastVersion, lastLastVersion, keybaseFM} from './utils' +export {currentVersion, lastVersion, lastLastVersion, keybaseFM} from '@/constants/whats-new/utils' // This store has no dependencies on other stores and is safe to import directly from other stores. type SeenVersionsMap = {[key in string]: boolean} diff --git a/shared/styles/colors.tsx b/shared/styles/colors.tsx index f84ad80c59b3..76c0da24acae 100644 --- a/shared/styles/colors.tsx +++ b/shared/styles/colors.tsx @@ -1,5 +1,5 @@ // the _on_white are precomputed colors so we can do less blending on mobile -import {useDarkModeState} from '@/constants/darkmode' +import {useDarkModeState} from '@/stores/darkmode' import {isIOS, isAndroid} from '@/constants/platform' import type {DynamicColorIOS as DynamicColorIOSType} from 'react-native' import type {Opaque} from '@/constants/types/ts' diff --git a/shared/styles/index.native.tsx b/shared/styles/index.native.tsx index 0fc8b52b108c..a15e6e2db217 100644 --- a/shared/styles/index.native.tsx +++ b/shared/styles/index.native.tsx @@ -2,7 +2,7 @@ import * as Shared from './shared' import {colors as lightColors} from './colors' import styleSheetCreateProxy, {type MapToStyles} from './style-sheet-proxy' import {StyleSheet, Dimensions} from 'react-native' -import {useDarkModeState} from '@/constants/darkmode' +import {useDarkModeState} from '@/stores/darkmode' import {isIOS, isTablet} from '@/constants/platform' const font = isIOS diff --git a/shared/styles/style-sheet-proxy.tsx b/shared/styles/style-sheet-proxy.tsx index 37cb8404f801..a6d33b090b3b 100644 --- a/shared/styles/style-sheet-proxy.tsx +++ b/shared/styles/style-sheet-proxy.tsx @@ -1,4 +1,4 @@ -import {useDarkModeState} from '@/constants/darkmode' +import {useDarkModeState} from '@/stores/darkmode' import type {StylesCrossPlatform} from '.' // Support a closure to enable simple dark mode. diff --git a/shared/team-building/contacts.tsx b/shared/team-building/contacts.tsx index 6d39827419c6..06edc5fb79f2 100644 --- a/shared/team-building/contacts.tsx +++ b/shared/team-building/contacts.tsx @@ -1,8 +1,8 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' -import {useSettingsContactsState} from '@/constants/settings-contacts' -import {useTBContext} from '@/constants/team-building' +import {useSettingsContactsState} from '@/stores/settings-contacts' +import {useTBContext} from '@/stores/team-building' const useContactsProps = () => { const contactsImported = useSettingsContactsState(s => s.importEnabled) diff --git a/shared/team-building/email-search.tsx b/shared/team-building/email-search.tsx index 669e819c92a4..3b0ffa004508 100644 --- a/shared/team-building/email-search.tsx +++ b/shared/team-building/email-search.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as TB from '@/constants/team-building' +import * as TB from '@/stores/team-building' import * as React from 'react' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' diff --git a/shared/team-building/filtered-service-tab-bar.tsx b/shared/team-building/filtered-service-tab-bar.tsx index 353ce9fa5665..b882965f5429 100644 --- a/shared/team-building/filtered-service-tab-bar.tsx +++ b/shared/team-building/filtered-service-tab-bar.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import type * as T from '@/constants/types' import {ServiceTabBar} from './service-tab-bar' -import * as TeamBuilding from '@/constants/team-building' +import * as TeamBuilding from '@/stores/team-building' export const FilteredServiceTabBar = ( props: Omit, 'services'> & { diff --git a/shared/team-building/index.tsx b/shared/team-building/index.tsx index bbc6518549f4..7b94ab175862 100644 --- a/shared/team-building/index.tsx +++ b/shared/team-building/index.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' -import * as TB from '@/constants/team-building' -import * as Teams from '@/constants/teams' +import * as TB from '@/stores/team-building' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as React from 'react' import * as T from '@/constants/types' diff --git a/shared/team-building/list-body.tsx b/shared/team-building/list-body.tsx index d9cb0fcbeb9a..20b0bcd9dac5 100644 --- a/shared/team-building/list-body.tsx +++ b/shared/team-building/list-body.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as C from '@/constants' -import * as TB from '@/constants/team-building' -import {useTeamsState} from '@/constants/teams' +import * as TB from '@/stores/team-building' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import * as Shared from './shared' import PeopleResult from './search-result/people-result' @@ -14,9 +14,9 @@ import type {RootRouteProps} from '@/router-v2/route-params' import {RecsAndRecos, numSectionLabel} from './recs-and-recos' import {formatAnyPhoneNumbers} from '@/util/phone-numbers' import {useRoute} from '@react-navigation/native' -import {useSettingsContactsState} from '@/constants/settings-contacts' -import {useFollowerState} from '@/constants/followers' -import {useCurrentUserState} from '@/constants/current-user' +import {useSettingsContactsState} from '@/stores/settings-contacts' +import {useFollowerState} from '@/stores/followers' +import {useCurrentUserState} from '@/stores/current-user' // import {useAnimatedScrollHandler} from '@/common-adapters/reanimated' import {useColorScheme} from 'react-native' diff --git a/shared/team-building/page.tsx b/shared/team-building/page.tsx index a5f899216400..083c6b96837b 100644 --- a/shared/team-building/page.tsx +++ b/shared/team-building/page.tsx @@ -1,7 +1,7 @@ import type * as C from '@/constants' import * as Kb from '@/common-adapters' import * as React from 'react' -import {TBProvider} from '@/constants/team-building' +import {TBProvider} from '@/stores/team-building' const getOptions = ({route}: OwnProps) => { const namespace: unknown = route.params.namespace diff --git a/shared/team-building/phone-search.tsx b/shared/team-building/phone-search.tsx index 4a93fd2dd078..993278b057c9 100644 --- a/shared/team-building/phone-search.tsx +++ b/shared/team-building/phone-search.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' -import * as TB from '@/constants/team-building' +import * as TB from '@/stores/team-building' import * as React from 'react' import * as Kb from '@/common-adapters/index' import type * as T from 'constants/types' import ContinueButton from './continue-button' -import {useSettingsPhoneState} from '@/constants/settings-phone' +import {useSettingsPhoneState} from '@/stores/settings-phone' type PhoneSearchProps = { continueLabel: string diff --git a/shared/team-building/search-result/hellobot-result.tsx b/shared/team-building/search-result/hellobot-result.tsx index 029e730955d1..8e080121a890 100644 --- a/shared/team-building/search-result/hellobot-result.tsx +++ b/shared/team-building/search-result/hellobot-result.tsx @@ -1,6 +1,6 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import {useTBContext} from '@/constants/team-building' +import {useTBContext} from '@/stores/team-building' import * as Kb from '@/common-adapters' import CommonResult, {type ResultProps} from './common-result' diff --git a/shared/team-building/search-result/people-result.tsx b/shared/team-building/search-result/people-result.tsx index 82bf99580a2c..7292f26ffae4 100644 --- a/shared/team-building/search-result/people-result.tsx +++ b/shared/team-building/search-result/people-result.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' import CommonResult, {type ResultProps} from './common-result' -import {useUsersState} from '@/constants/users' -import {useCurrentUserState} from '@/constants/current-user' +import {useUsersState} from '@/stores/users' +import {useCurrentUserState} from '@/stores/current-user' /* * This component is intended to be a drop-in replacement for UserResult. diff --git a/shared/team-building/search-result/you-result.tsx b/shared/team-building/search-result/you-result.tsx index 0e98651cd20a..0c482c089fc9 100644 --- a/shared/team-building/search-result/you-result.tsx +++ b/shared/team-building/search-result/you-result.tsx @@ -1,6 +1,6 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import {useTBContext} from '@/constants/team-building' +import {useTBContext} from '@/stores/team-building' import * as Kb from '@/common-adapters' import CommonResult, {type ResultProps} from './common-result' diff --git a/shared/team-building/shared.tsx b/shared/team-building/shared.tsx index 6342bd06fd0b..9303fdcff0ef 100644 --- a/shared/team-building/shared.tsx +++ b/shared/team-building/shared.tsx @@ -1,7 +1,7 @@ import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import type {IconType} from '@/common-adapters/icon.constants-gen' -import * as TeamBuilding from '@/constants/team-building' +import * as TeamBuilding from '@/stores/team-building' const services: { [K in T.TB.ServiceIdWithContact]: { diff --git a/shared/teams/add-members-wizard/add-contacts.native.tsx b/shared/teams/add-members-wizard/add-contacts.native.tsx index 6808ecaea271..e5e430e0bea1 100644 --- a/shared/teams/add-members-wizard/add-contacts.native.tsx +++ b/shared/teams/add-members-wizard/add-contacts.native.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import {pluralize} from '@/util/string' diff --git a/shared/teams/add-members-wizard/add-email.tsx b/shared/teams/add-members-wizard/add-email.tsx index 26cf7893dc31..c19e84f68547 100644 --- a/shared/teams/add-members-wizard/add-email.tsx +++ b/shared/teams/add-members-wizard/add-email.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import {useSafeNavigation} from '@/util/safe-navigation' import * as T from '@/constants/types' diff --git a/shared/teams/add-members-wizard/add-from-where.tsx b/shared/teams/add-members-wizard/add-from-where.tsx index 08c3f171a503..8bda843d03cf 100644 --- a/shared/teams/add-members-wizard/add-from-where.tsx +++ b/shared/teams/add-members-wizard/add-from-where.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as T from '@/constants/types' import {ModalTitle} from '../common' import {useSafeNavigation} from '@/util/safe-navigation' diff --git a/shared/teams/add-members-wizard/add-phone.tsx b/shared/teams/add-members-wizard/add-phone.tsx index 9a93ef6f9c4b..5ed2a3a15ae2 100644 --- a/shared/teams/add-members-wizard/add-phone.tsx +++ b/shared/teams/add-members-wizard/add-phone.tsx @@ -1,11 +1,11 @@ import * as C from '@/constants' import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import {ModalTitle, usePhoneNumberList} from '../common' import {useSafeNavigation} from '@/util/safe-navigation' -import {useSettingsPhoneState} from '@/constants/settings-phone' +import {useSettingsPhoneState} from '@/stores/settings-phone' const waitingKey = 'phoneLookup' diff --git a/shared/teams/add-members-wizard/confirm.tsx b/shared/teams/add-members-wizard/confirm.tsx index 743ef7110357..6c4fab1bef42 100644 --- a/shared/teams/add-members-wizard/confirm.tsx +++ b/shared/teams/add-members-wizard/confirm.tsx @@ -1,8 +1,8 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import {assertionToDisplay} from '@/common-adapters/usernames' diff --git a/shared/teams/channel/create-channels.tsx b/shared/teams/channel/create-channels.tsx index 2a11aa71da5b..ab94118ac4c5 100644 --- a/shared/teams/channel/create-channels.tsx +++ b/shared/teams/channel/create-channels.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import {CreateChannelsModal} from '../new-team/wizard/create-channels' diff --git a/shared/teams/channel/header.tsx b/shared/teams/channel/header.tsx index ea4654017c5b..16a840f36f2e 100644 --- a/shared/teams/channel/header.tsx +++ b/shared/teams/channel/header.tsx @@ -1,9 +1,9 @@ import * as T from '@/constants/types' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import {pluralize} from '@/util/string' import {Activity, useChannelParticipants} from '../common' diff --git a/shared/teams/channel/index.tsx b/shared/teams/channel/index.tsx index 0bad5f015636..0af5d5e9274d 100644 --- a/shared/teams/channel/index.tsx +++ b/shared/teams/channel/index.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import { @@ -15,8 +15,8 @@ import ChannelMemberRow from './rows' import BotRow from '../team/rows/bot-row/bot' import SettingsList from '../../chat/conversation/info-panel/settings' import EmptyRow from '../team/rows/empty-row' -import {useBotsState} from '@/constants/bots' -import {useUsersState} from '@/constants/users' +import {useBotsState} from '@/stores/bots' +import {useUsersState} from '@/stores/users' export type OwnProps = { teamID: T.Teams.TeamID diff --git a/shared/teams/channel/rows.tsx b/shared/teams/channel/rows.tsx index e07037b57201..5c77b0f6a518 100644 --- a/shared/teams/channel/rows.tsx +++ b/shared/teams/channel/rows.tsx @@ -1,13 +1,13 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useProfileState} from '@/constants/profile' -import * as Teams from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import {useProfileState} from '@/stores/profile' +import * as Teams from '@/stores/teams' import type * as T from '@/constants/types' import * as React from 'react' import * as Kb from '@/common-adapters' import MenuHeader from '../team/rows/menu-header.new' -import {useUsersState} from '@/constants/users' -import {useCurrentUserState} from '@/constants/current-user' +import {useUsersState} from '@/stores/users' +import {useCurrentUserState} from '@/stores/current-user' type Props = { conversationIDKey: T.Chat.ConversationIDKey diff --git a/shared/teams/channel/tabs.tsx b/shared/teams/channel/tabs.tsx index 795cfb89ab9e..bc8d5526ea3a 100644 --- a/shared/teams/channel/tabs.tsx +++ b/shared/teams/channel/tabs.tsx @@ -1,7 +1,7 @@ import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import type {Tab as TabType} from '@/common-adapters/tabs' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' export type TabKey = 'members' | 'attachments' | 'bots' | 'settings' | 'loading' diff --git a/shared/teams/common/activity.tsx b/shared/teams/common/activity.tsx index 6ebbf1f4c098..f31a80050dff 100644 --- a/shared/teams/common/activity.tsx +++ b/shared/teams/common/activity.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' diff --git a/shared/teams/common/channel-hooks.tsx b/shared/teams/common/channel-hooks.tsx index 934b7100704b..7736f46a4e49 100644 --- a/shared/teams/common/channel-hooks.tsx +++ b/shared/teams/common/channel-hooks.tsx @@ -1,8 +1,8 @@ import * as T from '@/constants/types' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' // Filter bots out using team role info, isolate to only when related state changes export const useChannelParticipants = ( diff --git a/shared/teams/common/enable-contacts.tsx b/shared/teams/common/enable-contacts.tsx index 133d5cb95967..829078c08933 100644 --- a/shared/teams/common/enable-contacts.tsx +++ b/shared/teams/common/enable-contacts.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import * as Kb from '@/common-adapters' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' /** * Popup explaining that Keybase doesn't have contact permissions with a link to diff --git a/shared/teams/common/selection-popup.tsx b/shared/teams/common/selection-popup.tsx index 630b995890f3..a30fc04dd584 100644 --- a/shared/teams/common/selection-popup.tsx +++ b/shared/teams/common/selection-popup.tsx @@ -1,8 +1,8 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' import * as React from 'react' import type * as T from '@/constants/types' import {FloatingRolePicker} from '../role-picker' diff --git a/shared/teams/common/use-contacts.native.tsx b/shared/teams/common/use-contacts.native.tsx index 822c30fea955..aa8329ca7130 100644 --- a/shared/teams/common/use-contacts.native.tsx +++ b/shared/teams/common/use-contacts.native.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import {e164ToDisplay} from '@/util/phone-numbers' import logger from '@/logger' import {getDefaultCountryCode} from 'react-native-kb' -import {useSettingsContactsState} from '@/constants/settings-contacts' -import {getE164} from '@/constants/settings-phone' +import {useSettingsContactsState} from '@/stores/settings-contacts' +import {getE164} from '@/util/phone-numbers' // Contact info coming from the native contacts library. export type Contact = { diff --git a/shared/teams/confirm-modals/confirm-kick-out.tsx b/shared/teams/confirm-modals/confirm-kick-out.tsx index 5a8a0d0624e1..4c9d358d20a3 100644 --- a/shared/teams/confirm-modals/confirm-kick-out.tsx +++ b/shared/teams/confirm-modals/confirm-kick-out.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as React from 'react' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import {useSafeNavigation} from '@/util/safe-navigation' diff --git a/shared/teams/confirm-modals/confirm-remove-from-channel.tsx b/shared/teams/confirm-modals/confirm-remove-from-channel.tsx index 4c346846133f..c05aa0d0d84b 100644 --- a/shared/teams/confirm-modals/confirm-remove-from-channel.tsx +++ b/shared/teams/confirm-modals/confirm-remove-from-channel.tsx @@ -1,8 +1,8 @@ import * as T from '@/constants/types' import * as C from '@/constants' import * as React from 'react' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import {useSafeNavigation} from '@/util/safe-navigation' diff --git a/shared/teams/confirm-modals/delete-channel.tsx b/shared/teams/confirm-modals/delete-channel.tsx index 9ad085f55ab3..c2e44e152a52 100644 --- a/shared/teams/confirm-modals/delete-channel.tsx +++ b/shared/teams/confirm-modals/delete-channel.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as React from 'react' import type * as T from '@/constants/types' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import {pluralize} from '@/util/string' import {useAllChannelMetas} from '@/teams/common/channel-hooks' diff --git a/shared/teams/confirm-modals/really-leave-team/index.tsx b/shared/teams/confirm-modals/really-leave-team/index.tsx index 684726a1e8a4..9d4340be3b68 100644 --- a/shared/teams/confirm-modals/really-leave-team/index.tsx +++ b/shared/teams/confirm-modals/really-leave-team/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as C from '@/constants' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import {useSafeSubmit} from '@/util/safe-submit' import type * as T from '@/constants/types' diff --git a/shared/teams/container.tsx b/shared/teams/container.tsx index f3219023e020..e298f8692896 100644 --- a/shared/teams/container.tsx +++ b/shared/teams/container.tsx @@ -1,15 +1,15 @@ import * as C from '@/constants' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import * as FS from '@/constants/fs' +import * as FS from '@/stores/fs' import Main from './main' import openURL from '@/util/open-url' import {useTeamsSubscribe} from './subscriber' import {useActivityLevels} from './common' import {useSafeNavigation} from '@/util/safe-navigation' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const orderTeams = ( teams: ReadonlyMap, diff --git a/shared/teams/delete-team.tsx b/shared/teams/delete-team.tsx index e0dfd2750e0f..4c69295c90ac 100644 --- a/shared/teams/delete-team.tsx +++ b/shared/teams/delete-team.tsx @@ -6,8 +6,8 @@ import * as Kb from '@/common-adapters' import {pluralize} from '@/util/string' import {useTeamDetailsSubscribe} from './subscriber' import noop from 'lodash/noop' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' type OwnProps = {teamID: T.Teams.TeamID} diff --git a/shared/teams/edit-team-description.tsx b/shared/teams/edit-team-description.tsx index 7be608185f4c..71e0934031c3 100644 --- a/shared/teams/edit-team-description.tsx +++ b/shared/teams/edit-team-description.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import {ModalTitle} from './common' diff --git a/shared/teams/emojis/add-alias.tsx b/shared/teams/emojis/add-alias.tsx index cfbf1a23f600..728b3e93a2a4 100644 --- a/shared/teams/emojis/add-alias.tsx +++ b/shared/teams/emojis/add-alias.tsx @@ -1,6 +1,6 @@ import * as T from '@/constants/types' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import {EmojiPickerDesktop} from '@/chat/emoji-picker/container' diff --git a/shared/teams/emojis/add-emoji.tsx b/shared/teams/emojis/add-emoji.tsx index b1f9a3343e17..81c4e896a1f7 100644 --- a/shared/teams/emojis/add-emoji.tsx +++ b/shared/teams/emojis/add-emoji.tsx @@ -1,6 +1,6 @@ import * as T from '@/constants/types' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' import * as Kb from '@/common-adapters' import {AliasInput, Modal} from './common' diff --git a/shared/teams/external-team.tsx b/shared/teams/external-team.tsx index 642461031ab6..9fd9da9f4f66 100644 --- a/shared/teams/external-team.tsx +++ b/shared/teams/external-team.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useProfileState} from '@/constants/profile' +import * as Chat from '@/stores/chat2' +import {useProfileState} from '@/stores/profile' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import {useTeamLinkPopup} from './common' import {pluralize} from '@/util/string' import capitalize from 'lodash/capitalize' diff --git a/shared/teams/get-options.tsx b/shared/teams/get-options.tsx index e4aca9f077a2..f0cf90c88b0f 100644 --- a/shared/teams/get-options.tsx +++ b/shared/teams/get-options.tsx @@ -1,7 +1,7 @@ import * as Kb from '@/common-adapters' import {HeaderRightActions} from './main/header' import {useSafeNavigation} from '@/util/safe-navigation' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' const useHeaderActions = () => { const nav = useSafeNavigation() diff --git a/shared/teams/invite-by-contact/team-invite-by-contacts.native.tsx b/shared/teams/invite-by-contact/team-invite-by-contacts.native.tsx index c0afab8186de..cffc7f924255 100644 --- a/shared/teams/invite-by-contact/team-invite-by-contacts.native.tsx +++ b/shared/teams/invite-by-contact/team-invite-by-contacts.native.tsx @@ -1,11 +1,11 @@ import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import type * as T from '@/constants/types' import useContacts, {type Contact} from '../common/use-contacts.native' import {InviteByContact, type ContactRowProps} from './index.native' import {useTeamDetailsSubscribe} from '../subscriber' import {useSafeNavigation} from '@/util/safe-navigation' -import {getE164} from '@/constants/settings-phone' +import {getE164} from '@/util/phone-numbers' // Seitan invite names (labels) look like this: "[name] ([phone number])". Try // to derive E164 phone number based on seitan invite name and user's region. diff --git a/shared/teams/invite-by-email.tsx b/shared/teams/invite-by-email.tsx index eb81f145ac77..f0201964e4d5 100644 --- a/shared/teams/invite-by-email.tsx +++ b/shared/teams/invite-by-email.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import type * as T from '@/constants/types' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as Kb from '@/common-adapters' import {FloatingRolePicker} from './role-picker' diff --git a/shared/teams/join-team/container.tsx b/shared/teams/join-team/container.tsx index abbdbc6f3941..7a1e2e4df322 100644 --- a/shared/teams/join-team/container.tsx +++ b/shared/teams/join-team/container.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import upperFirst from 'lodash/upperFirst' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as React from 'react' import * as Kb from '@/common-adapters' diff --git a/shared/teams/join-team/join-from-invite.tsx b/shared/teams/join-team/join-from-invite.tsx index fc4fa2ea5d33..f87440ceac61 100644 --- a/shared/teams/join-team/join-from-invite.tsx +++ b/shared/teams/join-team/join-from-invite.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import {Success} from './container' import {useSafeNavigation} from '@/util/safe-navigation' diff --git a/shared/teams/main/index.tsx b/shared/teams/main/index.tsx index 71ee7d1b4daa..7ef9fd136b08 100644 --- a/shared/teams/main/index.tsx +++ b/shared/teams/main/index.tsx @@ -4,7 +4,7 @@ import type * as T from '@/constants/types' import Banner from './banner' import TeamsFooter from './footer' import TeamRowNew from './team-row' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' type DeletedTeam = { teamName: string diff --git a/shared/teams/main/team-row.tsx b/shared/teams/main/team-row.tsx index a2550414088d..524f5e399dca 100644 --- a/shared/teams/main/team-row.tsx +++ b/shared/teams/main/team-row.tsx @@ -1,4 +1,4 @@ -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' import * as React from 'react' import type * as T from '@/constants/types' @@ -6,8 +6,8 @@ import TeamMenu from '../team/menu-container' import {pluralize} from '@/util/string' import {Activity} from '../common' import {useSafeNavigation} from '@/util/safe-navigation' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' type Props = { firstItem: boolean diff --git a/shared/teams/new-team/index.tsx b/shared/teams/new-team/index.tsx index 864bc75f6e6d..13d7883eaa0d 100644 --- a/shared/teams/new-team/index.tsx +++ b/shared/teams/new-team/index.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import openUrl from '@/util/open-url' diff --git a/shared/teams/new-team/wizard/add-subteam-members.tsx b/shared/teams/new-team/wizard/add-subteam-members.tsx index dc439ccc5bb5..6d9484b18811 100644 --- a/shared/teams/new-team/wizard/add-subteam-members.tsx +++ b/shared/teams/new-team/wizard/add-subteam-members.tsx @@ -1,4 +1,4 @@ -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as React from 'react' import * as T from '@/constants/types' @@ -6,7 +6,7 @@ import {ModalTitle} from '@/teams/common' import {pluralize} from '@/util/string' import {useTeamDetailsSubscribe} from '@/teams/subscriber' import {useSafeNavigation} from '@/util/safe-navigation' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' const AddSubteamMembers = () => { const nav = useSafeNavigation() diff --git a/shared/teams/new-team/wizard/create-channels.tsx b/shared/teams/new-team/wizard/create-channels.tsx index b2c22534ece2..dda466eb062e 100644 --- a/shared/teams/new-team/wizard/create-channels.tsx +++ b/shared/teams/new-team/wizard/create-channels.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import {pluralize} from '@/util/string' diff --git a/shared/teams/new-team/wizard/create-subteams.tsx b/shared/teams/new-team/wizard/create-subteams.tsx index e45764eff76c..89a3097a83d6 100644 --- a/shared/teams/new-team/wizard/create-subteams.tsx +++ b/shared/teams/new-team/wizard/create-subteams.tsx @@ -4,7 +4,7 @@ import * as T from '@/constants/types' import {pluralize} from '@/util/string' import {ModalTitle} from '@/teams/common' import {useSafeNavigation} from '@/util/safe-navigation' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' const cleanSubteamName = (name: string) => name.replace(/[^0-9a-zA-Z_]/, '') diff --git a/shared/teams/new-team/wizard/make-big-team.tsx b/shared/teams/new-team/wizard/make-big-team.tsx index 016a8edc4b71..071a0e4420f8 100644 --- a/shared/teams/new-team/wizard/make-big-team.tsx +++ b/shared/teams/new-team/wizard/make-big-team.tsx @@ -2,7 +2,7 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import {ModalTitle} from '@/teams/common' import {useSafeNavigation} from '@/util/safe-navigation' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' const MakeBigTeam = () => { const nav = useSafeNavigation() diff --git a/shared/teams/new-team/wizard/new-team-info.tsx b/shared/teams/new-team/wizard/new-team-info.tsx index cb9661e3b0ee..0bfb4183f529 100644 --- a/shared/teams/new-team/wizard/new-team-info.tsx +++ b/shared/teams/new-team/wizard/new-team-info.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import {ModalTitle} from '@/teams/common' import * as T from '@/constants/types' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' import {pluralize} from '@/util/string' import {InlineDropdown} from '@/common-adapters/dropdown' import {FloatingRolePicker} from '../../role-picker' diff --git a/shared/teams/new-team/wizard/team-purpose.tsx b/shared/teams/new-team/wizard/team-purpose.tsx index 2d75aad151e8..4fa97617bb83 100644 --- a/shared/teams/new-team/wizard/team-purpose.tsx +++ b/shared/teams/new-team/wizard/team-purpose.tsx @@ -2,7 +2,7 @@ import * as Kb from '@/common-adapters' import {ModalTitle} from '@/teams/common' import * as T from '@/constants/types' import {useSafeNavigation} from '@/util/safe-navigation' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' const TeamPurpose = () => { const nav = useSafeNavigation() diff --git a/shared/teams/rename-team.tsx b/shared/teams/rename-team.tsx index 3b080205a545..bdcb775f658d 100644 --- a/shared/teams/rename-team.tsx +++ b/shared/teams/rename-team.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' type OwnProps = {teamname: string} diff --git a/shared/teams/routes.tsx b/shared/teams/routes.tsx index 5692f5f15451..3d57aef29f3a 100644 --- a/shared/teams/routes.tsx +++ b/shared/teams/routes.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import contactRestricted from '../team-building/contact-restricted.page' import teamsTeamBuilder from '../team-building/page' import teamsRootGetOptions from './get-options' diff --git a/shared/teams/subscriber.tsx b/shared/teams/subscriber.tsx index e4dd3276faef..8ea982cb3645 100644 --- a/shared/teams/subscriber.tsx +++ b/shared/teams/subscriber.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import type * as T from '@/constants/types' // NOTE: If you are in a floating box or otherwise outside the navigation diff --git a/shared/teams/team/index.tsx b/shared/teams/team/index.tsx index 0d83779ee857..9c2ad37aa0a9 100644 --- a/shared/teams/team/index.tsx +++ b/shared/teams/team/index.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' @@ -18,7 +18,7 @@ import { type Section, type Item, } from './rows' -import {useBotsState} from '@/constants/bots' +import {useBotsState} from '@/stores/bots' type Props = { teamID: T.Teams.TeamID diff --git a/shared/teams/team/member/add-to-channels.tsx b/shared/teams/team/member/add-to-channels.tsx index 79922967b9e1..3e3035cb798e 100644 --- a/shared/teams/team/member/add-to-channels.tsx +++ b/shared/teams/team/member/add-to-channels.tsx @@ -1,14 +1,14 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as Kb from '@/common-adapters' import * as Common from '@/teams/common' import {pluralize} from '@/util/string' import {useAllChannelMetas} from '@/teams/common/channel-hooks' import {useSafeNavigation} from '@/util/safe-navigation' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type Props = { teamID: T.Teams.TeamID diff --git a/shared/teams/team/member/edit-channel.tsx b/shared/teams/team/member/edit-channel.tsx index 95679a91a100..1f1a49e5f552 100644 --- a/shared/teams/team/member/edit-channel.tsx +++ b/shared/teams/team/member/edit-channel.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as React from 'react' import type * as T from '@/constants/types' import {ModalTitle} from '@/teams/common' diff --git a/shared/teams/team/member/index.new.tsx b/shared/teams/team/member/index.new.tsx index 3ac20ce63dfa..c5bcd10e5aa9 100644 --- a/shared/teams/team/member/index.new.tsx +++ b/shared/teams/team/member/index.new.tsx @@ -1,8 +1,8 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import {useCurrentUserState} from '@/constants/current-user' -import * as Teams from '@/constants/teams' -import {useProfileState} from '@/constants/profile' +import * as Chat from '@/stores/chat2' +import {useCurrentUserState} from '@/stores/current-user' +import * as Teams from '@/stores/teams' +import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import * as React from 'react' diff --git a/shared/teams/team/menu-container.tsx b/shared/teams/team/menu-container.tsx index 4e63c738378f..fdc3047a780a 100644 --- a/shared/teams/team/menu-container.tsx +++ b/shared/teams/team/menu-container.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import type * as React from 'react' import * as FS from '@/constants/fs/util' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import capitalize from 'lodash/capitalize' import * as T from '@/constants/types' import {pluralize} from '@/util/string' diff --git a/shared/teams/team/new-header.tsx b/shared/teams/team/new-header.tsx index bbdf3a4bb0aa..b5f05946e03b 100644 --- a/shared/teams/team/new-header.tsx +++ b/shared/teams/team/new-header.tsx @@ -1,15 +1,15 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import TeamMenu from './menu-container' import {pluralize} from '@/util/string' import {Activity, useActivityLevels, useTeamLinkPopup} from '../common' import type * as T from '@/constants/types' import {useSafeNavigation} from '@/util/safe-navigation' -import {useCurrentUserState} from '@/constants/current-user' -import {useTeamsState} from '@/constants/teams' +import {useCurrentUserState} from '@/stores/current-user' +import {useTeamsState} from '@/stores/teams' const AddPeopleButton = ({teamID}: {teamID: T.Teams.TeamID}) => { const startAddMembersWizard = useTeamsState(s => s.dispatch.startAddMembersWizard) diff --git a/shared/teams/team/rows/bot-row/bot.tsx b/shared/teams/team/rows/bot-row/bot.tsx index a6fb1ef29367..4724d6429e39 100644 --- a/shared/teams/team/rows/bot-row/bot.tsx +++ b/shared/teams/team/rows/bot-row/bot.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import BotMenu from './bot-menu' -import {useBotsState} from '@/constants/bots' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' +import {useBotsState} from '@/stores/bots' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' export type Props = { botAlias: string diff --git a/shared/teams/team/rows/channel-row/channel.tsx b/shared/teams/team/rows/channel-row/channel.tsx index 846b88deb7e1..3b8b31017ac0 100644 --- a/shared/teams/team/rows/channel-row/channel.tsx +++ b/shared/teams/team/rows/channel-row/channel.tsx @@ -4,8 +4,8 @@ import type * as T from '@/constants/types' import {Activity, useChannelParticipants} from '@/teams/common' import {pluralize} from '@/util/string' import {useSafeNavigation} from '@/util/safe-navigation' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' type ChannelRowProps = { conversationIDKey: T.Chat.ConversationIDKey diff --git a/shared/teams/team/rows/emoji-row/add.tsx b/shared/teams/team/rows/emoji-row/add.tsx index b4381e54f327..b48b58e984e4 100644 --- a/shared/teams/team/rows/emoji-row/add.tsx +++ b/shared/teams/team/rows/emoji-row/add.tsx @@ -1,8 +1,8 @@ import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import {useSafeNavigation} from '@/util/safe-navigation' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' type OwnProps = { teamID: T.Teams.TeamID diff --git a/shared/teams/team/rows/emoji-row/item.tsx b/shared/teams/team/rows/emoji-row/item.tsx index dfc547d4cafc..41c72d14f68b 100644 --- a/shared/teams/team/rows/emoji-row/item.tsx +++ b/shared/teams/team/rows/emoji-row/item.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as T from '@/constants/types' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import * as Kb from '@/common-adapters' import * as dateFns from 'date-fns' @@ -8,7 +8,7 @@ import {RPCToEmojiData} from '@/common-adapters/emoji' import EmojiMenu from './emoji-menu' import {useEmojiState} from '@/teams/emojis/use-emoji' import {useSafeNavigation} from '@/util/safe-navigation' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type OwnProps = { conversationIDKey: T.Chat.ConversationIDKey diff --git a/shared/teams/team/rows/empty-row.tsx b/shared/teams/team/rows/empty-row.tsx index b30917726587..df3f9f02eaaa 100644 --- a/shared/teams/team/rows/empty-row.tsx +++ b/shared/teams/team/rows/empty-row.tsx @@ -1,10 +1,10 @@ import type * as T from '@/constants/types' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import * as Teams from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import {useSafeNavigation} from '@/util/safe-navigation' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type Props = { type: 'channelsEmpty' | 'channelsFew' | 'members' | 'subteams' diff --git a/shared/teams/team/rows/index.tsx b/shared/teams/team/rows/index.tsx index cef7d9413a38..ddfe2b0808fa 100644 --- a/shared/teams/team/rows/index.tsx +++ b/shared/teams/team/rows/index.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as T from '@/constants/types' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as React from 'react' import EmptyRow from './empty-row' @@ -14,7 +14,7 @@ import {RequestRow, InviteRow} from './invite-row' import {SubteamAddRow, SubteamInfoRow, SubteamTeamRow} from './subteam-row' import {getOrderedMemberArray, sortInvites, getOrderedBotsArray} from './helpers' import {useEmojiState} from '../../emojis/use-emoji' -import {useCurrentUserState} from '@/constants/current-user' +import {useCurrentUserState} from '@/stores/current-user' type Requests = Omit, 'firstItem' | 'teamID'> diff --git a/shared/teams/team/rows/invite-row/invite.tsx b/shared/teams/team/rows/invite-row/invite.tsx index 78b2c553a7c0..ff3f9958b352 100644 --- a/shared/teams/team/rows/invite-row/invite.tsx +++ b/shared/teams/team/rows/invite-row/invite.tsx @@ -2,8 +2,8 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import {formatPhoneNumber} from '@/util/phone-numbers' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' export type Props = { isKeybaseUser?: boolean diff --git a/shared/teams/team/rows/invite-row/request.tsx b/shared/teams/team/rows/invite-row/request.tsx index a4342c9d8e08..36be8c8e829c 100644 --- a/shared/teams/team/rows/invite-row/request.tsx +++ b/shared/teams/team/rows/invite-row/request.tsx @@ -1,8 +1,8 @@ import * as React from 'react' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import * as Teams from '@/constants/teams' -import {useProfileState} from '@/constants/profile' +import * as Chat from '@/stores/chat2' +import * as Teams from '@/stores/teams' +import {useProfileState} from '@/stores/profile' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {FloatingRolePicker, sendNotificationFooter} from '@/teams/role-picker' diff --git a/shared/teams/team/rows/member-row.tsx b/shared/teams/team/rows/member-row.tsx index 5c74bd5d754e..7fc8920b2a01 100644 --- a/shared/teams/team/rows/member-row.tsx +++ b/shared/teams/team/rows/member-row.tsx @@ -1,15 +1,15 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as Kb from '@/common-adapters' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as React from 'react' import type * as T from '@/constants/types' import MenuHeader from './menu-header.new' import {useSafeNavigation} from '@/util/safe-navigation' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' -import {useUsersState} from '@/constants/users' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' +import {useUsersState} from '@/stores/users' +import {useCurrentUserState} from '@/stores/current-user' export type Props = { firstItem: boolean diff --git a/shared/teams/team/rows/subteam-row/add.tsx b/shared/teams/team/rows/subteam-row/add.tsx index 6e80257e3113..58102c169fa9 100644 --- a/shared/teams/team/rows/subteam-row/add.tsx +++ b/shared/teams/team/rows/subteam-row/add.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import {useTeamsState} from '@/constants/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' diff --git a/shared/teams/team/settings-tab/default-channels.tsx b/shared/teams/team/settings-tab/default-channels.tsx index 4bd9dbf45d56..76524135f8bc 100644 --- a/shared/teams/team/settings-tab/default-channels.tsx +++ b/shared/teams/team/settings-tab/default-channels.tsx @@ -4,8 +4,8 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import type {RPCError} from '@/util/errors' import {ChannelsWidget} from '@/teams/common' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' type Props = { teamID: T.Teams.TeamID diff --git a/shared/teams/team/settings-tab/index.tsx b/shared/teams/team/settings-tab/index.tsx index 264e7690abad..5b83a2071295 100644 --- a/shared/teams/team/settings-tab/index.tsx +++ b/shared/teams/team/settings-tab/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import * as Teams from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import * as Teams from '@/stores/teams' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {FloatingRolePicker} from '@/teams/role-picker' diff --git a/shared/teams/team/settings-tab/retention/index.tsx b/shared/teams/team/settings-tab/retention/index.tsx index 3fc393dd4026..0c539384b43c 100644 --- a/shared/teams/team/settings-tab/retention/index.tsx +++ b/shared/teams/team/settings-tab/retention/index.tsx @@ -1,8 +1,8 @@ import * as C from '@/constants' -import * as Chat from '@/constants/chat2' +import * as Chat from '@/stores/chat2' import * as React from 'react' -import * as Teams from '@/constants/teams' -import {useTeamsState} from '@/constants/teams' +import * as Teams from '@/stores/teams' +import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import type {StylesCrossPlatform} from '@/styles' diff --git a/shared/teams/team/tabs.tsx b/shared/teams/team/tabs.tsx index a27c8027232c..a2fcf15ecd24 100644 --- a/shared/teams/team/tabs.tsx +++ b/shared/teams/team/tabs.tsx @@ -1,8 +1,8 @@ import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import * as C from '@/constants' -import * as Chat from '@/constants/chat2' -import * as Teams from '@/constants/teams' +import * as Chat from '@/stores/chat2' +import * as Teams from '@/stores/teams' import type {Tab as TabType} from '@/common-adapters/tabs' type TeamTabsProps = { diff --git a/shared/teams/team/team-info.tsx b/shared/teams/team/team-info.tsx index 5c1a170c27e5..4eb6002f45b9 100644 --- a/shared/teams/team/team-info.tsx +++ b/shared/teams/team/team-info.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as React from 'react' -import * as Teams from '@/constants/teams' +import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import {ModalTitle} from '../common' diff --git a/shared/tracker2/assertion.tsx b/shared/tracker2/assertion.tsx index 57a0014647c3..41a35459911b 100644 --- a/shared/tracker2/assertion.tsx +++ b/shared/tracker2/assertion.tsx @@ -1,16 +1,16 @@ import * as React from 'react' import * as C from '@/constants' -import {useConfigState} from '@/constants/config' -import {useCurrentUserState} from '@/constants/current-user' +import {useConfigState} from '@/stores/config' +import {useCurrentUserState} from '@/stores/current-user' import type * as T from '@/constants/types' import openUrl from '@/util/open-url' import * as Kb from '@/common-adapters' import {SiteIcon} from '@/profile/generic/shared' import {formatTimeForAssertionPopup} from '@/util/timestamp' import {useColorScheme} from 'react-native' -import * as Tracker from '@/constants/tracker2' -import {useTrackerState} from '@/constants/tracker2' -import {useProfileState} from '@/constants/profile' +import * as Tracker from '@/stores/tracker2' +import {useTrackerState} from '@/stores/tracker2' +import {useProfileState} from '@/stores/profile' type OwnProps = { isSuggestion?: boolean diff --git a/shared/tracker2/bio.tsx b/shared/tracker2/bio.tsx index 9113b0f41b25..e26d67af9457 100644 --- a/shared/tracker2/bio.tsx +++ b/shared/tracker2/bio.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' -import {useTrackerState} from '@/constants/tracker2' -import {useFollowerState} from '@/constants/followers' +import {useTrackerState} from '@/stores/tracker2' +import {useFollowerState} from '@/stores/followers' type OwnProps = { inTracker: boolean diff --git a/shared/tracker2/remote-container.desktop.tsx b/shared/tracker2/remote-container.desktop.tsx index 16c3549ec2ca..4433a19c09b2 100644 --- a/shared/tracker2/remote-container.desktop.tsx +++ b/shared/tracker2/remote-container.desktop.tsx @@ -1,7 +1,7 @@ // Inside tracker we use an embedded Avatar which is connected. import * as React from 'react' import * as C from '@/constants' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import * as R from '@/constants/remote' import * as RemoteGen from '../actions/remote-gen' import type * as T from '@/constants/types' @@ -9,11 +9,11 @@ import Tracker from './index.desktop' import type {DeserializeProps} from './remote-serializer.desktop' import KB2 from '@/util/electron.desktop' import {useAvatarState} from '@/common-adapters/avatar/store' -import {useTrackerState} from '@/constants/tracker2' -import {useUsersState} from '@/constants/users' -import {useFollowerState} from '@/constants/followers' -import {useCurrentUserState} from '@/constants/current-user' -import {useDarkModeState} from '@/constants/darkmode' +import {useTrackerState} from '@/stores/tracker2' +import {useUsersState} from '@/stores/users' +import {useFollowerState} from '@/stores/followers' +import {useCurrentUserState} from '@/stores/current-user' +import {useDarkModeState} from '@/stores/darkmode' const {closeWindow} = KB2.functions diff --git a/shared/tracker2/remote-proxy.desktop.tsx b/shared/tracker2/remote-proxy.desktop.tsx index f8ca55fb0c87..0cb25baaab0f 100644 --- a/shared/tracker2/remote-proxy.desktop.tsx +++ b/shared/tracker2/remote-proxy.desktop.tsx @@ -1,7 +1,7 @@ // A mirror of the remote tracker windows. import * as C from '@/constants' import {useAvatarState} from '@/common-adapters/avatar/store' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' import * as React from 'react' import useSerializeProps from '../desktop/remote/use-serialize-props.desktop' import useBrowserWindow from '../desktop/remote/use-browser-window.desktop' @@ -9,10 +9,10 @@ import {serialize, type ProxyProps} from './remote-serializer.desktop' import {intersect} from '@/util/set' import {mapFilterByKey} from '@/util/map' import {useColorScheme} from 'react-native' -import {useTrackerState} from '@/constants/tracker2' -import {useUsersState} from '@/constants/users' -import {useFollowerState} from '@/constants/followers' -import {useCurrentUserState} from '@/constants/current-user' +import {useTrackerState} from '@/stores/tracker2' +import {useUsersState} from '@/stores/users' +import {useFollowerState} from '@/stores/followers' +import {useCurrentUserState} from '@/stores/current-user' const MAX_TRACKERS = 5 const windowOpts = {hasShadow: false, height: 470, transparent: true, width: 320} diff --git a/shared/unlock-folders/device-list.desktop.tsx b/shared/unlock-folders/device-list.desktop.tsx index 9a2456b13680..ab64aeb86072 100644 --- a/shared/unlock-folders/device-list.desktop.tsx +++ b/shared/unlock-folders/device-list.desktop.tsx @@ -1,5 +1,5 @@ import * as Kb from '@/common-adapters' -import type {State as ConfigStore} from '@/constants/config' +import type {State as ConfigStore} from '@/stores/config' export type Props = { devices: ConfigStore['unlockFoldersDevices'] diff --git a/shared/unlock-folders/index.desktop.tsx b/shared/unlock-folders/index.desktop.tsx index d8cd03f4894a..af45ee616ebd 100644 --- a/shared/unlock-folders/index.desktop.tsx +++ b/shared/unlock-folders/index.desktop.tsx @@ -4,8 +4,8 @@ import DeviceList from './device-list.desktop' import DragHeader from '../desktop/remote/drag-header.desktop' import PaperKeyInput from './paper-key-input.desktop' import Success from './success.desktop' -import type * as Constants from '@/constants/unlock-folders' -import type {State as ConfigStore} from '@/constants/config' +import type * as Constants from '@/stores/unlock-folders' +import type {State as ConfigStore} from '@/stores/config' export type Props = { phase: Constants.State['phase'] diff --git a/shared/unlock-folders/remote-container.desktop.tsx b/shared/unlock-folders/remote-container.desktop.tsx index 15446563ffc6..18db5590d794 100644 --- a/shared/unlock-folders/remote-container.desktop.tsx +++ b/shared/unlock-folders/remote-container.desktop.tsx @@ -3,8 +3,8 @@ import * as React from 'react' import * as RemoteGen from '../actions/remote-gen' import UnlockFolders from './index.desktop' import type {DeserializeProps} from './remote-serializer.desktop' -import {useUnlockFoldersState as useUFState} from '@/constants/unlock-folders' -import {useDarkModeState} from '@/constants/darkmode' +import {useUnlockFoldersState as useUFState} from '@/stores/unlock-folders' +import {useDarkModeState} from '@/stores/darkmode' const RemoteContainer = (d: DeserializeProps) => { const {darkMode, devices, waiting, paperKeyError: _error} = d diff --git a/shared/unlock-folders/remote-proxy.desktop.tsx b/shared/unlock-folders/remote-proxy.desktop.tsx index 34ae7ba99c1d..ebe89bf3d4b7 100644 --- a/shared/unlock-folders/remote-proxy.desktop.tsx +++ b/shared/unlock-folders/remote-proxy.desktop.tsx @@ -4,7 +4,7 @@ import useBrowserWindow from '../desktop/remote/use-browser-window.desktop' import useSerializeProps from '../desktop/remote/use-serialize-props.desktop' import {serialize, type ProxyProps} from './remote-serializer.desktop' import {useColorScheme} from 'react-native' -import {useConfigState} from '@/constants/config' +import {useConfigState} from '@/stores/config' const windowOpts = {height: 300, width: 500} diff --git a/shared/unlock-folders/remote-serializer.desktop.tsx b/shared/unlock-folders/remote-serializer.desktop.tsx index 0370a4c3a86c..b46524dc672d 100644 --- a/shared/unlock-folders/remote-serializer.desktop.tsx +++ b/shared/unlock-folders/remote-serializer.desktop.tsx @@ -1,5 +1,5 @@ import * as T from '@/constants/types' -import type * as ConfigConstants from '@/constants/config' +import type * as ConfigConstants from '@/stores/config' import {produce} from 'immer' export type ProxyProps = { diff --git a/shared/util/phone-numbers/index.tsx b/shared/util/phone-numbers/index.tsx index 7c419b18d118..587795dbaf09 100644 --- a/shared/util/phone-numbers/index.tsx +++ b/shared/util/phone-numbers/index.tsx @@ -2,10 +2,10 @@ import * as C from '@/constants' import libphonenumber from 'google-libphonenumber' const PNF = libphonenumber.PhoneNumberFormat -export const PhoneNumberFormat = PNF +const PhoneNumberFormat = PNF -export const phoneUtil = libphonenumber.PhoneNumberUtil.getInstance() -export const ValidationResult = libphonenumber.PhoneNumberUtil.ValidationResult +const phoneUtil = libphonenumber.PhoneNumberUtil.getInstance() +const ValidationResult = libphonenumber.PhoneNumberUtil.ValidationResult const supported = phoneUtil.getSupportedRegions() export type CountryData = { @@ -188,3 +188,17 @@ export const formatPhoneNumberInternational = (rawNumber: string): string | unde return undefined } } + +// Get phone number in e.164, or null if we can't parse it. +export const getE164 = (phoneNumber: string, countryCode?: string) => { + try { + const parsed = countryCode ? phoneUtil.parse(phoneNumber, countryCode) : phoneUtil.parse(phoneNumber) + const reason = phoneUtil.isPossibleNumberWithReason(parsed) + if (reason !== ValidationResult.IS_POSSIBLE) { + return null + } + return phoneUtil.format(parsed, PhoneNumberFormat.E164) + } catch { + return null + } +} diff --git a/shared/wallets/index.tsx b/shared/wallets/index.tsx index 796c7dc738ab..9cdbccfe61df 100644 --- a/shared/wallets/index.tsx +++ b/shared/wallets/index.tsx @@ -2,8 +2,8 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import * as Wallets from '@/constants/wallets' -import {useState as useWalletsState} from '@/constants/wallets' +import * as Wallets from '@/stores/wallets' +import {useState as useWalletsState} from '@/stores/wallets' const Row = (p: {account: Wallets.Account}) => { const {account} = p diff --git a/shared/wallets/really-remove-account.tsx b/shared/wallets/really-remove-account.tsx index e72a8cf90bba..88c7ad3c6408 100644 --- a/shared/wallets/really-remove-account.tsx +++ b/shared/wallets/really-remove-account.tsx @@ -3,9 +3,9 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import * as React from 'react' import WalletPopup from './wallet-popup' -import * as Wallets from '@/constants/wallets' -import {useState as useWalletsState} from '@/constants/wallets' -import {useConfigState} from '@/constants/config' +import * as Wallets from '@/stores/wallets' +import {useState as useWalletsState} from '@/stores/wallets' +import {useConfigState} from '@/stores/config' type OwnProps = {accountID: string} diff --git a/shared/wallets/remove-account.tsx b/shared/wallets/remove-account.tsx index 6088a87265c4..4847147c1825 100644 --- a/shared/wallets/remove-account.tsx +++ b/shared/wallets/remove-account.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import WalletPopup from './wallet-popup' -import {useState as useWalletsState} from '@/constants/wallets' +import {useState as useWalletsState} from '@/stores/wallets' type OwnProps = {accountID: string} diff --git a/shared/whats-new/container.tsx b/shared/whats-new/container.tsx index 605376435ff3..5f2fbf69501d 100644 --- a/shared/whats-new/container.tsx +++ b/shared/whats-new/container.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' import openURL from '@/util/open-url' -import {currentVersion} from '@/constants/whats-new' +import {currentVersion} from '@/stores/whats-new' import {Current, Last, LastLast} from './versions' import WhatsNew from '.' -import {useWhatsNewState as useWNState} from '@/constants/whats-new' -import {useConfigState} from '@/constants/config' +import {useWhatsNewState as useWNState} from '@/stores/whats-new' +import {useConfigState} from '@/stores/config' const WhatsNewContainer = () => { const _onNavigateExternal = (url: string) => { diff --git a/shared/whats-new/icon/index.tsx b/shared/whats-new/icon/index.tsx index 05ca4fb3b455..08ee61d17832 100644 --- a/shared/whats-new/icon/index.tsx +++ b/shared/whats-new/icon/index.tsx @@ -1,10 +1,10 @@ import * as React from 'react' import * as Kb from '@/common-adapters' import type {IconStyle} from '@/common-adapters/icon' -import {keybaseFM} from '@/constants/whats-new' +import {keybaseFM} from '@/stores/whats-new' import Popup from './popup' import './icon.css' -import {useWhatsNewState as useWNState} from '@/constants/whats-new' +import {useWhatsNewState as useWNState} from '@/stores/whats-new' type OwnProps = { color?: string diff --git a/shared/whats-new/index.tsx b/shared/whats-new/index.tsx index f52f93af4ef6..f15609db9263 100644 --- a/shared/whats-new/index.tsx +++ b/shared/whats-new/index.tsx @@ -1,7 +1,7 @@ import type * as React from 'react' import * as Kb from '@/common-adapters' import type * as C from '@/constants' -import {currentVersion, lastVersion, lastLastVersion} from '@/constants/whats-new' +import {currentVersion, lastVersion, lastLastVersion} from '@/stores/whats-new' import type {VersionProps} from './versions' type Props = { diff --git a/shared/whats-new/versions.tsx b/shared/whats-new/versions.tsx index cd3763ab6b12..05433c1fa130 100644 --- a/shared/whats-new/versions.tsx +++ b/shared/whats-new/versions.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import {encryptTab} from '@/constants/crypto/util' import type * as React from 'react' import * as Kb from '@/common-adapters' -import {keybaseFM} from '@/constants/whats-new' +import {keybaseFM} from '@/stores/whats-new' import NewFeatureRow from './new-feature-row' import {settingsCryptoTab, settingsDisplayTab} from '@/constants/settings/util' From b7fab697e70a5f673293ce61419d9d0d9019161d Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Mon, 12 Jan 2026 10:20:44 -0500 Subject: [PATCH 12/20] WIP: shift 13 (#28795) * WIP * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/app/global-errors/hook.tsx | 2 +- shared/common-adapters/reload.tsx | 2 +- shared/constants/chat2/convostate.tsx | 10 +++++----- shared/constants/chat2/{util.tsx => index.tsx} | 0 shared/constants/chat2/message.tsx | 8 ++++---- shared/constants/chat2/meta.tsx | 6 +++--- shared/constants/{config/util.tsx => config.tsx} | 2 +- shared/constants/{crypto/util.tsx => crypto.tsx} | 2 +- .../constants/{deeplinks/index.tsx => deeplinks.tsx} | 8 ++++---- shared/constants/fs/{util.tsx => index.tsx} | 4 ++-- shared/constants/fs/platform-specific.desktop.tsx | 2 +- shared/constants/init/index.desktop.tsx | 2 +- shared/constants/init/shared.tsx | 2 +- .../{notifications/util.tsx => notifications.tsx} | 0 shared/constants/{people/util.tsx => people.tsx} | 0 shared/constants/platform-specific/push.native.tsx | 2 +- shared/constants/push.native.tsx | 4 ++-- .../utils.tsx => recover-password.tsx} | 0 shared/constants/{router2/util.tsx => router2.tsx} | 11 +++++------ shared/constants/{settings/util.tsx => settings.tsx} | 0 .../{team-building/utils.tsx => team-building.tsx} | 2 +- shared/constants/{teams/util.tsx => teams.tsx} | 2 +- shared/constants/{tracker2/util.tsx => tracker2.tsx} | 0 .../{unlock-folders/util.tsx => unlock-folders.tsx} | 0 shared/constants/{users/util.tsx => users.tsx} | 0 shared/constants/{wallets/utils.tsx => wallets.tsx} | 0 .../constants/{whats-new/utils.tsx => whats-new.tsx} | 0 shared/crypto/routes.tsx | 2 +- shared/desktop/renderer/main2.desktop.tsx | 4 ++-- shared/login/routes.tsx | 2 +- shared/people/announcement.tsx | 2 +- shared/people/todo.tsx | 2 +- shared/router-v2/account-switcher/index.tsx | 2 +- shared/router-v2/tab-bar.desktop.tsx | 2 +- shared/settings/routes.tsx | 2 +- shared/stores/archive.tsx | 8 ++++---- shared/stores/autoreset.tsx | 4 ++-- shared/stores/chat2.tsx | 6 +++--- shared/stores/config.tsx | 4 ++-- shared/stores/crypto.tsx | 6 +++--- shared/stores/fs.tsx | 8 ++++---- shared/stores/git.tsx | 2 +- shared/stores/logout.tsx | 4 ++-- shared/stores/notifications.tsx | 2 +- shared/stores/pinentry.tsx | 2 +- shared/stores/profile.tsx | 6 +++--- shared/stores/provision.tsx | 4 ++-- shared/stores/recover-password.tsx | 4 ++-- shared/stores/router2.tsx | 8 ++++---- shared/stores/settings-contacts.d.ts | 2 +- shared/stores/settings-contacts.native.tsx | 8 ++++---- shared/stores/settings-invites.tsx | 2 +- shared/stores/settings-password.tsx | 2 +- shared/stores/settings.tsx | 8 ++++---- shared/stores/signup.tsx | 4 ++-- shared/{constants => stores}/store-registry.tsx | 0 shared/stores/team-building.tsx | 8 ++++---- shared/stores/teams.tsx | 10 +++++----- shared/stores/tracker2.tsx | 4 ++-- shared/stores/wallets.tsx | 4 ++-- shared/stores/whats-new.tsx | 4 ++-- shared/team-building/phone-search.tsx | 2 +- shared/teams/team/menu-container.tsx | 2 +- shared/util/crop.tsx | 2 +- shared/whats-new/versions.tsx | 4 ++-- 65 files changed, 111 insertions(+), 112 deletions(-) rename shared/constants/chat2/{util.tsx => index.tsx} (100%) rename shared/constants/{config/util.tsx => config.tsx} (96%) rename shared/constants/{crypto/util.tsx => crypto.tsx} (98%) rename shared/constants/{deeplinks/index.tsx => deeplinks.tsx} (98%) rename shared/constants/fs/{util.tsx => index.tsx} (99%) rename shared/constants/{notifications/util.tsx => notifications.tsx} (100%) rename shared/constants/{people/util.tsx => people.tsx} (100%) rename shared/constants/{recover-password/utils.tsx => recover-password.tsx} (100%) rename shared/constants/{router2/util.tsx => router2.tsx} (98%) rename shared/constants/{settings/util.tsx => settings.tsx} (100%) rename shared/constants/{team-building/utils.tsx => team-building.tsx} (93%) rename shared/constants/{teams/util.tsx => teams.tsx} (99%) rename shared/constants/{tracker2/util.tsx => tracker2.tsx} (100%) rename shared/constants/{unlock-folders/util.tsx => unlock-folders.tsx} (100%) rename shared/constants/{users/util.tsx => users.tsx} (100%) rename shared/constants/{wallets/utils.tsx => wallets.tsx} (100%) rename shared/constants/{whats-new/utils.tsx => whats-new.tsx} (100%) rename shared/{constants => stores}/store-registry.tsx (100%) diff --git a/shared/app/global-errors/hook.tsx b/shared/app/global-errors/hook.tsx index f35ad7056a9c..d8e9d9701d30 100644 --- a/shared/app/global-errors/hook.tsx +++ b/shared/app/global-errors/hook.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import * as React from 'react' import {useConfigState} from '@/stores/config' import type {RPCError} from '@/util/errors' -import {settingsFeedbackTab} from '@/constants/settings/util' +import {settingsFeedbackTab} from '@/constants/settings' import {useDaemonState} from '@/stores/daemon' export type Size = 'Closed' | 'Small' | 'Big' diff --git a/shared/common-adapters/reload.tsx b/shared/common-adapters/reload.tsx index 08fe71c05cd7..03279bdf596a 100644 --- a/shared/common-adapters/reload.tsx +++ b/shared/common-adapters/reload.tsx @@ -9,7 +9,7 @@ import Text from './text' import Button from './button' import Icon from './icon' import type {RPCError} from '@/util/errors' -import {settingsFeedbackTab} from '@/constants/settings/util' +import {settingsFeedbackTab} from '@/constants/settings' import {useConfigState} from '@/stores/config' const Kb = { diff --git a/shared/constants/chat2/convostate.tsx b/shared/constants/chat2/convostate.tsx index a1c4d33dd1df..5f2b250a8c10 100644 --- a/shared/constants/chat2/convostate.tsx +++ b/shared/constants/chat2/convostate.tsx @@ -1,6 +1,6 @@ // TODO remove useChatNavigateAppend // TODO remove -import * as TeamsUtil from '../teams/util' +import * as TeamsUtil from '../teams' import * as PlatformSpecific from '../platform-specific' import { clearModals, @@ -11,7 +11,7 @@ import { getVisibleScreen, getModalStack, navToThread, -} from '../router2/util' +} from '../router2' import {isIOS} from '../platform' import {updateImmer} from '../utils' import * as T from '../types' @@ -23,7 +23,7 @@ import * as Message from './message' import * as Meta from './meta' import * as React from 'react' import * as Z from '@/util/zustand' -import {makeActionForOpenPathInFilesTab} from '@/constants/fs/util' +import {makeActionForOpenPathInFilesTab} from '@/constants/fs' import HiddenString from '@/util/hidden-string' import isEqual from 'lodash/isEqual' import logger from '@/logger' @@ -41,12 +41,12 @@ import {hexToUint8Array} from 'uint8array-extras' import assign from 'lodash/assign' import {clearChatTimeCache} from '@/util/timestamp' import {registerDebugClear} from '@/util/debug' -import * as Config from '@/constants/config/util' +import * as Config from '@/constants/config' import {isMobile} from '@/constants/platform' import {enumKeys, ignorePromise, shallowEqual} from '../utils' import * as Strings from '@/constants/strings' -import {storeRegistry} from '../store-registry' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' diff --git a/shared/constants/chat2/util.tsx b/shared/constants/chat2/index.tsx similarity index 100% rename from shared/constants/chat2/util.tsx rename to shared/constants/chat2/index.tsx diff --git a/shared/constants/chat2/message.tsx b/shared/constants/chat2/message.tsx index c35c576d07e2..2897f2899bb1 100644 --- a/shared/constants/chat2/message.tsx +++ b/shared/constants/chat2/message.tsx @@ -1,14 +1,14 @@ // Message related constants import * as T from '../types' -import * as TeamsUtil from '../teams/util' +import * as TeamsUtil from '@/constants/teams' import type * as ConvoConstants from './convostate' import HiddenString from '@/util/hidden-string' import logger from '@/logger' -import type * as MessageTypes from '../types/chat2/message' +import type * as MessageTypes from '@/constants/types/chat2/message' import type {ServiceId} from 'util/platforms' -import {noConversationIDKey} from '../types/chat2/common' +import {noConversationIDKey} from '@/constants/types/chat2/common' import invert from 'lodash/invert' -import {isIOS, isMobile} from '../platform' +import {isIOS, isMobile} from '@/constants/platform' const noString = new HiddenString('') diff --git a/shared/constants/chat2/meta.tsx b/shared/constants/chat2/meta.tsx index 93b889627441..1540e8f9879f 100644 --- a/shared/constants/chat2/meta.tsx +++ b/shared/constants/chat2/meta.tsx @@ -1,10 +1,10 @@ // Meta manages the metadata about a conversation. Participants, isMuted, reset people, etc. Things that drive the inbox import {shallowEqual} from '../utils' -import * as T from '../types' -import * as Teams from '../teams/util' +import * as T from '@/constants/types' +import * as Teams from '@/constants/teams' import * as Message from './message' import {base64ToUint8Array, uint8ArrayToHex} from 'uint8array-extras' -import {storeRegistry} from '../store-registry' +import {storeRegistry} from '@/stores/store-registry' import {useCurrentUserState} from '@/stores/current-user' const conversationMemberStatusToMembershipType = (m: T.RPCChat.ConversationMemberStatus) => { diff --git a/shared/constants/config/util.tsx b/shared/constants/config.tsx similarity index 96% rename from shared/constants/config/util.tsx rename to shared/constants/config.tsx index b44de040a866..954a6daddde8 100644 --- a/shared/constants/config/util.tsx +++ b/shared/constants/config.tsx @@ -1,5 +1,5 @@ import uniq from 'lodash/uniq' -import {runMode} from '../platform' +import {runMode} from './platform' // An ugly error message from the service that we'd like to rewrite ourselves. export const invalidPasswordErrorString = 'Bad password: Invalid password. Server rejected login attempt..' diff --git a/shared/constants/crypto/util.tsx b/shared/constants/crypto.tsx similarity index 98% rename from shared/constants/crypto/util.tsx rename to shared/constants/crypto.tsx index 6f88e37d8e57..459215e60c1f 100644 --- a/shared/constants/crypto/util.tsx +++ b/shared/constants/crypto.tsx @@ -1,4 +1,4 @@ -import {isMobile} from '../platform' +import {isMobile} from './platform' export const saltpackDocumentation = 'https://saltpack.org' export const inputDesktopMaxHeight = {maxHeight: '30%'} as const diff --git a/shared/constants/deeplinks/index.tsx b/shared/constants/deeplinks.tsx similarity index 98% rename from shared/constants/deeplinks/index.tsx rename to shared/constants/deeplinks.tsx index 998f184dc780..23e8d713efc2 100644 --- a/shared/constants/deeplinks/index.tsx +++ b/shared/constants/deeplinks.tsx @@ -1,12 +1,12 @@ -import * as Crypto from '../crypto/util' -import * as Tabs from '../tabs' +import * as Crypto from './crypto' +import * as Tabs from './tabs' import {isPathSaltpackEncrypted, isPathSaltpackSigned} from '@/util/path' import type HiddenString from '@/util/hidden-string' import URL from 'url-parse' import logger from '@/logger' import * as T from '@/constants/types' -import {navigateAppend, switchTab} from '../router2/util' -import {storeRegistry} from '../store-registry' +import {navigateAppend, switchTab} from './router2' +import {storeRegistry} from '@/stores/store-registry' import {useCryptoState} from '@/stores/crypto' import {useConfigState} from '@/stores/config' diff --git a/shared/constants/fs/util.tsx b/shared/constants/fs/index.tsx similarity index 99% rename from shared/constants/fs/util.tsx rename to shared/constants/fs/index.tsx index d57ccfd6c7cc..543c1ff5d733 100644 --- a/shared/constants/fs/util.tsx +++ b/shared/constants/fs/index.tsx @@ -2,8 +2,8 @@ import type * as React from 'react' import * as Tabs from '../tabs' import * as T from '../types' import {isLinux, isMobile} from '../platform' -import {settingsFsTab} from '../settings/util' -import {navigateAppend} from '../router2/util' +import {settingsFsTab} from '../settings' +import {navigateAppend} from '../router2' export const makeActionForOpenPathInFilesTab = ( // TODO: remove the second arg when we are done with migrating to nav2 path: T.FS.Path diff --git a/shared/constants/fs/platform-specific.desktop.tsx b/shared/constants/fs/platform-specific.desktop.tsx index 557910c110af..86c3137c337c 100644 --- a/shared/constants/fs/platform-specific.desktop.tsx +++ b/shared/constants/fs/platform-specific.desktop.tsx @@ -7,7 +7,7 @@ import logger from '@/logger' import * as Path from '@/util/path' import KB2 from '@/util/electron.desktop' import {uint8ArrayToHex} from 'uint8array-extras' -import {navigateAppend} from '../router2/util' +import {navigateAppend} from '../router2' import {useConfigState} from '@/stores/config' const useFSState = Constants.useFSState diff --git a/shared/constants/init/index.desktop.tsx b/shared/constants/init/index.desktop.tsx index c7ba7e02fb83..1b239d9bad46 100644 --- a/shared/constants/init/index.desktop.tsx +++ b/shared/constants/init/index.desktop.tsx @@ -18,7 +18,7 @@ import {isLinux, isWindows} from '@/constants/platform.desktop' import {kbfsNotification} from '@/constants/platform-specific/kbfs-notifications' import {skipAppFocusActions} from '@/local-debug.desktop' import NotifyPopup from '@/util/notify-popup' -import {noKBFSFailReason} from '@/constants/config/util' +import {noKBFSFailReason} from '@/constants/config' import {initSharedSubscriptions, _onEngineIncoming} from './shared' import {wrapErrors} from '@/util/debug' diff --git a/shared/constants/init/shared.tsx b/shared/constants/init/shared.tsx index 7be982c97f36..9c148b3de4e6 100644 --- a/shared/constants/init/shared.tsx +++ b/shared/constants/init/shared.tsx @@ -24,7 +24,7 @@ import type * as UseNotificationsStateType from '@/stores/notifications' import type * as UsePeopleStateType from '@/stores/people' import type * as UsePinentryStateType from '@/stores/pinentry' import {useProvisionState} from '@/stores/provision' -import {storeRegistry} from '../store-registry' +import {storeRegistry} from '@/stores/store-registry' import {useSettingsContactsState} from '@/stores/settings-contacts' import type * as UseSignupStateType from '@/stores/signup' import type * as UseTeamsStateType from '@/stores/teams' diff --git a/shared/constants/notifications/util.tsx b/shared/constants/notifications.tsx similarity index 100% rename from shared/constants/notifications/util.tsx rename to shared/constants/notifications.tsx diff --git a/shared/constants/people/util.tsx b/shared/constants/people.tsx similarity index 100% rename from shared/constants/people/util.tsx rename to shared/constants/people.tsx diff --git a/shared/constants/platform-specific/push.native.tsx b/shared/constants/platform-specific/push.native.tsx index 60d5fb4df93b..dd44edad2b3f 100644 --- a/shared/constants/platform-specific/push.native.tsx +++ b/shared/constants/platform-specific/push.native.tsx @@ -9,7 +9,7 @@ import { getInitialNotification, removeAllPendingNotificationRequests, } from 'react-native-kb' -import {storeRegistry} from '../store-registry' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useLogoutState} from '@/stores/logout' diff --git a/shared/constants/push.native.tsx b/shared/constants/push.native.tsx index 7f115f028fe5..ea5e57e6d087 100644 --- a/shared/constants/push.native.tsx +++ b/shared/constants/push.native.tsx @@ -1,8 +1,8 @@ import * as Tabs from '@/constants/tabs' import * as S from '@/constants/strings' import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from '@/constants/utils' -import {navigateAppend, navUpToScreen, switchTab} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {navigateAppend, navUpToScreen, switchTab} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import {useLogoutState} from '@/stores/logout' diff --git a/shared/constants/recover-password/utils.tsx b/shared/constants/recover-password.tsx similarity index 100% rename from shared/constants/recover-password/utils.tsx rename to shared/constants/recover-password.tsx diff --git a/shared/constants/router2/util.tsx b/shared/constants/router2.tsx similarity index 98% rename from shared/constants/router2/util.tsx rename to shared/constants/router2.tsx index f47b6a479a5e..5da352fedcb7 100644 --- a/shared/constants/router2/util.tsx +++ b/shared/constants/router2.tsx @@ -1,6 +1,6 @@ import type * as React from 'react' -import type * as T from '../types' -import * as Tabs from '../tabs' +import type * as T from './types' +import * as Tabs from './tabs' import { StackActions, CommonActions, @@ -10,11 +10,11 @@ import { type NavigationState, } from '@react-navigation/core' import type {NavigateAppendType, RouteKeys, RootParamList as KBRootParamList} from '@/router-v2/route-params' -import type {GetOptionsRet} from '../types/router2' +import type {GetOptionsRet} from './types/router2' import {produce} from 'immer' import isEqual from 'lodash/isEqual' -import {isMobile, isTablet} from '../platform' -import {shallowEqual, type ViewPropsToPageProps} from '../utils' +import {isMobile, isTablet} from './platform' +import {shallowEqual, type ViewPropsToPageProps} from './utils' import {registerDebugClear} from '@/util/debug' export const navigationRef = createNavigationContainerRef() @@ -440,4 +440,3 @@ export const appendEncryptRecipientsBuilder = () => { selected: 'cryptoTeamBuilder', }) } - diff --git a/shared/constants/settings/util.tsx b/shared/constants/settings.tsx similarity index 100% rename from shared/constants/settings/util.tsx rename to shared/constants/settings.tsx diff --git a/shared/constants/team-building/utils.tsx b/shared/constants/team-building.tsx similarity index 93% rename from shared/constants/team-building/utils.tsx rename to shared/constants/team-building.tsx index e277db5d587f..bdad54ace64d 100644 --- a/shared/constants/team-building/utils.tsx +++ b/shared/constants/team-building.tsx @@ -1,4 +1,4 @@ -import type * as T from '../types' +import type * as T from './types' const searchServices: Array = ['keybase', 'twitter', 'github', 'reddit', 'hackernews'] diff --git a/shared/constants/teams/util.tsx b/shared/constants/teams.tsx similarity index 99% rename from shared/constants/teams/util.tsx rename to shared/constants/teams.tsx index ce11cc0f9c40..5eb4fbea86ff 100644 --- a/shared/constants/teams/util.tsx +++ b/shared/constants/teams.tsx @@ -1,4 +1,4 @@ -import * as T from '../types' +import * as T from './types' import invert from 'lodash/invert' export const makeRetentionPolicy = ( diff --git a/shared/constants/tracker2/util.tsx b/shared/constants/tracker2.tsx similarity index 100% rename from shared/constants/tracker2/util.tsx rename to shared/constants/tracker2.tsx diff --git a/shared/constants/unlock-folders/util.tsx b/shared/constants/unlock-folders.tsx similarity index 100% rename from shared/constants/unlock-folders/util.tsx rename to shared/constants/unlock-folders.tsx diff --git a/shared/constants/users/util.tsx b/shared/constants/users.tsx similarity index 100% rename from shared/constants/users/util.tsx rename to shared/constants/users.tsx diff --git a/shared/constants/wallets/utils.tsx b/shared/constants/wallets.tsx similarity index 100% rename from shared/constants/wallets/utils.tsx rename to shared/constants/wallets.tsx diff --git a/shared/constants/whats-new/utils.tsx b/shared/constants/whats-new.tsx similarity index 100% rename from shared/constants/whats-new/utils.tsx rename to shared/constants/whats-new.tsx diff --git a/shared/crypto/routes.tsx b/shared/crypto/routes.tsx index da93e894f5bb..14200ecfdaf5 100644 --- a/shared/crypto/routes.tsx +++ b/shared/crypto/routes.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import * as C from '@/constants' -import * as Crypto from '@/constants/crypto/util' +import * as Crypto from '@/constants/crypto' import {HeaderLeftCancel2, type HeaderBackButtonProps} from '@/common-adapters/header-hoc' import cryptoTeamBuilder from '../team-building/page' diff --git a/shared/desktop/renderer/main2.desktop.tsx b/shared/desktop/renderer/main2.desktop.tsx index 9a4faab9139f..e2153297bafe 100644 --- a/shared/desktop/renderer/main2.desktop.tsx +++ b/shared/desktop/renderer/main2.desktop.tsx @@ -16,8 +16,8 @@ import {useConfigState} from '@/stores/config' import {usePinentryState} from '@/stores/pinentry' import * as T from '@/constants/types' import {RPCError} from '@/util/errors' -import {switchTab} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {switchTab} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {onEngineConnected, onEngineDisconnected} from '@/constants/init/index.desktop' import {handleAppLink, handleSaltPackOpen} from '@/constants/deeplinks' import logger from '@/logger' diff --git a/shared/login/routes.tsx b/shared/login/routes.tsx index f6d31a7081eb..06d196706d66 100644 --- a/shared/login/routes.tsx +++ b/shared/login/routes.tsx @@ -5,7 +5,7 @@ import {InfoIcon} from '@/signup/common' import {newRoutes as provisionRoutes} from '../provision/routes-sub' import {sharedNewRoutes as settingsRoutes} from '../settings/routes' import {newRoutes as signupRoutes} from './signup/routes' -import {settingsFeedbackTab} from '@/constants/settings/util' +import {settingsFeedbackTab} from '@/constants/settings' const recoverPasswordStyles = Kb.Styles.styleSheetCreate(() => ({ questionBox: Kb.Styles.padding(Kb.Styles.globalMargins.tiny, Kb.Styles.globalMargins.tiny, 0), diff --git a/shared/people/announcement.tsx b/shared/people/announcement.tsx index 8e44e7145ec9..d3807eff4157 100644 --- a/shared/people/announcement.tsx +++ b/shared/people/announcement.tsx @@ -4,7 +4,7 @@ import * as T from '@/constants/types' import openURL from '@/util/open-url' import * as Kb from '@/common-adapters' import PeopleItem from './item' -import * as Settings from '@/constants/settings/util' +import * as Settings from '@/constants/settings' import {usePeopleState} from '@/stores/people' type OwnProps = { diff --git a/shared/people/todo.tsx b/shared/people/todo.tsx index 87cafea4576a..016bc55b3d41 100644 --- a/shared/people/todo.tsx +++ b/shared/people/todo.tsx @@ -8,7 +8,7 @@ import PeopleItem, {type TaskButton} from './item' import * as Kb from '@/common-adapters' import {useSettingsPhoneState} from '@/stores/settings-phone' import {useSettingsEmailState} from '@/stores/settings-email' -import {settingsAccountTab, settingsGitTab} from '@/constants/settings/util' +import {settingsAccountTab, settingsGitTab} from '@/constants/settings' import {useTrackerState} from '@/stores/tracker2' import {useProfileState} from '@/stores/profile' import {usePeopleState, todoTypes} from '@/stores/people' diff --git a/shared/router-v2/account-switcher/index.tsx b/shared/router-v2/account-switcher/index.tsx index fa570869a785..f4a67159ff4d 100644 --- a/shared/router-v2/account-switcher/index.tsx +++ b/shared/router-v2/account-switcher/index.tsx @@ -4,7 +4,7 @@ import {useConfigState} from '@/stores/config' import * as Kb from '@/common-adapters' import * as React from 'react' import type * as T from '@/constants/types' -import {settingsLogOutTab} from '@/constants/settings/util' +import {settingsLogOutTab} from '@/constants/settings' import {useTrackerState} from '@/stores/tracker2' import {useProfileState} from '@/stores/profile' import {useUsersState} from '@/stores/users' diff --git a/shared/router-v2/tab-bar.desktop.tsx b/shared/router-v2/tab-bar.desktop.tsx index a9cceadc90c8..67baf715faf2 100644 --- a/shared/router-v2/tab-bar.desktop.tsx +++ b/shared/router-v2/tab-bar.desktop.tsx @@ -13,7 +13,7 @@ import openURL from '@/util/open-url' import {isLinux} from '@/constants/platform' import KB2 from '@/util/electron.desktop' import './tab-bar.css' -import {settingsLogOutTab} from '@/constants/settings/util' +import {settingsLogOutTab} from '@/constants/settings' import {useTrackerState} from '@/stores/tracker2' import {useFSState} from '@/stores/fs' import {useProfileState} from '@/stores/profile' diff --git a/shared/settings/routes.tsx b/shared/settings/routes.tsx index 71bf575d9e67..dead7baabb06 100644 --- a/shared/settings/routes.tsx +++ b/shared/settings/routes.tsx @@ -3,7 +3,7 @@ import * as C from '@/constants' import {newRoutes as devicesRoutes} from '../devices/routes' import {newRoutes as gitRoutes} from '../git/routes' import {newRoutes as walletsRoutes} from '../wallets/routes' -import * as Settings from '@/constants/settings/util' +import * as Settings from '@/constants/settings' const SettingsRootDesktop = React.lazy(async () => import('./root-desktop-tablet')) diff --git a/shared/stores/archive.tsx b/shared/stores/archive.tsx index 450e6b3ec185..f5869166c8d0 100644 --- a/shared/stores/archive.tsx +++ b/shared/stores/archive.tsx @@ -1,11 +1,11 @@ -import * as T from '../constants/types' +import * as T from '@/constants/types' import * as Z from '@/util/zustand' -import {ignorePromise} from '../constants/utils' +import {ignorePromise} from '@/constants/utils' import * as EngineGen from '@/actions/engine-gen-gen' -import {pathToRPCPath} from '@/constants/fs/util' +import {pathToRPCPath} from '@/constants/fs' import {formatTimeForPopup} from '@/util/timestamp' import {uint8ArrayToHex} from 'uint8array-extras' -import {isMobile} from '../constants/platform' +import {isMobile} from '@/constants/platform' type ChatJob = { id: string diff --git a/shared/stores/autoreset.tsx b/shared/stores/autoreset.tsx index af4e33076267..ebb8f4d61f74 100644 --- a/shared/stores/autoreset.tsx +++ b/shared/stores/autoreset.tsx @@ -5,8 +5,8 @@ import * as T from '@/constants/types' import * as EngineGen from '@/actions/engine-gen-gen' import logger from '@/logger' import {RPCError} from '@/util/errors' -import {navigateAppend, navUpToScreen} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {navigateAppend, navUpToScreen} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' type Store = T.Immutable<{ active: boolean diff --git a/shared/stores/chat2.tsx b/shared/stores/chat2.tsx index 18936b18c5c4..44db48471c5c 100644 --- a/shared/stores/chat2.tsx +++ b/shared/stores/chat2.tsx @@ -5,7 +5,7 @@ import * as EngineGen from '@/actions/engine-gen-gen' import type * as ConfigConstants from '@/stores/config' import * as Message from '@/constants/chat2/message' import * as Router2 from '@/stores/router2' -import * as TeamConstants from '@/constants/teams/util' +import * as TeamConstants from '@/constants/teams' import logger from '@/logger' import {RPCError} from '@/util/errors' import * as Meta from '@/constants/chat2/meta' @@ -16,8 +16,8 @@ import {clearChatStores, chatStores} from '@/constants/chat2/convostate' import {uint8ArrayToString} from 'uint8array-extras' import isEqual from 'lodash/isEqual' import {bodyToJSON} from '@/constants/rpc-utils' -import {navigateAppend, navUpToScreen, switchTab} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {navigateAppend, navUpToScreen, switchTab} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import {useWaitingState} from '@/stores/waiting' diff --git a/shared/stores/config.tsx b/shared/stores/config.tsx index d1a2498cbe20..bed141114cad 100644 --- a/shared/stores/config.tsx +++ b/shared/stores/config.tsx @@ -11,8 +11,8 @@ import type {Tab} from '@/constants/tabs' import {RPCError, convertToError, isEOFError, isErrorTransient, niceError} from '@/util/errors' import {defaultUseNativeFrame, isMobile} from '@/constants/platform' import {type CommonResponseHandler} from '@/engine/types' -import {invalidPasswordErrorString} from '@/constants/config/util' -import {navigateAppend} from '@/constants/router2/util' +import {invalidPasswordErrorString} from '@/constants/config' +import {navigateAppend} from '@/constants/router2' type Store = T.Immutable<{ active: boolean diff --git a/shared/stores/crypto.tsx b/shared/stores/crypto.tsx index 881fb2f59a11..99fd2fdd3781 100644 --- a/shared/stores/crypto.tsx +++ b/shared/stores/crypto.tsx @@ -6,10 +6,10 @@ import HiddenString from '@/util/hidden-string' import logger from '@/logger' import * as T from '@/constants/types' import {RPCError} from '@/util/errors' -import {navigateAppend} from '@/constants/router2/util' +import {navigateAppend} from '@/constants/router2' import {useCurrentUserState} from '@/stores/current-user' -import {Operations} from '@/constants/crypto/util' -export * from '@/constants/crypto/util' +import {Operations} from '@/constants/crypto' +export * from '@/constants/crypto' type CommonStore = { bytesComplete: number diff --git a/shared/stores/fs.tsx b/shared/stores/fs.tsx index ace4730a19c4..a7dbef4ad088 100644 --- a/shared/stores/fs.tsx +++ b/shared/stores/fs.tsx @@ -11,13 +11,13 @@ import logger from '@/logger' import {tlfToPreferredOrder} from '@/util/kbfs' import isObject from 'lodash/isObject' import isEqual from 'lodash/isEqual' -import {navigateAppend, navigateUp} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {navigateAppend, navigateUp} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' -import * as Util from '@/constants/fs/util' +import * as Util from '@/constants/fs' -export * from '@/constants/fs/util' +export * from '@/constants/fs' const subscriptionDeduplicateIntervalSecond = 1 diff --git a/shared/stores/git.tsx b/shared/stores/git.tsx index 9ea6dbc1d2c6..3b09ac438bd7 100644 --- a/shared/stores/git.tsx +++ b/shared/stores/git.tsx @@ -5,7 +5,7 @@ import * as EngineGen from '@/actions/engine-gen-gen' import * as dateFns from 'date-fns' import * as Z from '@/util/zustand' import debounce from 'lodash/debounce' -import {navigateAppend} from '@/constants/router2/util' +import {navigateAppend} from '@/constants/router2' import {useConfigState} from '@/stores/config' const parseRepos = (results: ReadonlyArray) => { diff --git a/shared/stores/logout.tsx b/shared/stores/logout.tsx index 1f4983b4fa0d..1348cca9b47b 100644 --- a/shared/stores/logout.tsx +++ b/shared/stores/logout.tsx @@ -3,8 +3,8 @@ import {ignorePromise, timeoutPromise} from '@/constants/utils' import * as T from '@/constants/types' // normally util.container but it re-exports from us so break the cycle import * as Z from '@/util/zustand' -import {settingsPasswordTab} from '@/constants/settings/util' -import {navigateAppend} from '@/constants/router2/util' +import {settingsPasswordTab} from '@/constants/settings' +import {navigateAppend} from '@/constants/router2' import {isMobile} from '@/constants/platform' import * as Tabs from '@/constants/tabs' diff --git a/shared/stores/notifications.tsx b/shared/stores/notifications.tsx index 3fcbeab6cb8c..5a2304b81a77 100644 --- a/shared/stores/notifications.tsx +++ b/shared/stores/notifications.tsx @@ -4,7 +4,7 @@ import type * as T from '@/constants/types' import {isMobile} from '@/constants/platform' import isEqual from 'lodash/isEqual' import * as Tabs from '@/constants/tabs' -import {storeRegistry} from '@/constants/store-registry' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' diff --git a/shared/stores/pinentry.tsx b/shared/stores/pinentry.tsx index 8ad874ff5cf1..8dc26ad61ace 100644 --- a/shared/stores/pinentry.tsx +++ b/shared/stores/pinentry.tsx @@ -2,7 +2,7 @@ import * as Z from '@/util/zustand' import * as EngineGen from '@/actions/engine-gen-gen' import * as T from '@/constants/types' import logger from '@/logger' -import {invalidPasswordErrorString} from '@/constants/config/util' +import {invalidPasswordErrorString} from '@/constants/config' import {wrapErrors} from '@/constants/utils' // This store has no dependencies on other stores and is safe to import directly from other stores. diff --git a/shared/stores/profile.tsx b/shared/stores/profile.tsx index 8d1f42ea1fef..b0c7204ced98 100644 --- a/shared/stores/profile.tsx +++ b/shared/stores/profile.tsx @@ -7,10 +7,10 @@ import logger from '@/logger' import openURL from '@/util/open-url' import {RPCError} from '@/util/errors' import {fixCrop} from '@/util/crop' -import {clearModals, navigateAppend, navigateUp} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {clearModals, navigateAppend, navigateUp} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {useCurrentUserState} from '@/stores/current-user' -import {navToProfile} from '@/constants/router2/util' +import {navToProfile} from '@/constants/router2' type ProveGenericParams = { logoBlack: T.Tracker.SiteIconSet diff --git a/shared/stores/provision.tsx b/shared/stores/provision.tsx index b30d9a3d5e05..cf3f5c95f5ad 100644 --- a/shared/stores/provision.tsx +++ b/shared/stores/provision.tsx @@ -7,8 +7,8 @@ import {isMobile} from '@/constants/platform' import {type CommonResponseHandler} from '@/engine/types' import isEqual from 'lodash/isEqual' import {rpcDeviceToDevice} from '@/constants/rpc-utils' -import {invalidPasswordErrorString} from '@/constants/config/util' -import {clearModals, navigateAppend} from '@/constants/router2/util' +import {invalidPasswordErrorString} from '@/constants/config' +import {clearModals, navigateAppend} from '@/constants/router2' import {useWaitingState} from '@/stores/waiting' export type Device = { diff --git a/shared/stores/recover-password.tsx b/shared/stores/recover-password.tsx index 464bb2e1aa87..80e96c070b3a 100644 --- a/shared/stores/recover-password.tsx +++ b/shared/stores/recover-password.tsx @@ -6,8 +6,8 @@ import logger from '@/logger' import {RPCError} from '@/util/errors' import {type Device} from '@/stores/provision' import {rpcDeviceToDevice} from '@/constants/rpc-utils' -import {clearModals, navigateAppend, navigateUp} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {clearModals, navigateAppend, navigateUp} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' type Store = T.Immutable<{ diff --git a/shared/stores/router2.tsx b/shared/stores/router2.tsx index 69864067988b..0e5c0c8f2c6e 100644 --- a/shared/stores/router2.tsx +++ b/shared/stores/router2.tsx @@ -2,8 +2,8 @@ import type * as T from '@/constants/types' import * as Z from '@/util/zustand' import * as Tabs from '@/constants/tabs' import type {RouteKeys} from '@/router-v2/route-params' -import {storeRegistry} from '@/constants/store-registry' -import * as Util from '@/constants/router2/util' +import {storeRegistry} from '@/stores/store-registry' +import * as Util from '@/constants/router2' export { type NavState, @@ -21,8 +21,8 @@ export { getRouteLoggedIn, useSafeFocusEffect, makeScreen, -} from '@/constants/router2/util' -export type {PathParam, Navigator} from '@/constants/router2/util' +} from '@/constants/router2' +export type {PathParam, Navigator} from '@/constants/router2' type Store = T.Immutable<{ navState?: unknown diff --git a/shared/stores/settings-contacts.d.ts b/shared/stores/settings-contacts.d.ts index 0ab05a739542..2920c6643055 100644 --- a/shared/stores/settings-contacts.d.ts +++ b/shared/stores/settings-contacts.d.ts @@ -1,4 +1,4 @@ -import type * as T from '../constants/types' +import type * as T from '@/constants/types' import type {UseBoundStore, StoreApi} from 'zustand' type PermissionStatus = 'granted' | 'denied' | 'undetermined' | 'unknown' diff --git a/shared/stores/settings-contacts.native.tsx b/shared/stores/settings-contacts.native.tsx index 786e6d0710ab..5043bf04d1f3 100644 --- a/shared/stores/settings-contacts.native.tsx +++ b/shared/stores/settings-contacts.native.tsx @@ -1,7 +1,7 @@ import * as Contacts from 'expo-contacts' -import {ignorePromise} from '../constants/utils' -import {importContactsWaitingKey} from '../constants/strings' -import * as T from '../constants/types' +import {ignorePromise} from '@/constants/utils' +import {importContactsWaitingKey} from '@/constants/strings' +import * as T from '@/constants/types' import * as Z from '@/util/zustand' import {addNotificationRequest} from 'react-native-kb' import logger from '@/logger' @@ -10,7 +10,7 @@ import {RPCError} from '@/util/errors' import {getDefaultCountryCode} from 'react-native-kb' import {getE164} from '@/util/phone-numbers' import {pluralize} from '@/util/string' -import {navigateAppend} from '@/constants/router2/util' +import {navigateAppend} from '@/constants/router2' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import {useWaitingState} from '@/stores/waiting' diff --git a/shared/stores/settings-invites.tsx b/shared/stores/settings-invites.tsx index 75cf71ef468f..93e5df2833bf 100644 --- a/shared/stores/settings-invites.tsx +++ b/shared/stores/settings-invites.tsx @@ -5,7 +5,7 @@ import {RPCError} from '@/util/errors' import logger from '@/logger' import trim from 'lodash/trim' import * as T from '@/constants/types' -import {navigateAppend} from '@/constants/router2/util' +import {navigateAppend} from '@/constants/router2' type InviteBase = { id: string diff --git a/shared/stores/settings-password.tsx b/shared/stores/settings-password.tsx index 138097633658..0b3c441f2422 100644 --- a/shared/stores/settings-password.tsx +++ b/shared/stores/settings-password.tsx @@ -4,7 +4,7 @@ import {waitingKeySettingsGeneric} from '@/constants/strings' import logger from '@/logger' import {RPCError} from '@/util/errors' import * as T from '@/constants/types' -import {navigateUp} from '@/constants/router2/util' +import {navigateUp} from '@/constants/router2' import {useLogoutState} from '@/stores/logout' type Store = T.Immutable<{ diff --git a/shared/stores/settings.tsx b/shared/stores/settings.tsx index 73fbe751a5f8..27b3240712b7 100644 --- a/shared/stores/settings.tsx +++ b/shared/stores/settings.tsx @@ -7,14 +7,14 @@ import * as Z from '@/util/zustand' import {RPCError} from '@/util/errors' import * as Tabs from '@/constants/tabs' import logger from '@/logger' -import {clearModals, navigateAppend, switchTab} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {clearModals, navigateAppend, switchTab} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import {useWaitingState} from '@/stores/waiting' -import {processorProfileInProgressKey, traceInProgressKey} from '@/constants/settings/util' +import {processorProfileInProgressKey, traceInProgressKey} from '@/constants/settings' -export * from '@/constants/settings/util' +export * from '@/constants/settings' type Store = T.Immutable<{ checkPasswordIsCorrect?: boolean diff --git a/shared/stores/signup.tsx b/shared/stores/signup.tsx index 2a0058d0f5cf..6e9c390979f6 100644 --- a/shared/stores/signup.tsx +++ b/shared/stores/signup.tsx @@ -8,8 +8,8 @@ import logger from '@/logger' import trim from 'lodash/trim' import {RPCError} from '@/util/errors' import {isValidEmail, isValidName, isValidUsername} from '@/util/simple-validators' -import {navigateAppend, navigateUp} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {navigateAppend, navigateUp} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' type Store = T.Immutable<{ diff --git a/shared/constants/store-registry.tsx b/shared/stores/store-registry.tsx similarity index 100% rename from shared/constants/store-registry.tsx rename to shared/stores/store-registry.tsx diff --git a/shared/stores/team-building.tsx b/shared/stores/team-building.tsx index 4db76d25466f..5d0631b64b95 100644 --- a/shared/stores/team-building.tsx +++ b/shared/stores/team-building.tsx @@ -11,11 +11,11 @@ import {serviceIdFromString} from '@/util/platforms' import {type StoreApi, type UseBoundStore, useStore} from 'zustand' import {validateEmailAddress} from '@/util/email-address' import {registerDebugClear} from '@/util/debug' -import {searchWaitingKey} from '@/constants/team-building/utils' -import {navigateUp} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {searchWaitingKey} from '@/constants/team-building' +import {navigateUp} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {useCryptoState} from '@/stores/crypto' -export {allServices, selfToUser, searchWaitingKey} from '@/constants/team-building/utils' +export {allServices, selfToUser, searchWaitingKey} from '@/constants/team-building' type Store = T.Immutable<{ namespace: T.TB.AllowedNamespace diff --git a/shared/stores/teams.tsx b/shared/stores/teams.tsx index 27fbb2f9fac0..dd71b509190d 100644 --- a/shared/stores/teams.tsx +++ b/shared/stores/teams.tsx @@ -9,7 +9,7 @@ import { navigateUp, navUpToScreen, navToProfile, -} from '@/constants/router2/util' +} from '@/constants/router2' import * as Z from '@/util/zustand' import invert from 'lodash/invert' import logger from '@/logger' @@ -19,11 +19,11 @@ import {isMobile, isPhone} from '@/constants/platform' import {mapGetEnsureValue} from '@/util/map' import {bodyToJSON} from '@/constants/rpc-utils' import {fixCrop} from '@/util/crop' -import {storeRegistry} from '@/constants/store-registry' +import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' -import * as Util from '@/constants/teams/util' -import {getTab} from '@/constants/router2/util' +import * as Util from '@/constants/teams' +import {getTab} from '@/constants/router2' export { baseRetentionPolicies, @@ -33,7 +33,7 @@ export { teamRoleByEnum, retentionPolicyToServiceRetentionPolicy, userIsRoleInTeamWithInfo, -} from '@/constants/teams/util' +} from '@/constants/teams' export const teamRoleTypes = ['reader', 'writer', 'admin', 'owner'] as const diff --git a/shared/stores/tracker2.tsx b/shared/stores/tracker2.tsx index 1fa1152e9c29..60712f586ef3 100644 --- a/shared/stores/tracker2.tsx +++ b/shared/stores/tracker2.tsx @@ -6,8 +6,8 @@ import logger from '@/logger' import * as T from '@/constants/types' import {RPCError} from '@/util/errors' import {mapGetEnsureValue} from '@/util/map' -import {navigateAppend, navigateUp} from '@/constants/router2/util' -import {storeRegistry} from '@/constants/store-registry' +import {navigateAppend, navigateUp} from '@/constants/router2' +import {storeRegistry} from '@/stores/store-registry' import {useCurrentUserState} from '@/stores/current-user' export const noDetails: T.Tracker.Details = { diff --git a/shared/stores/wallets.tsx b/shared/stores/wallets.tsx index e340fd2cf383..6fffb6c14dd2 100644 --- a/shared/stores/wallets.tsx +++ b/shared/stores/wallets.tsx @@ -1,10 +1,10 @@ import * as T from '@/constants/types' import {ignorePromise} from '@/constants/utils' import * as Z from '@/util/zustand' -import {loadAccountsWaitingKey} from '@/constants/wallets/utils' +import {loadAccountsWaitingKey} from '@/constants/wallets' import {useConfigState} from '@/stores/config' -export {loadAccountsWaitingKey} from '@/constants/wallets/utils' +export {loadAccountsWaitingKey} from '@/constants/wallets' export type Account = { accountID: string diff --git a/shared/stores/whats-new.tsx b/shared/stores/whats-new.tsx index 2944a3685655..e52289d7527c 100644 --- a/shared/stores/whats-new.tsx +++ b/shared/stores/whats-new.tsx @@ -1,9 +1,9 @@ import type * as T from '@/constants/types' import * as Z from '@/util/zustand' import {uint8ArrayToString} from 'uint8array-extras' -import {noVersion, getSeenVersions} from '@/constants/whats-new/utils' +import {noVersion, getSeenVersions} from '@/constants/whats-new' -export {currentVersion, lastVersion, lastLastVersion, keybaseFM} from '@/constants/whats-new/utils' +export {currentVersion, lastVersion, lastLastVersion, keybaseFM} from '@/constants/whats-new' // This store has no dependencies on other stores and is safe to import directly from other stores. type SeenVersionsMap = {[key in string]: boolean} diff --git a/shared/team-building/phone-search.tsx b/shared/team-building/phone-search.tsx index 993278b057c9..69a8a3d36f61 100644 --- a/shared/team-building/phone-search.tsx +++ b/shared/team-building/phone-search.tsx @@ -2,7 +2,7 @@ import * as C from '@/constants' import * as TB from '@/stores/team-building' import * as React from 'react' import * as Kb from '@/common-adapters/index' -import type * as T from 'constants/types' +import type * as T from '@/constants/types' import ContinueButton from './continue-button' import {useSettingsPhoneState} from '@/stores/settings-phone' diff --git a/shared/teams/team/menu-container.tsx b/shared/teams/team/menu-container.tsx index fdc3047a780a..d618e52631eb 100644 --- a/shared/teams/team/menu-container.tsx +++ b/shared/teams/team/menu-container.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import type * as React from 'react' -import * as FS from '@/constants/fs/util' +import * as FS from '@/constants/fs' import * as Teams from '@/stores/teams' import capitalize from 'lodash/capitalize' import * as T from '@/constants/types' diff --git a/shared/util/crop.tsx b/shared/util/crop.tsx index b06f65bb002b..2f3b745a0c57 100644 --- a/shared/util/crop.tsx +++ b/shared/util/crop.tsx @@ -1,4 +1,4 @@ -import type * as T from '../constants/types' +import type * as T from '@/constants/types' export const fixCrop = (c?: T.RPCChat.Keybase1.ImageCropRect) => { return c diff --git a/shared/whats-new/versions.tsx b/shared/whats-new/versions.tsx index 05433c1fa130..ddf79961c28c 100644 --- a/shared/whats-new/versions.tsx +++ b/shared/whats-new/versions.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' -import {encryptTab} from '@/constants/crypto/util' +import {encryptTab} from '@/constants/crypto' import type * as React from 'react' import * as Kb from '@/common-adapters' import {keybaseFM} from '@/stores/whats-new' import NewFeatureRow from './new-feature-row' -import {settingsCryptoTab, settingsDisplayTab} from '@/constants/settings/util' +import {settingsCryptoTab, settingsDisplayTab} from '@/constants/settings' export type VersionProps = { seen: boolean From 28f5bd3c513349ecd586a5a5ebf4f627012d3ab1 Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Mon, 12 Jan 2026 15:22:22 -0500 Subject: [PATCH 13/20] WIP: shift 14 (#28797) * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/constants/chat2/common.tsx | 6 +- shared/constants/chat2/message.tsx | 2 +- shared/constants/deeplinks.tsx | 26 ------- .../fs/platform-specific.desktop.tsx | 19 +++--- shared/constants/init/index.native.tsx | 6 +- shared/constants/init/shared.tsx | 59 ++++++++++++++++ shared/constants/strings.tsx | 2 + shared/constants/team-building.tsx | 2 - shared/desktop/renderer/main2.desktop.tsx | 29 +++++++- shared/router-v2/hooks.native.tsx | 2 +- shared/router-v2/tab-bar.native.tsx | 2 +- shared/settings/archive/modal.tsx | 2 +- shared/settings/feedback/container.native.tsx | 2 +- .../settings/notifications/index.native.tsx | 2 +- shared/settings/notifications/push-prompt.tsx | 2 +- shared/settings/notifications/render.tsx | 2 +- shared/settings/root-phone.tsx | 2 +- shared/settings/sub-nav/left-nav.tsx | 2 +- shared/signup/email.tsx | 2 +- shared/stores/chat2.tsx | 6 +- .../chat2 => stores}/convostate.tsx | 26 +++---- .../push-listener.native.tsx} | 6 +- shared/{constants => stores}/push.d.ts | 2 +- shared/{constants => stores}/push.desktop.tsx | 2 +- shared/{constants => stores}/push.native.tsx | 2 +- shared/stores/store-registry.tsx | 10 +-- shared/stores/team-building.tsx | 67 ++++++++++++++----- shared/team-building/email-search.tsx | 3 +- shared/team-building/phone-search.tsx | 3 +- 29 files changed, 197 insertions(+), 101 deletions(-) rename shared/{constants/chat2 => stores}/convostate.tsx (99%) rename shared/{constants/platform-specific/push.native.tsx => stores/push-listener.native.tsx} (98%) rename shared/{constants => stores}/push.d.ts (95%) rename shared/{constants => stores}/push.desktop.tsx (92%) rename shared/{constants => stores}/push.native.tsx (99%) diff --git a/shared/constants/chat2/common.tsx b/shared/constants/chat2/common.tsx index c16ed15eb76f..45ae0acc1c03 100644 --- a/shared/constants/chat2/common.tsx +++ b/shared/constants/chat2/common.tsx @@ -1,12 +1,12 @@ import * as T from '../types' import {isMobile, isTablet} from '../platform' -import * as Router2 from '@/stores/router2' +import {getVisibleScreen} from '@/constants/router2' import {useConfigState} from '@/stores/config' export const explodingModeGregorKeyPrefix = 'exploding:' export const getSelectedConversation = (allowUnderModal: boolean = false): T.Chat.ConversationIDKey => { - const maybeVisibleScreen = Router2.getVisibleScreen(undefined, allowUnderModal) + const maybeVisibleScreen = getVisibleScreen(undefined, allowUnderModal) if (maybeVisibleScreen?.name === threadRouteName) { const mParams = maybeVisibleScreen.params as undefined | {conversationIDKey?: T.Chat.ConversationIDKey} return mParams?.conversationIDKey ?? T.Chat.noConversationIDKey @@ -25,7 +25,7 @@ export const isUserActivelyLookingAtThisThread = (conversationIDKey: T.Chat.Conv if (!isSplit) { chatThreadSelected = true // conversationIDKey === selectedConversationIDKey is the only thing that matters in the new router } else { - const maybeVisibleScreen = Router2.getVisibleScreen() + const maybeVisibleScreen = getVisibleScreen() chatThreadSelected = (maybeVisibleScreen === undefined ? undefined : maybeVisibleScreen.name) === threadRouteName } diff --git a/shared/constants/chat2/message.tsx b/shared/constants/chat2/message.tsx index 2897f2899bb1..b0cdf7684d5b 100644 --- a/shared/constants/chat2/message.tsx +++ b/shared/constants/chat2/message.tsx @@ -1,7 +1,7 @@ // Message related constants import * as T from '../types' import * as TeamsUtil from '@/constants/teams' -import type * as ConvoConstants from './convostate' +import type * as ConvoConstants from '@/stores/convostate' import HiddenString from '@/util/hidden-string' import logger from '@/logger' import type * as MessageTypes from '@/constants/types/chat2/message' diff --git a/shared/constants/deeplinks.tsx b/shared/constants/deeplinks.tsx index 23e8d713efc2..dbcc975c6b42 100644 --- a/shared/constants/deeplinks.tsx +++ b/shared/constants/deeplinks.tsx @@ -1,14 +1,9 @@ -import * as Crypto from './crypto' import * as Tabs from './tabs' -import {isPathSaltpackEncrypted, isPathSaltpackSigned} from '@/util/path' -import type HiddenString from '@/util/hidden-string' import URL from 'url-parse' import logger from '@/logger' import * as T from '@/constants/types' import {navigateAppend, switchTab} from './router2' import {storeRegistry} from '@/stores/store-registry' -import {useCryptoState} from '@/stores/crypto' -import {useConfigState} from '@/stores/config' const prefix = 'keybase://' export const linkFromConvAndMessage = (conv: string, messageID: number) => @@ -264,24 +259,3 @@ export const handleKeybaseLink = (link: string) => { navigateAppend({props: {error}, selected: 'keybaseLinkError'}) } -export const handleSaltPackOpen = (_path: string | HiddenString) => { - const path = typeof _path === 'string' ? _path : _path.stringValue() - - if (!useConfigState.getState().loggedIn) { - console.warn('Tried to open a saltpack file before being logged in') - return - } - let operation: T.Crypto.Operations | undefined - if (isPathSaltpackEncrypted(path)) { - operation = Crypto.Operations.Decrypt - } else if (isPathSaltpackSigned(path)) { - operation = Crypto.Operations.Verify - } else { - logger.warn( - 'Deeplink received saltpack file path not ending in ".encrypted.saltpack" or ".signed.saltpack"' - ) - return - } - useCryptoState.getState().dispatch.onSaltpackOpenFile(operation, path) - switchTab(Tabs.cryptoTab) -} diff --git a/shared/constants/fs/platform-specific.desktop.tsx b/shared/constants/fs/platform-specific.desktop.tsx index 86c3137c337c..25ff18430ff0 100644 --- a/shared/constants/fs/platform-specific.desktop.tsx +++ b/shared/constants/fs/platform-specific.desktop.tsx @@ -1,16 +1,15 @@ import * as T from '@/constants/types' -import {ignorePromise, wrapErrors} from '../utils' -import * as Constants from '@/stores/fs' -import * as Tabs from '../tabs' -import {isWindows, isLinux, pathSep, isDarwin} from '../platform.desktop' +import {ignorePromise, wrapErrors} from '@/constants/utils' +import * as Constants from '@/constants/fs' +import * as Tabs from '@/constants/tabs' +import {isWindows, isLinux, pathSep, isDarwin} from '@/constants/platform.desktop' import logger from '@/logger' import * as Path from '@/util/path' import KB2 from '@/util/electron.desktop' import {uint8ArrayToHex} from 'uint8array-extras' -import {navigateAppend} from '../router2' +import {navigateAppend} from '@/constants/router2' import {useConfigState} from '@/stores/config' - -const useFSState = Constants.useFSState +import {useFSState, errorToActionOrThrow} from '@/stores/fs' const {openPathInFinder, openURL, getPathType, selectFilesToUploadDialog} = KB2.functions const {darwinCopyToKBFSTempUploadFile, relaunchApp, uninstallKBFSDialog, uninstallDokanDialog} = KB2.functions @@ -129,7 +128,7 @@ const onInstallCachedDokan = async () => { await installCachedDokan?.() useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() } catch (e) { - Constants.errorToActionOrThrow(e) + errorToActionOrThrow(e) } } @@ -166,7 +165,7 @@ const initPlatformSpecific = () => { await _openPathInSystemFileManagerPromise(localPath, pathType === 'directory') } } catch (e) { - Constants.errorToActionOrThrow(e) + errorToActionOrThrow(e) } } ignorePromise(f()) @@ -180,7 +179,7 @@ const initPlatformSpecific = () => { _rebaseKbfsPathToMountLocation(path, sfmi.directMountDir), ![T.FS.PathKind.InGroupTlf, T.FS.PathKind.InTeamTlf].includes(Constants.parsePath(path).kind) || Constants.getPathItem(pathItems, path).type === T.FS.PathType.Folder - ).catch((e: unknown) => Constants.errorToActionOrThrow(e, path)) + ).catch((e: unknown) => errorToActionOrThrow(e, path)) : new Promise((resolve, reject) => { if (sfmi.driverStatus.type !== T.FS.DriverStatusType.Enabled) { // This usually indicates a developer error as diff --git a/shared/constants/init/index.native.tsx b/shared/constants/init/index.native.tsx index 380f554e8503..33f79bb51267 100644 --- a/shared/constants/init/index.native.tsx +++ b/shared/constants/init/index.native.tsx @@ -21,7 +21,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} from '@/stores/router2' +import {getTab, getVisiblePath, logState} from '@/constants/router2' import {launchImageLibraryAsync} from '@/util/expo-image-picker.native' import {setupAudioMode} from '@/util/audio.native' import { @@ -32,12 +32,12 @@ import { guiConfig, shareListenersRegistered, } from 'react-native-kb' -import {initPushListener, getStartupDetailsFromInitialPush} from '../platform-specific/push.native' +import {initPushListener, getStartupDetailsFromInitialPush} from '@/stores/push-listener.native' import {initSharedSubscriptions, _onEngineIncoming} from './shared' import type {ImageInfo} from '@/util/expo-image-picker.native' import {noConversationIDKey} from '../types/chat2/common' import {getSelectedConversation} from '../chat2/common' -import {getConvoState} from '../chat2/convostate' +import {getConvoState} from '@/stores/convostate' import {requestLocationPermission, showShareActionSheet} from '../platform-specific/index.native' const loadStartupDetails = async () => { diff --git a/shared/constants/init/shared.tsx b/shared/constants/init/shared.tsx index 9c148b3de4e6..5a3c36820eb0 100644 --- a/shared/constants/init/shared.tsx +++ b/shared/constants/init/shared.tsx @@ -26,6 +26,10 @@ import type * as UsePinentryStateType from '@/stores/pinentry' import {useProvisionState} from '@/stores/provision' import {storeRegistry} from '@/stores/store-registry' import {useSettingsContactsState} from '@/stores/settings-contacts' +import {createTBStore} from '@/stores/team-building' +import {useCryptoState} from '@/stores/crypto' +import {useProfileState} from '@/stores/profile' +import {useUsersState} from '@/stores/users' import type * as UseSignupStateType from '@/stores/signup' import type * as UseTeamsStateType from '@/stores/teams' import {useTeamsState} from '@/stores/teams' @@ -93,6 +97,59 @@ export const onEngineDisconnected = () => { storeRegistry.getState('daemon').dispatch.setError(new Error('Disconnected')) } +// Initialize team building callbacks. Not ideal but keeping all the existing logic for now. +export const initTeamBuildingCallbacks = () => { + const commonCallbacks = { + onAddMembersWizardPushMembers: (members: Array) => { + useTeamsState.getState().dispatch.addMembersWizardPushMembers(members) + }, + onGetSettingsContactsImportEnabled: () => { + return useSettingsContactsState.getState().importEnabled + }, + onGetSettingsContactsUserCountryCode: () => { + return useSettingsContactsState.getState().userCountryCode + }, + onShowUserProfile: (username: string) => { + useProfileState.getState().dispatch.showUserProfile(username) + }, + onUsersGetBlockState: (usernames: ReadonlyArray) => { + useUsersState.getState().dispatch.getBlockState(usernames) + }, + onUsersUpdates: (infos: ReadonlyArray<{name: string; info: Partial}>) => { + useUsersState.getState().dispatch.updates(infos) + }, + } + + const namespaces: Array = ['chat2', 'crypto', 'teams', 'people'] + for (const namespace of namespaces) { + const store = createTBStore(namespace) + const currentState = store.getState() + store.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + ...currentState.dispatch.dynamic, + ...commonCallbacks, + ...(namespace === 'chat2' + ? { + onFinishedTeamBuildingChat: users => { + storeRegistry.getState('chat').dispatch.onTeamBuildingFinished(users) + }, + } + : {}), + ...(namespace === 'crypto' + ? { + onFinishedTeamBuildingCrypto: users => { + useCryptoState.getState().dispatch.onTeamBuildingFinished(users) + }, + } + : {}), + }, + }, + }) + } +} + export const initSharedSubscriptions = () => { useConfigState.subscribe((s, old) => { if (s.loadOnStartPhase !== old.loadOnStartPhase) { @@ -277,6 +334,8 @@ export const initSharedSubscriptions = () => { ignorePromise(f()) } }) + + initTeamBuildingCallbacks() } // This is to defer loading stores we don't need immediately. diff --git a/shared/constants/strings.tsx b/shared/constants/strings.tsx index 5fe715a7795c..dc63e5f6cd85 100644 --- a/shared/constants/strings.tsx +++ b/shared/constants/strings.tsx @@ -44,6 +44,8 @@ export const waitingKeyRecoverPassword = 'recover-password:waiting' export const waitingKeyCrypto = 'cryptoWaiting' +export const searchWaitingKey = 'teamBuilding:search' + export const waitingKeyTeamsLoaded = 'teams:loaded' export const waitingKeyTeamsJoinTeam = 'teams:joinTeam' export const waitingKeyTeamsTeam = (teamID: T.Teams.TeamID) => `team:${teamID}` diff --git a/shared/constants/team-building.tsx b/shared/constants/team-building.tsx index bdad54ace64d..24e3c9d457e7 100644 --- a/shared/constants/team-building.tsx +++ b/shared/constants/team-building.tsx @@ -16,5 +16,3 @@ export const selfToUser = (you: string): T.TB.User => ({ serviceMap: {}, username: you, }) - -export const searchWaitingKey = 'teamBuilding:search' diff --git a/shared/desktop/renderer/main2.desktop.tsx b/shared/desktop/renderer/main2.desktop.tsx index e2153297bafe..329d55bb0b53 100644 --- a/shared/desktop/renderer/main2.desktop.tsx +++ b/shared/desktop/renderer/main2.desktop.tsx @@ -19,7 +19,12 @@ import {RPCError} from '@/util/errors' import {switchTab} from '@/constants/router2' import {storeRegistry} from '@/stores/store-registry' import {onEngineConnected, onEngineDisconnected} from '@/constants/init/index.desktop' -import {handleAppLink, handleSaltPackOpen} from '@/constants/deeplinks' +import {handleAppLink} from '@/constants/deeplinks' +import * as Crypto from '@/constants/crypto' +import * as Tabs from '@/constants/tabs' +import {isPathSaltpackEncrypted, isPathSaltpackSigned} from '@/util/path' +import type HiddenString from '@/util/hidden-string' +import {useCryptoState} from '@/stores/crypto' import logger from '@/logger' import {debugWarning} from '@/util/debug-warning' import type {default as NewMainType} from '../../app/main.desktop' @@ -31,6 +36,28 @@ setServiceDecoration(ServiceDecoration) const {ipcRendererOn, requestWindowsStartService, appStartedUp, ctlQuit, dumpNodeLogger} = KB2.functions +const handleSaltPackOpen = (_path: string | HiddenString) => { + const path = typeof _path === 'string' ? _path : _path.stringValue() + + if (!useConfigState.getState().loggedIn) { + console.warn('Tried to open a saltpack file before being logged in') + return + } + let operation: T.Crypto.Operations | undefined + if (isPathSaltpackEncrypted(path)) { + operation = Crypto.Operations.Decrypt + } else if (isPathSaltpackSigned(path)) { + operation = Crypto.Operations.Verify + } else { + logger.warn( + 'Deeplink received saltpack file path not ending in ".encrypted.saltpack" or ".signed.saltpack"' + ) + return + } + useCryptoState.getState().dispatch.onSaltpackOpenFile(operation, path) + switchTab(Tabs.cryptoTab) +} + const dumpLogs = async (reason?: string) => { await logger.dump() await (dumpNodeLogger?.() ?? Promise.resolve([])) diff --git a/shared/router-v2/hooks.native.tsx b/shared/router-v2/hooks.native.tsx index ade3784a1414..b68ef802fbef 100644 --- a/shared/router-v2/hooks.native.tsx +++ b/shared/router-v2/hooks.native.tsx @@ -6,7 +6,7 @@ import * as React from 'react' import {handleAppLink} from '@/constants/deeplinks' import {Linking} from 'react-native' import {useColorScheme} from 'react-native' -import {usePushState} from '@/constants/push' +import {usePushState} from '@/stores/push' type InitialStateState = 'init' | 'loading' | 'loaded' diff --git a/shared/router-v2/tab-bar.native.tsx b/shared/router-v2/tab-bar.native.tsx index 3a136f6a74fd..30671cb861f4 100644 --- a/shared/router-v2/tab-bar.native.tsx +++ b/shared/router-v2/tab-bar.native.tsx @@ -6,7 +6,7 @@ import * as Shared from './router.shared' import {View} from 'react-native' import {useSafeAreaFrame} from 'react-native-safe-area-context' import {useColorScheme} from 'react-native' -import {usePushState} from '@/constants/push' +import {usePushState} from '@/stores/push' import {useNotifState} from '@/stores/notifications' const settingsTabChildren = [Tabs.gitTab, Tabs.devicesTab, Tabs.settingsTab] as const diff --git a/shared/settings/archive/modal.tsx b/shared/settings/archive/modal.tsx index fad4d4c0141b..1e77cb8b0a8c 100644 --- a/shared/settings/archive/modal.tsx +++ b/shared/settings/archive/modal.tsx @@ -7,7 +7,7 @@ import * as FsCommon from '@/fs/common' import {useArchiveState} from '@/stores/archive' import {settingsArchiveTab} from '@/stores/settings' import {useCurrentUserState} from '@/stores/current-user' -import {getConvoState} from '@/constants/chat2/convostate' +import {getConvoState} from '@/stores/convostate' type Props = | {type: 'chatID'; conversationIDKey: T.Chat.ConversationIDKey} diff --git a/shared/settings/feedback/container.native.tsx b/shared/settings/feedback/container.native.tsx index 45a5ca45867c..a504f4ab065a 100644 --- a/shared/settings/feedback/container.native.tsx +++ b/shared/settings/feedback/container.native.tsx @@ -9,7 +9,7 @@ import {getExtraChatLogsForLogSend} from './shared' import {isAndroid, version, pprofDir} from '@/constants/platform' import {logSend, appVersionName, appVersionCode} from 'react-native-kb' import type {Props as OwnProps} from './container' -import {usePushState} from '@/constants/push' +import {usePushState} from '@/stores/push' export type Props = { chat: object diff --git a/shared/settings/notifications/index.native.tsx b/shared/settings/notifications/index.native.tsx index b4e429461668..caefe5cb7cf6 100644 --- a/shared/settings/notifications/index.native.tsx +++ b/shared/settings/notifications/index.native.tsx @@ -4,7 +4,7 @@ import Notifications from './render' import {Reloadable} from '@/common-adapters' import {useSettingsNotifState} from '@/stores/settings-notifications' import {useSettingsState} from '@/stores/settings' -import {usePushState} from '@/constants/push' +import {usePushState} from '@/stores/push' const MobileNotifications = () => { const loadSettings = useSettingsState(s => s.dispatch.loadSettings) diff --git a/shared/settings/notifications/push-prompt.tsx b/shared/settings/notifications/push-prompt.tsx index 9917a9110fc4..1cf01b98196a 100644 --- a/shared/settings/notifications/push-prompt.tsx +++ b/shared/settings/notifications/push-prompt.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' -import {usePushState} from '@/constants/push' +import {usePushState} from '@/stores/push' const PushPrompt = () => { const rejectPermissions = usePushState(s => s.dispatch.rejectPermissions) diff --git a/shared/settings/notifications/render.tsx b/shared/settings/notifications/render.tsx index 7784aa673b12..fd67e846c9e0 100644 --- a/shared/settings/notifications/render.tsx +++ b/shared/settings/notifications/render.tsx @@ -1,7 +1,7 @@ import * as Kb from '@/common-adapters' import useNotifications from './hooks' import Group from '../group' -import {usePushState} from '@/constants/push' +import {usePushState} from '@/stores/push' type Props = ReturnType diff --git a/shared/settings/root-phone.tsx b/shared/settings/root-phone.tsx index 379ad5fbc252..e481ddc5883d 100644 --- a/shared/settings/root-phone.tsx +++ b/shared/settings/root-phone.tsx @@ -9,7 +9,7 @@ import WhatsNewIcon from '../whats-new/icon' import noop from 'lodash/noop' import {useSettingsContactsState} from '@/stores/settings-contacts' import * as Settings from '@/stores/settings' -import {usePushState} from '@/constants/push' +import {usePushState} from '@/stores/push' import {useNotifState} from '@/stores/notifications' const PerfRow = () => { diff --git a/shared/settings/sub-nav/left-nav.tsx b/shared/settings/sub-nav/left-nav.tsx index 57ca3a5fbf13..6e7337a14961 100644 --- a/shared/settings/sub-nav/left-nav.tsx +++ b/shared/settings/sub-nav/left-nav.tsx @@ -5,7 +5,7 @@ import WhatsNewIcon from '@/whats-new/icon' import SettingsItem from './settings-item' import {keybaseFM} from '@/stores/whats-new' import * as Settings from '@/stores/settings' -import {usePushState} from '@/constants/push' +import {usePushState} from '@/stores/push' import {useNotifState} from '@/stores/notifications' type Props = { diff --git a/shared/signup/email.tsx b/shared/signup/email.tsx index 0f6f33bef3b6..b167e9e3db0b 100644 --- a/shared/signup/email.tsx +++ b/shared/signup/email.tsx @@ -4,7 +4,7 @@ import * as Kb from '@/common-adapters' import {SignupScreen, errorBanner} from './common' import {useSettingsEmailState} from '@/stores/settings-email' import {useSignupState} from '@/stores/signup' -import {usePushState} from '@/constants/push' +import {usePushState} from '@/stores/push' const ConnectedEnterEmail = () => { const _showPushPrompt = usePushState(s => C.isMobile && !s.hasPermissions && s.showPushPrompt) diff --git a/shared/stores/chat2.tsx b/shared/stores/chat2.tsx index 44db48471c5c..68884adec3fd 100644 --- a/shared/stores/chat2.tsx +++ b/shared/stores/chat2.tsx @@ -12,7 +12,7 @@ import * as Meta from '@/constants/chat2/meta' import {isMobile, isPhone} from '@/constants/platform' import * as Z from '@/util/zustand' import * as Common from '@/constants/chat2/common' -import {clearChatStores, chatStores} from '@/constants/chat2/convostate' +import {clearChatStores, chatStores} from '@/stores/convostate' import {uint8ArrayToString} from 'uint8array-extras' import isEqual from 'lodash/isEqual' import {bodyToJSON} from '@/constants/rpc-utils' @@ -1966,7 +1966,7 @@ export const useChatState = Z.createZustand((set, get) => { } }) -import {type ChatProviderProps, ProviderScreen} from '@/constants/chat2/convostate' +import {type ChatProviderProps, ProviderScreen} from '@/stores/convostate' import type {GetOptionsRet} from '@/constants/types/router2' export function makeChatScreen>( @@ -1992,7 +1992,7 @@ export function makeChatScreen>( } } -export * from '@/constants/chat2/convostate' +export * from '@/stores/convostate' export * from '@/constants/chat2/common' export * from '@/constants/chat2/meta' export * from '@/constants/chat2/message' diff --git a/shared/constants/chat2/convostate.tsx b/shared/stores/convostate.tsx similarity index 99% rename from shared/constants/chat2/convostate.tsx rename to shared/stores/convostate.tsx index 5f2b250a8c10..fd246ac0d5de 100644 --- a/shared/constants/chat2/convostate.tsx +++ b/shared/stores/convostate.tsx @@ -1,7 +1,7 @@ // TODO remove useChatNavigateAppend // TODO remove -import * as TeamsUtil from '../teams' -import * as PlatformSpecific from '../platform-specific' +import * as TeamsUtil from '@/constants/teams' +import * as PlatformSpecific from '@/constants/platform-specific' import { clearModals, navigateAppend, @@ -11,16 +11,16 @@ import { getVisibleScreen, getModalStack, navToThread, -} from '../router2' -import {isIOS} from '../platform' -import {updateImmer} from '../utils' -import * as T from '../types' +} from '@/constants/router2' +import {isIOS} from '@/constants/platform' +import {updateImmer} from '@/constants/utils' +import * as T from '@/constants/types' import * as Styles from '@/styles' -import * as Common from './common' -import * as Tabs from '../tabs' +import * as Common from '@/constants/chat2/common' +import * as Tabs from '@/constants/tabs' import * as EngineGen from '@/actions/engine-gen-gen' -import * as Message from './message' -import * as Meta from './meta' +import * as Message from '@/constants/chat2/message' +import * as Meta from '@/constants/chat2/meta' import * as React from 'react' import * as Z from '@/util/zustand' import {makeActionForOpenPathInFilesTab} from '@/constants/fs' @@ -32,9 +32,9 @@ import type {DebouncedFunc} from 'lodash' import {RPCError} from '@/util/errors' import {findLast} from '@/util/arrays' import {mapGetEnsureValue} from '@/util/map' -import {noConversationIDKey} from '../types/chat2/common' +import {noConversationIDKey} from '@/constants/types/chat2/common' import {type StoreApi, type UseBoundStore, useStore} from 'zustand' -import * as Platform from '../platform' +import * as Platform from '@/constants/platform' import KB2 from '@/util/electron' import NotifyPopup from '@/util/notify-popup' import {hexToUint8Array} from 'uint8array-extras' @@ -43,7 +43,7 @@ import {clearChatTimeCache} from '@/util/timestamp' import {registerDebugClear} from '@/util/debug' import * as Config from '@/constants/config' import {isMobile} from '@/constants/platform' -import {enumKeys, ignorePromise, shallowEqual} from '../utils' +import {enumKeys, ignorePromise, shallowEqual} from '@/constants/utils' import * as Strings from '@/constants/strings' import {storeRegistry} from '@/stores/store-registry' diff --git a/shared/constants/platform-specific/push.native.tsx b/shared/stores/push-listener.native.tsx similarity index 98% rename from shared/constants/platform-specific/push.native.tsx rename to shared/stores/push-listener.native.tsx index dd44edad2b3f..e51c943a2245 100644 --- a/shared/constants/platform-specific/push.native.tsx +++ b/shared/stores/push-listener.native.tsx @@ -1,7 +1,7 @@ -import * as T from '../types' -import {ignorePromise, timeoutPromise} from '../utils' +import * as T from '@/constants/types' +import {ignorePromise, timeoutPromise} from '@/constants/utils' import logger from '@/logger' -import {isAndroid} from '../platform' +import {isAndroid} from '@/constants/platform' import { getRegistrationToken, setApplicationIconBadgeNumber, diff --git a/shared/constants/push.d.ts b/shared/stores/push.d.ts similarity index 95% rename from shared/constants/push.d.ts rename to shared/stores/push.d.ts index ae8fd435e57a..fc96b75135bf 100644 --- a/shared/constants/push.d.ts +++ b/shared/stores/push.d.ts @@ -1,4 +1,4 @@ -import type * as T from './types' +import type * as T from '@/constants/types' import type {UseBoundStore, StoreApi} from 'zustand' type Store = T.Immutable<{ diff --git a/shared/constants/push.desktop.tsx b/shared/stores/push.desktop.tsx similarity index 92% rename from shared/constants/push.desktop.tsx rename to shared/stores/push.desktop.tsx index b3fed7e84595..d4626a2e8af6 100644 --- a/shared/constants/push.desktop.tsx +++ b/shared/stores/push.desktop.tsx @@ -1,5 +1,5 @@ import * as Z from '@/util/zustand' -import {type Store, type State} from './push' +import {type Store, type State} from '@/stores/push' export const tokenType = '' diff --git a/shared/constants/push.native.tsx b/shared/stores/push.native.tsx similarity index 99% rename from shared/constants/push.native.tsx rename to shared/stores/push.native.tsx index ea5e57e6d087..568e97478bf1 100644 --- a/shared/constants/push.native.tsx +++ b/shared/stores/push.native.tsx @@ -18,7 +18,7 @@ import { requestPushPermissions, removeAllPendingNotificationRequests, } from 'react-native-kb' -import {type Store, type State} from '@/constants/push' +import {type Store, type State} from '@/stores/push' export const tokenType = isIOS ? (isDevApplePushToken ? 'appledev' : 'apple') : 'androidplay' diff --git a/shared/stores/store-registry.tsx b/shared/stores/store-registry.tsx index d45249872caa..a54a04a129dd 100644 --- a/shared/stores/store-registry.tsx +++ b/shared/stores/store-registry.tsx @@ -2,8 +2,8 @@ // ONLY for zustand stores import type * as T from '@/constants/types' import type * as TBType from '@/stores/team-building' -import type * as ConvoStateType from '@/constants/chat2/convostate' -import type {ConvoState} from '@/constants/chat2/convostate' +import type * as ConvoStateType from '@/stores/convostate' +import type {ConvoState} from '@/stores/convostate' import type {State as AutoResetState, useAutoResetState} from '@/stores/autoreset' import type {State as BotsState, useBotsState} from '@/stores/bots' import type {State as ChatState, useChatState} from '@/stores/chat2' @@ -15,7 +15,7 @@ import type {State as NotificationsState, useNotifState} from '@/stores/notifica import type {State as PeopleState, usePeopleState} from '@/stores/people' import type {State as ProfileState, useProfileState} from '@/stores/profile' import type {State as ProvisionState, useProvisionState} from '@/stores/provision' -import type {State as PushState, usePushState} from '@/constants/push' +import type {State as PushState, usePushState} from '@/stores/push' import type { State as RecoverPasswordState, useState as useRecoverPasswordState, @@ -161,7 +161,7 @@ class StoreRegistry { return useProvisionState } case 'push': { - const {usePushState} = require('@/constants/push') + const {usePushState} = require('@/stores/push') return usePushState } case 'recover-password': { @@ -228,7 +228,7 @@ class StoreRegistry { } getConvoState(id: T.Chat.ConversationIDKey): ConvoState { - const {getConvoState} = require('@/constants/chat2/convostate') as typeof ConvoStateType + const {getConvoState} = require('@/stores/convostate') as typeof ConvoStateType return getConvoState(id) } } diff --git a/shared/stores/team-building.tsx b/shared/stores/team-building.tsx index 5d0631b64b95..cd65d9ee05de 100644 --- a/shared/stores/team-building.tsx +++ b/shared/stores/team-building.tsx @@ -11,11 +11,10 @@ import {serviceIdFromString} from '@/util/platforms' import {type StoreApi, type UseBoundStore, useStore} from 'zustand' import {validateEmailAddress} from '@/util/email-address' import {registerDebugClear} from '@/util/debug' -import {searchWaitingKey} from '@/constants/team-building' +import {searchWaitingKey} from '@/constants/strings' import {navigateUp} from '@/constants/router2' -import {storeRegistry} from '@/stores/store-registry' -import {useCryptoState} from '@/stores/crypto' -export {allServices, selfToUser, searchWaitingKey} from '@/constants/team-building' +export {allServices, selfToUser} from '@/constants/team-building' +export {searchWaitingKey} from '@/constants/strings' type Store = T.Immutable<{ namespace: T.TB.AllowedNamespace @@ -55,6 +54,16 @@ export interface State extends Store { cancelTeamBuilding: () => void changeSendNotification: (sendNotification: boolean) => void closeTeamBuilding: () => void + dynamic: { + onAddMembersWizardPushMembers: (members: Array) => void + onFinishedTeamBuildingChat: (users: ReadonlySet) => void + onFinishedTeamBuildingCrypto: (users: ReadonlySet) => void + onGetSettingsContactsImportEnabled: () => boolean | undefined + onGetSettingsContactsUserCountryCode: () => string | undefined + onShowUserProfile: (username: string) => void + onUsersGetBlockState: (usernames: ReadonlyArray) => void + onUsersUpdates: (infos: ReadonlyArray<{name: string; info: Partial}>) => void + } fetchUserRecs: () => void finishTeamBuilding: () => void finishedTeamBuilding: () => void @@ -272,7 +281,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { // we want the first item for (const user of teamSoFar) { const username = user.serviceMap.keybase || user.id - storeRegistry.getState('profile').dispatch.showUserProfile(username) + get().dispatch.dynamic.onShowUserProfile(username) break } }, 100) @@ -299,6 +308,32 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { navigateUp() } }, + dynamic: { + onAddMembersWizardPushMembers: (_members: Array) => { + throw new Error('onAddMembersWizardPushMembers not properly initialized') + }, + onFinishedTeamBuildingChat: (_users: ReadonlySet) => { + throw new Error('onFinishedTeamBuildingChat not properly initialized') + }, + onFinishedTeamBuildingCrypto: (_users: ReadonlySet) => { + throw new Error('onFinishedTeamBuildingCrypto not properly initialized') + }, + onGetSettingsContactsImportEnabled: () => { + throw new Error('onGetSettingsContactsImportEnabled not properly initialized') + }, + onGetSettingsContactsUserCountryCode: () => { + throw new Error('onGetSettingsContactsUserCountryCode not properly initialized') + }, + onShowUserProfile: (_username: string) => { + throw new Error('onShowUserProfile not properly initialized') + }, + onUsersGetBlockState: (_usernames: ReadonlyArray) => { + throw new Error('onUsersGetBlockState not properly initialized') + }, + onUsersUpdates: (_infos: ReadonlyArray<{name: string; info: Partial}>) => { + throw new Error('onUsersUpdates not properly initialized') + }, + }, fetchUserRecs: () => { const includeContacts = get().namespace === 'chat2' const f = async () => { @@ -314,7 +349,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const contacts = contactRes.map(contactToUser) let suggestions = suggestionRes.map(interestingPersonToUser) const expectingContacts = - storeRegistry.getState('settings-contacts').importEnabled && includeContacts + get().dispatch.dynamic.onGetSettingsContactsImportEnabled() && includeContacts if (expectingContacts) { suggestions = suggestions.slice(0, 10) } @@ -337,11 +372,9 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { get().dispatch.closeTeamBuilding() const {teamSoFar} = get() if (get().namespace === 'teams') { - storeRegistry - .getState('teams') - .dispatch.addMembersWizardPushMembers( - [...teamSoFar].map(user => ({assertion: user.id, role: 'writer'})) - ) + get().dispatch.dynamic.onAddMembersWizardPushMembers( + [...teamSoFar].map(user => ({assertion: user.id, role: 'writer'})) + ) get().dispatch.finishedTeamBuilding() } }, @@ -361,11 +394,11 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const {finishedTeam, namespace} = get() switch (namespace) { case 'crypto': { - useCryptoState.getState().dispatch.onTeamBuildingFinished(finishedTeam) + get().dispatch.dynamic.onFinishedTeamBuildingCrypto(finishedTeam) break } case 'chat2': { - storeRegistry.getState('chat').dispatch.onTeamBuildingFinished(finishedTeam) + get().dispatch.dynamic.onFinishedTeamBuildingChat(finishedTeam) break } default: @@ -416,7 +449,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { let users: typeof _users if (selectedService === 'keybase') { // If we are on Keybase tab, do additional search if query is phone/email. - const userRegion = storeRegistry.getState('settings-contacts').userCountryCode + const userRegion = get().dispatch.dynamic.onGetSettingsContactsUserCountryCode() users = await specialContactSearch(_users, searchQuery, userRegion) } else { users = _users @@ -433,7 +466,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { } return arr }, new Array<{info: {fullname: string}; name: string}>()) - storeRegistry.getState('users').dispatch.updates(updates) + get().dispatch.dynamic.onUsersUpdates(updates) const blocks = users.reduce((arr, {serviceMap}) => { const {keybase} = serviceMap if (keybase) { @@ -441,7 +474,9 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { } return arr }, new Array()) - blocks.length && storeRegistry.getState('users').dispatch.getBlockState(blocks) + if (blocks.length) { + get().dispatch.dynamic.onUsersGetBlockState(blocks) + } } ignorePromise(f()) }, diff --git a/shared/team-building/email-search.tsx b/shared/team-building/email-search.tsx index 3b0ffa004508..2f5f8f17930d 100644 --- a/shared/team-building/email-search.tsx +++ b/shared/team-building/email-search.tsx @@ -6,6 +6,7 @@ import type * as T from '@/constants/types' import {validateEmailAddress} from '@/util/email-address' import {UserMatchMention} from './phone-search' import ContinueButton from './continue-button' +import {searchWaitingKey} from '@/constants/strings' type EmailSearchProps = { continueLabel: string @@ -17,7 +18,7 @@ const EmailSearch = ({continueLabel, namespace, search}: EmailSearchProps) => { const teamBuildingSearchResults = TB.useTBContext(s => s.searchResults) const [isEmailValid, setEmailValidity] = React.useState(false) const [emailString, setEmailString] = React.useState('') - const waiting = C.Waiting.useAnyWaiting(TB.searchWaitingKey) + const waiting = C.Waiting.useAnyWaiting(searchWaitingKey) const user: T.TB.User | undefined = teamBuildingSearchResults.get(emailString)?.get('email')?.[0] const canSubmit = !!user && !waiting && isEmailValid diff --git a/shared/team-building/phone-search.tsx b/shared/team-building/phone-search.tsx index 69a8a3d36f61..7c3a04a330bd 100644 --- a/shared/team-building/phone-search.tsx +++ b/shared/team-building/phone-search.tsx @@ -5,6 +5,7 @@ import * as Kb from '@/common-adapters/index' import type * as T from '@/constants/types' import ContinueButton from './continue-button' import {useSettingsPhoneState} from '@/stores/settings-phone' +import {searchWaitingKey} from '@/constants/strings' type PhoneSearchProps = { continueLabel: string @@ -18,7 +19,7 @@ const PhoneSearch = (props: PhoneSearchProps) => { const [isPhoneValid, setPhoneValidity] = React.useState(false) const [phoneNumber, setPhoneNumber] = React.useState('') const [phoneInputKey, setPhoneInputKey] = React.useState(0) - const waiting = C.Waiting.useAnyWaiting(TB.searchWaitingKey) + const waiting = C.Waiting.useAnyWaiting(searchWaitingKey) const loadDefaultPhoneCountry = useSettingsPhoneState(s => s.dispatch.loadDefaultPhoneCountry) // trigger a default phone number country rpc if it's not already loaded const defaultCountry = useSettingsPhoneState(s => s.defaultCountry) From 29bf146c24e66e5e8650cd811a130bd0baaf693e Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Mon, 12 Jan 2026 17:23:56 -0500 Subject: [PATCH 14/20] WIP: shift 15 (#28799) * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/constants/fs/common.native.tsx | 69 ---- shared/constants/fs/index.tsx | 11 +- .../fs/platform-specific.android.tsx | 66 ---- shared/constants/fs/platform-specific.d.ts | 2 - .../fs/platform-specific.desktop.tsx | 310 ------------------ shared/constants/fs/platform-specific.ios.tsx | 2 - shared/constants/init/index.desktop.tsx | 303 ++++++++++++++++- shared/constants/init/index.native.tsx | 122 ++++++- shared/constants/init/shared.tsx | 2 +- shared/stores/convostate.tsx | 3 - shared/stores/fs.tsx | 7 +- shared/stores/team-building.tsx | 5 +- 12 files changed, 430 insertions(+), 472 deletions(-) delete mode 100644 shared/constants/fs/common.native.tsx delete mode 100644 shared/constants/fs/platform-specific.android.tsx delete mode 100644 shared/constants/fs/platform-specific.d.ts delete mode 100644 shared/constants/fs/platform-specific.desktop.tsx delete mode 100644 shared/constants/fs/platform-specific.ios.tsx diff --git a/shared/constants/fs/common.native.tsx b/shared/constants/fs/common.native.tsx deleted file mode 100644 index 920f0561993f..000000000000 --- a/shared/constants/fs/common.native.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import logger from '@/logger' -import {ignorePromise} from '../utils' -import {wrapErrors} from '@/util/debug' -import * as T from '../types' -import * as Styles from '@/styles' -import * as FS from '@/stores/fs' -import {launchImageLibraryAsync} from '@/util/expo-image-picker.native' -import {saveAttachmentToCameraRoll, showShareActionSheet} from '../platform-specific' -import {useFSState} from '@/stores/fs' - -export default function initNative() { - useFSState.setState(s => { - s.dispatch.dynamic.pickAndUploadMobile = wrapErrors( - (type: T.FS.MobilePickType, parentPath: T.FS.Path) => { - const f = async () => { - try { - const result = await launchImageLibraryAsync(type, true, true) - if (result.canceled) return - result.assets.map(r => - useFSState.getState().dispatch.upload(parentPath, Styles.unnormalizePath(r.uri)) - ) - } catch (e) { - FS.errorToActionOrThrow(e) - } - } - ignorePromise(f()) - } - ) - - s.dispatch.dynamic.finishedDownloadWithIntentMobile = wrapErrors( - (downloadID: string, downloadIntent: T.FS.DownloadIntent, mimeType: string) => { - const f = async () => { - const {downloads, dispatch} = useFSState.getState() - const downloadState = downloads.state.get(downloadID) || FS.emptyDownloadState - if (downloadState === FS.emptyDownloadState) { - logger.warn('missing download', downloadID) - return - } - const dismissDownload = dispatch.dismissDownload - if (downloadState.error) { - dispatch.redbar(downloadState.error) - dismissDownload(downloadID) - return - } - const {localPath} = downloadState - try { - switch (downloadIntent) { - case T.FS.DownloadIntent.CameraRoll: - await saveAttachmentToCameraRoll(localPath, mimeType) - dismissDownload(downloadID) - return - case T.FS.DownloadIntent.Share: - await showShareActionSheet({filePath: localPath, mimeType}) - dismissDownload(downloadID) - return - case T.FS.DownloadIntent.None: - return - default: - return - } - } catch (err) { - FS.errorToActionOrThrow(err) - } - } - ignorePromise(f()) - } - ) - }) -} diff --git a/shared/constants/fs/index.tsx b/shared/constants/fs/index.tsx index 543c1ff5d733..790ed28645a9 100644 --- a/shared/constants/fs/index.tsx +++ b/shared/constants/fs/index.tsx @@ -1,9 +1,10 @@ import type * as React from 'react' -import * as Tabs from '../tabs' -import * as T from '../types' -import {isLinux, isMobile} from '../platform' -import {settingsFsTab} from '../settings' -import {navigateAppend} from '../router2' +import * as Tabs from '@/constants/tabs' +import * as T from '@/constants/types' +import {isLinux, isMobile} from '@/constants/platform' +import {settingsFsTab} from '@/constants/settings' +import {navigateAppend} from '@/constants/router2' + export const makeActionForOpenPathInFilesTab = ( // TODO: remove the second arg when we are done with migrating to nav2 path: T.FS.Path diff --git a/shared/constants/fs/platform-specific.android.tsx b/shared/constants/fs/platform-specific.android.tsx deleted file mode 100644 index a31524a9b47e..000000000000 --- a/shared/constants/fs/platform-specific.android.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import * as T from '../types' -import {ignorePromise, wrapErrors} from '../utils' -import * as FS from '@/stores/fs' -import logger from '@/logger' -import nativeInit from './common.native' -import {useFSState} from '@/stores/fs' -import {androidAddCompleteDownload, fsCacheDir, fsDownloadDir} from 'react-native-kb' - -const finishedRegularDownloadIDs = new Set() - -export default function initPlatformSpecific() { - nativeInit() - - useFSState.setState(s => { - s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged = wrapErrors(() => { - const f = async () => { - await T.RPCGen.SimpleFSSimpleFSConfigureDownloadRpcPromise({ - // Android's cache dir is (when I tried) [app]/cache but Go side uses - // [app]/.cache by default, which can't be used for sharing to other apps. - cacheDirOverride: fsCacheDir, - downloadDirOverride: fsDownloadDir, - }) - } - ignorePromise(f()) - }) - // needs to be called, TODO could make this better - s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged() - - s.dispatch.dynamic.finishedRegularDownloadMobile = wrapErrors((downloadID: string, mimeType: string) => { - const f = async () => { - // This is fired from a hook and can happen more than once per downloadID. - // So just deduplicate them here. This is small enough and won't happen - // constantly, so don't worry about clearing them. - if (finishedRegularDownloadIDs.has(downloadID)) { - return - } - finishedRegularDownloadIDs.add(downloadID) - - const {downloads} = useFSState.getState() - - const downloadState = downloads.state.get(downloadID) || FS.emptyDownloadState - const downloadInfo = downloads.info.get(downloadID) || FS.emptyDownloadInfo - if (downloadState === FS.emptyDownloadState || downloadInfo === FS.emptyDownloadInfo) { - logger.warn('missing download', downloadID) - return - } - if (downloadState.error) { - return - } - try { - await androidAddCompleteDownload({ - description: `Keybase downloaded ${downloadInfo.filename}`, - mime: mimeType, - path: downloadState.localPath, - showNotification: true, - title: downloadInfo.filename, - }) - } catch { - logger.warn('Failed to addCompleteDownload') - } - // No need to dismiss here as the download wrapper does it for Android. - } - ignorePromise(f()) - }) - }) -} diff --git a/shared/constants/fs/platform-specific.d.ts b/shared/constants/fs/platform-specific.d.ts deleted file mode 100644 index e5bdb364c59a..000000000000 --- a/shared/constants/fs/platform-specific.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare function initPlatformSpecific(): void -export default initPlatformSpecific diff --git a/shared/constants/fs/platform-specific.desktop.tsx b/shared/constants/fs/platform-specific.desktop.tsx deleted file mode 100644 index 25ff18430ff0..000000000000 --- a/shared/constants/fs/platform-specific.desktop.tsx +++ /dev/null @@ -1,310 +0,0 @@ -import * as T from '@/constants/types' -import {ignorePromise, wrapErrors} from '@/constants/utils' -import * as Constants from '@/constants/fs' -import * as Tabs from '@/constants/tabs' -import {isWindows, isLinux, pathSep, isDarwin} from '@/constants/platform.desktop' -import logger from '@/logger' -import * as Path from '@/util/path' -import KB2 from '@/util/electron.desktop' -import {uint8ArrayToHex} from 'uint8array-extras' -import {navigateAppend} from '@/constants/router2' -import {useConfigState} from '@/stores/config' -import {useFSState, errorToActionOrThrow} from '@/stores/fs' - -const {openPathInFinder, openURL, getPathType, selectFilesToUploadDialog} = KB2.functions -const {darwinCopyToKBFSTempUploadFile, relaunchApp, uninstallKBFSDialog, uninstallDokanDialog} = KB2.functions -const {exitApp, windowsCheckMountFromOtherDokanInstall, installCachedDokan, uninstallDokan} = KB2.functions - -// _openPathInSystemFileManagerPromise opens `openPath` in system file manager. -// If isFolder is true, it just opens it. Otherwise, it shows it in its parent -// folder. This function does not check if the file exists, or try to convert -// KBFS paths. Caller should take care of those. -const _openPathInSystemFileManagerPromise = async (openPath: string, isFolder: boolean): Promise => - openPathInFinder?.(openPath, isFolder) - -const escapeBackslash = isWindows - ? (pathElem: string): string => - pathElem - .replace(/‰/g, '‰2030') - .replace(/([<>:"/\\|?*])/g, (_, c: Uint8Array) => '‰' + uint8ArrayToHex(c)) - : (pathElem: string): string => pathElem - -const _rebaseKbfsPathToMountLocation = (kbfsPath: T.FS.Path, mountLocation: string) => - Path.join(mountLocation, T.FS.getPathElements(kbfsPath).slice(1).map(escapeBackslash).join(pathSep)) - -const fuseStatusToUninstallExecPath = isWindows - ? (status: T.RPCGen.FuseStatus) => { - const field = status.status.fields?.find(({key}) => key === 'uninstallString') - return field?.value - } - : () => undefined - -const fuseStatusToActions = - (previousStatusType: T.FS.DriverStatusType) => (status: T.RPCGen.FuseStatus | undefined) => { - if (!status) { - useFSState.getState().dispatch.setDriverStatus(Constants.defaultDriverStatus) - return - } - - if (status.kextStarted) { - useFSState.getState().dispatch.setDriverStatus({ - ...Constants.emptyDriverStatusEnabled, - dokanOutdated: status.installAction === T.RPCGen.InstallAction.upgrade, - dokanUninstallExecPath: fuseStatusToUninstallExecPath(status), - }) - } else { - useFSState.getState().dispatch.setDriverStatus(Constants.emptyDriverStatusDisabled) - } - - if (status.kextStarted && previousStatusType === T.FS.DriverStatusType.Disabled) { - useFSState - .getState() - .dispatch.dynamic.openPathInSystemFileManagerDesktop?.(T.FS.stringToPath('/keybase')) - } - } - -const fuseInstallResultIsKextPermissionError = (result: T.RPCGen.InstallResult): boolean => - result.componentResults?.findIndex( - c => c.name === 'fuse' && c.exitCode === Constants.ExitCodeFuseKextPermissionError - ) !== -1 - -const driverEnableFuse = async (isRetry: boolean) => { - const result = await T.RPCGen.installInstallFuseRpcPromise() - if (fuseInstallResultIsKextPermissionError(result)) { - useFSState.getState().dispatch.driverKextPermissionError() - if (!isRetry) { - navigateAppend('kextPermission') - } - } else { - await T.RPCGen.installInstallKBFSRpcPromise() // restarts kbfsfuse - await T.RPCGen.kbfsMountWaitForMountsRpcPromise() - useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() - } -} - -const uninstallKBFSConfirm = async () => { - const remove = await (uninstallKBFSDialog?.() ?? Promise.resolve(false)) - if (remove) { - useFSState.getState().dispatch.driverDisabling() - } -} - -const uninstallKBFS = async () => - T.RPCGen.installUninstallKBFSRpcPromise().then(() => { - // Restart since we had to uninstall KBFS and it's needed by the service (for chat) - relaunchApp?.() - exitApp?.(0) - }) - -const uninstallDokanConfirm = async () => { - const driverStatus = useFSState.getState().sfmi.driverStatus - if (driverStatus.type !== T.FS.DriverStatusType.Enabled) { - return - } - if (!driverStatus.dokanUninstallExecPath) { - await uninstallDokanDialog?.() - useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() - return - } - useFSState.getState().dispatch.driverDisabling() -} - -const onUninstallDokan = async () => { - const driverStatus = useFSState.getState().sfmi.driverStatus - if (driverStatus.type !== T.FS.DriverStatusType.Enabled) return - const execPath: string = driverStatus.dokanUninstallExecPath || '' - logger.info('Invoking dokan uninstaller', execPath) - try { - await uninstallDokan?.(execPath) - } catch {} - useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() -} - -// Invoking the cached installer package has to happen from the topmost process -// or it won't be visible to the user. The service also does this to support command line -// operations. -const onInstallCachedDokan = async () => { - try { - await installCachedDokan?.() - useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() - } catch (e) { - errorToActionOrThrow(e) - } -} - -const initPlatformSpecific = () => { - useConfigState.subscribe((s, old) => { - if (s.appFocused === old.appFocused) return - useFSState.getState().dispatch.onChangedFocus(s.appFocused) - }) - - useFSState.setState(s => { - s.dispatch.dynamic.uploadFromDragAndDropDesktop = wrapErrors( - (parentPath: T.FS.Path, localPaths: string[]) => { - const {upload} = useFSState.getState().dispatch - const f = async () => { - if (isDarwin && darwinCopyToKBFSTempUploadFile) { - const dir = await T.RPCGen.SimpleFSSimpleFSMakeTempDirForUploadRpcPromise() - const lp = await Promise.all( - localPaths.map(async localPath => darwinCopyToKBFSTempUploadFile(dir, localPath)) - ) - lp.forEach(localPath => upload(parentPath, localPath)) - } else { - localPaths.forEach(localPath => upload(parentPath, localPath)) - } - } - ignorePromise(f()) - } - ) - - s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop = wrapErrors((localPath: string) => { - const f = async () => { - try { - if (getPathType) { - const pathType = await getPathType(localPath) - await _openPathInSystemFileManagerPromise(localPath, pathType === 'directory') - } - } catch (e) { - errorToActionOrThrow(e) - } - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.openPathInSystemFileManagerDesktop = wrapErrors((path: T.FS.Path) => { - const f = async () => { - const {sfmi, pathItems} = useFSState.getState() - return sfmi.driverStatus.type === T.FS.DriverStatusType.Enabled && sfmi.directMountDir - ? _openPathInSystemFileManagerPromise( - _rebaseKbfsPathToMountLocation(path, sfmi.directMountDir), - ![T.FS.PathKind.InGroupTlf, T.FS.PathKind.InTeamTlf].includes(Constants.parsePath(path).kind) || - Constants.getPathItem(pathItems, path).type === T.FS.PathType.Folder - ).catch((e: unknown) => errorToActionOrThrow(e, path)) - : new Promise((resolve, reject) => { - if (sfmi.driverStatus.type !== T.FS.DriverStatusType.Enabled) { - // This usually indicates a developer error as - // openPathInSystemFileManager shouldn't be used when FUSE integration - // is not enabled. So just blackbar to encourage a log send. - reject(new Error('FUSE integration is not enabled')) - } else { - logger.warn('empty directMountDir') // if this happens it might be a race? - resolve() - } - }) - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.refreshDriverStatusDesktop = wrapErrors(() => { - const f = async () => { - let status = await T.RPCGen.installFuseStatusRpcPromise({ - bundleVersion: '', - }) - if (isWindows && status.installStatus !== T.RPCGen.InstallStatus.installed) { - const m = await T.RPCGen.kbfsMountGetCurrentMountDirRpcPromise() - status = await (windowsCheckMountFromOtherDokanInstall?.(m, status) ?? Promise.resolve(status)) - } - fuseStatusToActions(useFSState.getState().sfmi.driverStatus.type)(status) - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.refreshMountDirsDesktop = wrapErrors(() => { - const f = async () => { - const {sfmi, dispatch} = useFSState.getState() - const driverStatus = sfmi.driverStatus - if (driverStatus.type !== T.FS.DriverStatusType.Enabled) { - return - } - const directMountDir = await T.RPCGen.kbfsMountGetCurrentMountDirRpcPromise() - const preferredMountDirs = await T.RPCGen.kbfsMountGetPreferredMountDirsRpcPromise() - dispatch.setDirectMountDir(directMountDir) - dispatch.setPreferredMountDirs(preferredMountDirs || []) - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.setSfmiBannerDismissedDesktop = wrapErrors((dismissed: boolean) => { - const f = async () => { - await T.RPCGen.SimpleFSSimpleFSSetSfmiBannerDismissedRpcPromise({dismissed}) - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.afterDriverEnabled = wrapErrors((isRetry: boolean) => { - const f = async () => { - useFSState.getState().dispatch.dynamic.setSfmiBannerDismissedDesktop?.(false) - if (isWindows) { - await onInstallCachedDokan() - } else { - await driverEnableFuse(isRetry) - } - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.afterDriverDisable = wrapErrors(() => { - const f = async () => { - useFSState.getState().dispatch.dynamic.setSfmiBannerDismissedDesktop?.(false) - if (isWindows) { - await uninstallDokanConfirm() - } else { - await uninstallKBFSConfirm() - } - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.afterDriverDisabling = wrapErrors(() => { - const f = async () => { - if (isWindows) { - await onUninstallDokan() - } else { - await uninstallKBFS() - } - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.openSecurityPreferencesDesktop = wrapErrors(() => { - const f = async () => { - await openURL?.('x-apple.systempreferences:com.apple.preference.security?General', {activate: true}) - } - ignorePromise(f()) - }) - - s.dispatch.dynamic.openFilesFromWidgetDesktop = wrapErrors((path: T.FS.Path) => { - useConfigState.getState().dispatch.showMain() - if (path) { - Constants.makeActionForOpenPathInFilesTab(path) - } else { - navigateAppend(Tabs.fsTab) - } - }) - - s.dispatch.dynamic.openAndUploadDesktop = wrapErrors( - (type: T.FS.OpenDialogType, parentPath: T.FS.Path) => { - const f = async () => { - const localPaths = await (selectFilesToUploadDialog?.(type, parentPath ?? undefined) ?? - Promise.resolve([])) - localPaths.forEach(localPath => useFSState.getState().dispatch.upload(parentPath, localPath)) - } - ignorePromise(f()) - } - ) - - if (!isLinux) { - s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged = wrapErrors(() => { - const {kbfsDaemonStatus, dispatch} = useFSState.getState() - if (kbfsDaemonStatus.rpcStatus === T.FS.KbfsDaemonRpcStatus.Connected) { - dispatch.dynamic.refreshDriverStatusDesktop?.() - } - dispatch.dynamic.refreshMountDirsDesktop?.() - }) - // force call as it could have happened already - s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged() - } - }) -} - -export default initPlatformSpecific diff --git a/shared/constants/fs/platform-specific.ios.tsx b/shared/constants/fs/platform-specific.ios.tsx deleted file mode 100644 index abfbc2d4b997..000000000000 --- a/shared/constants/fs/platform-specific.ios.tsx +++ /dev/null @@ -1,2 +0,0 @@ -import nativeInit from './common.native' -export default nativeInit diff --git a/shared/constants/init/index.desktop.tsx b/shared/constants/init/index.desktop.tsx index 1b239d9bad46..5c4283c71170 100644 --- a/shared/constants/init/index.desktop.tsx +++ b/shared/constants/init/index.desktop.tsx @@ -14,16 +14,25 @@ import KB2 from '@/util/electron.desktop' import logger from '@/logger' import type {RPCError} from '@/util/errors' import {getEngine} from '@/engine' -import {isLinux, isWindows} from '@/constants/platform.desktop' +import {isLinux, isWindows, isDarwin, pathSep} from '@/constants/platform.desktop' import {kbfsNotification} from '@/constants/platform-specific/kbfs-notifications' import {skipAppFocusActions} from '@/local-debug.desktop' import NotifyPopup from '@/util/notify-popup' import {noKBFSFailReason} from '@/constants/config' import {initSharedSubscriptions, _onEngineIncoming} from './shared' import {wrapErrors} from '@/util/debug' +import * as Constants from '@/constants/fs' +import * as Tabs from '@/constants/tabs' +import * as Path from '@/util/path' +import {uint8ArrayToHex} from 'uint8array-extras' +import {navigateAppend} from '@/constants/router2' +import {errorToActionOrThrow} from '@/stores/fs' const {showMainWindow, activeChanged, requestWindowsStartService, ctlQuit, dumpNodeLogger} = KB2.functions const {quitApp, exitApp, setOpenAtLogin, copyToClipboard} = KB2.functions +const {openPathInFinder, openURL, getPathType, selectFilesToUploadDialog} = KB2.functions +const {darwinCopyToKBFSTempUploadFile, relaunchApp, uninstallKBFSDialog, uninstallDokanDialog} = KB2.functions +const {windowsCheckMountFromOtherDokanInstall, installCachedDokan, uninstallDokan} = KB2.functions const dumpLogs = async (reason?: string) => { await logger.dump() @@ -125,6 +134,123 @@ export const onEngineIncoming = (action: EngineGen.Actions) => { } } +// _openPathInSystemFileManagerPromise opens `openPath` in system file manager. +// If isFolder is true, it just opens it. Otherwise, it shows it in its parent +// folder. This function does not check if the file exists, or try to convert +// KBFS paths. Caller should take care of those. +const _openPathInSystemFileManagerPromise = async (openPath: string, isFolder: boolean): Promise => + openPathInFinder?.(openPath, isFolder) + +const escapeBackslash = isWindows + ? (pathElem: string): string => + pathElem + .replace(/‰/g, '‰2030') + .replace(/([<>:"/\\|?*])/g, (_, c: Uint8Array) => '‰' + uint8ArrayToHex(c)) + : (pathElem: string): string => pathElem + +const _rebaseKbfsPathToMountLocation = (kbfsPath: T.FS.Path, mountLocation: string) => + Path.join(mountLocation, T.FS.getPathElements(kbfsPath).slice(1).map(escapeBackslash).join(pathSep)) + +const fuseStatusToUninstallExecPath = isWindows + ? (status: T.RPCGen.FuseStatus) => { + const field = status.status.fields?.find(({key}) => key === 'uninstallString') + return field?.value + } + : () => undefined + +const fuseStatusToActions = + (previousStatusType: T.FS.DriverStatusType) => (status: T.RPCGen.FuseStatus | undefined) => { + if (!status) { + useFSState.getState().dispatch.setDriverStatus(Constants.defaultDriverStatus) + return + } + + if (status.kextStarted) { + useFSState.getState().dispatch.setDriverStatus({ + ...Constants.emptyDriverStatusEnabled, + dokanOutdated: status.installAction === T.RPCGen.InstallAction.upgrade, + dokanUninstallExecPath: fuseStatusToUninstallExecPath(status), + }) + } else { + useFSState.getState().dispatch.setDriverStatus(Constants.emptyDriverStatusDisabled) + } + + if (status.kextStarted && previousStatusType === T.FS.DriverStatusType.Disabled) { + useFSState + .getState() + .dispatch.dynamic.openPathInSystemFileManagerDesktop?.(T.FS.stringToPath('/keybase')) + } + } + +const fuseInstallResultIsKextPermissionError = (result: T.RPCGen.InstallResult): boolean => + result.componentResults?.findIndex( + c => c.name === 'fuse' && c.exitCode === Constants.ExitCodeFuseKextPermissionError + ) !== -1 + +const driverEnableFuse = async (isRetry: boolean) => { + const result = await T.RPCGen.installInstallFuseRpcPromise() + if (fuseInstallResultIsKextPermissionError(result)) { + useFSState.getState().dispatch.driverKextPermissionError() + if (!isRetry) { + navigateAppend('kextPermission') + } + } else { + await T.RPCGen.installInstallKBFSRpcPromise() // restarts kbfsfuse + await T.RPCGen.kbfsMountWaitForMountsRpcPromise() + useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() + } +} + +const uninstallKBFSConfirm = async () => { + const remove = await (uninstallKBFSDialog?.() ?? Promise.resolve(false)) + if (remove) { + useFSState.getState().dispatch.driverDisabling() + } +} + +const uninstallKBFS = async () => + T.RPCGen.installUninstallKBFSRpcPromise().then(() => { + // Restart since we had to uninstall KBFS and it's needed by the service (for chat) + relaunchApp?.() + exitApp?.(0) + }) + +const uninstallDokanConfirm = async () => { + const driverStatus = useFSState.getState().sfmi.driverStatus + if (driverStatus.type !== T.FS.DriverStatusType.Enabled) { + return + } + if (!driverStatus.dokanUninstallExecPath) { + await uninstallDokanDialog?.() + useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() + return + } + useFSState.getState().dispatch.driverDisabling() +} + +const onUninstallDokan = async () => { + const driverStatus = useFSState.getState().sfmi.driverStatus + if (driverStatus.type !== T.FS.DriverStatusType.Enabled) return + const execPath: string = driverStatus.dokanUninstallExecPath || '' + logger.info('Invoking dokan uninstaller', execPath) + try { + await uninstallDokan?.(execPath) + } catch {} + useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() +} + +// Invoking the cached installer package has to happen from the topmost process +// or it won't be visible to the user. The service also does this to support command line +// operations. +const onInstallCachedDokan = async () => { + try { + await installCachedDokan?.() + useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() + } catch (e) { + errorToActionOrThrow(e) + } +} + export const initPlatformListener = () => { useConfigState.setState(s => { s.dispatch.dynamic.dumpLogsNative = dumpLogs @@ -139,6 +265,11 @@ export const initPlatformListener = () => { }) }) + useConfigState.subscribe((s, old) => { + if (s.appFocused === old.appFocused) return + useFSState.getState().dispatch.onChangedFocus(s.appFocused) + }) + useConfigState.subscribe((s, old) => { if (s.loggedIn !== old.loggedIn) { s.dispatch.osNetworkStatusChanged(navigator.onLine, 'notavailable', true) @@ -277,8 +408,176 @@ export const initPlatformListener = () => { } }) + useFSState.setState(s => { + s.dispatch.dynamic.uploadFromDragAndDropDesktop = wrapErrors( + (parentPath: T.FS.Path, localPaths: string[]) => { + const {upload} = useFSState.getState().dispatch + const f = async () => { + if (isDarwin && darwinCopyToKBFSTempUploadFile) { + const dir = await T.RPCGen.SimpleFSSimpleFSMakeTempDirForUploadRpcPromise() + const lp = await Promise.all( + localPaths.map(async localPath => darwinCopyToKBFSTempUploadFile(dir, localPath)) + ) + lp.forEach(localPath => upload(parentPath, localPath)) + } else { + localPaths.forEach(localPath => upload(parentPath, localPath)) + } + } + ignorePromise(f()) + } + ) + + s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop = wrapErrors((localPath: string) => { + const f = async () => { + try { + if (getPathType) { + const pathType = await getPathType(localPath) + await _openPathInSystemFileManagerPromise(localPath, pathType === 'directory') + } + } catch (e) { + errorToActionOrThrow(e) + } + } + ignorePromise(f()) + }) + + s.dispatch.dynamic.openPathInSystemFileManagerDesktop = wrapErrors((path: T.FS.Path) => { + const f = async () => { + const {sfmi, pathItems} = useFSState.getState() + return sfmi.driverStatus.type === T.FS.DriverStatusType.Enabled && sfmi.directMountDir + ? _openPathInSystemFileManagerPromise( + _rebaseKbfsPathToMountLocation(path, sfmi.directMountDir), + ![T.FS.PathKind.InGroupTlf, T.FS.PathKind.InTeamTlf].includes(Constants.parsePath(path).kind) || + Constants.getPathItem(pathItems, path).type === T.FS.PathType.Folder + ).catch((e: unknown) => errorToActionOrThrow(e, path)) + : new Promise((resolve, reject) => { + if (sfmi.driverStatus.type !== T.FS.DriverStatusType.Enabled) { + // This usually indicates a developer error as + // openPathInSystemFileManager shouldn't be used when FUSE integration + // is not enabled. So just blackbar to encourage a log send. + reject(new Error('FUSE integration is not enabled')) + } else { + logger.warn('empty directMountDir') // if this happens it might be a race? + resolve() + } + }) + } + ignorePromise(f()) + }) + + s.dispatch.dynamic.refreshDriverStatusDesktop = wrapErrors(() => { + const f = async () => { + let status = await T.RPCGen.installFuseStatusRpcPromise({ + bundleVersion: '', + }) + if (isWindows && status.installStatus !== T.RPCGen.InstallStatus.installed) { + const m = await T.RPCGen.kbfsMountGetCurrentMountDirRpcPromise() + status = await (windowsCheckMountFromOtherDokanInstall?.(m, status) ?? Promise.resolve(status)) + } + fuseStatusToActions(useFSState.getState().sfmi.driverStatus.type)(status) + } + ignorePromise(f()) + }) + + s.dispatch.dynamic.refreshMountDirsDesktop = wrapErrors(() => { + const f = async () => { + const {sfmi, dispatch} = useFSState.getState() + const driverStatus = sfmi.driverStatus + if (driverStatus.type !== T.FS.DriverStatusType.Enabled) { + return + } + const directMountDir = await T.RPCGen.kbfsMountGetCurrentMountDirRpcPromise() + const preferredMountDirs = await T.RPCGen.kbfsMountGetPreferredMountDirsRpcPromise() + dispatch.setDirectMountDir(directMountDir) + dispatch.setPreferredMountDirs(preferredMountDirs || []) + } + ignorePromise(f()) + }) + + s.dispatch.dynamic.setSfmiBannerDismissedDesktop = wrapErrors((dismissed: boolean) => { + const f = async () => { + await T.RPCGen.SimpleFSSimpleFSSetSfmiBannerDismissedRpcPromise({dismissed}) + } + ignorePromise(f()) + }) + + s.dispatch.dynamic.afterDriverEnabled = wrapErrors((isRetry: boolean) => { + const f = async () => { + useFSState.getState().dispatch.dynamic.setSfmiBannerDismissedDesktop?.(false) + if (isWindows) { + await onInstallCachedDokan() + } else { + await driverEnableFuse(isRetry) + } + } + ignorePromise(f()) + }) + + s.dispatch.dynamic.afterDriverDisable = wrapErrors(() => { + const f = async () => { + useFSState.getState().dispatch.dynamic.setSfmiBannerDismissedDesktop?.(false) + if (isWindows) { + await uninstallDokanConfirm() + } else { + await uninstallKBFSConfirm() + } + } + ignorePromise(f()) + }) + + s.dispatch.dynamic.afterDriverDisabling = wrapErrors(() => { + const f = async () => { + if (isWindows) { + await onUninstallDokan() + } else { + await uninstallKBFS() + } + } + ignorePromise(f()) + }) + + s.dispatch.dynamic.openSecurityPreferencesDesktop = wrapErrors(() => { + const f = async () => { + await openURL?.('x-apple.systempreferences:com.apple.preference.security?General', {activate: true}) + } + ignorePromise(f()) + }) + + s.dispatch.dynamic.openFilesFromWidgetDesktop = wrapErrors((path: T.FS.Path) => { + useConfigState.getState().dispatch.showMain() + if (path) { + Constants.makeActionForOpenPathInFilesTab(path) + } else { + navigateAppend(Tabs.fsTab) + } + }) + + s.dispatch.dynamic.openAndUploadDesktop = wrapErrors( + (type: T.FS.OpenDialogType, parentPath: T.FS.Path) => { + const f = async () => { + const localPaths = await (selectFilesToUploadDialog?.(type, parentPath ?? undefined) ?? + Promise.resolve([])) + localPaths.forEach(localPath => useFSState.getState().dispatch.upload(parentPath, localPath)) + } + ignorePromise(f()) + } + ) + + if (!isLinux) { + s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged = wrapErrors(() => { + const {kbfsDaemonStatus, dispatch} = useFSState.getState() + if (kbfsDaemonStatus.rpcStatus === T.FS.KbfsDaemonRpcStatus.Connected) { + dispatch.dynamic.refreshDriverStatusDesktop?.() + } + dispatch.dynamic.refreshMountDirsDesktop?.() + }) + // force call as it could have happened already + s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged() + } + }) + initSharedSubscriptions() - ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) + } export {onEngineConnected, onEngineDisconnected} from './shared' diff --git a/shared/constants/init/index.native.tsx b/shared/constants/init/index.native.tsx index 33f79bb51267..8e2e2755b7bc 100644 --- a/shared/constants/init/index.native.tsx +++ b/shared/constants/init/index.native.tsx @@ -25,6 +25,7 @@ import {getTab, getVisiblePath, logState} from '@/constants/router2' import {launchImageLibraryAsync} from '@/util/expo-image-picker.native' import {setupAudioMode} from '@/util/audio.native' import { + androidAddCompleteDownload, androidOpenSettings, fsCacheDir, fsDownloadDir, @@ -38,7 +39,11 @@ import type {ImageInfo} from '@/util/expo-image-picker.native' import {noConversationIDKey} from '../types/chat2/common' import {getSelectedConversation} from '../chat2/common' import {getConvoState} from '@/stores/convostate' -import {requestLocationPermission, showShareActionSheet} from '../platform-specific/index.native' +import {requestLocationPermission, saveAttachmentToCameraRoll, showShareActionSheet} from '../platform-specific/index.native' +import * as FS from '@/stores/fs' +import * as Styles from '@/styles' + +const finishedRegularDownloadIDs = new Set() const loadStartupDetails = async () => { const [routeState, initialUrl, push] = await Promise.all([ @@ -500,9 +505,120 @@ export const initPlatformListener = () => { }) }) - initSharedSubscriptions() + useFSState.setState(s => { + s.dispatch.dynamic.pickAndUploadMobile = wrapErrors( + (type: T.FS.MobilePickType, parentPath: T.FS.Path) => { + const f = async () => { + try { + const result = await launchImageLibraryAsync(type, true, true) + if (result.canceled) return + result.assets.map(r => + useFSState.getState().dispatch.upload(parentPath, Styles.unnormalizePath(r.uri)) + ) + } catch (e) { + FS.errorToActionOrThrow(e) + } + } + ignorePromise(f()) + } + ) + + s.dispatch.dynamic.finishedDownloadWithIntentMobile = wrapErrors( + (downloadID: string, downloadIntent: T.FS.DownloadIntent, mimeType: string) => { + const f = async () => { + const {downloads, dispatch} = useFSState.getState() + const downloadState = downloads.state.get(downloadID) || FS.emptyDownloadState + if (downloadState === FS.emptyDownloadState) { + logger.warn('missing download', downloadID) + return + } + const dismissDownload = dispatch.dismissDownload + if (downloadState.error) { + dispatch.redbar(downloadState.error) + dismissDownload(downloadID) + return + } + const {localPath} = downloadState + try { + switch (downloadIntent) { + case T.FS.DownloadIntent.CameraRoll: + await saveAttachmentToCameraRoll(localPath, mimeType) + dismissDownload(downloadID) + return + case T.FS.DownloadIntent.Share: + await showShareActionSheet({filePath: localPath, mimeType}) + dismissDownload(downloadID) + return + case T.FS.DownloadIntent.None: + return + default: + return + } + } catch (err) { + FS.errorToActionOrThrow(err) + } + } + ignorePromise(f()) + } + ) + }) + + if (isAndroid) { + useFSState.setState(s => { + s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged = wrapErrors(() => { + const f = async () => { + await T.RPCGen.SimpleFSSimpleFSConfigureDownloadRpcPromise({ + // Android's cache dir is (when I tried) [app]/cache but Go side uses + // [app]/.cache by default, which can't be used for sharing to other apps. + cacheDirOverride: fsCacheDir, + downloadDirOverride: fsDownloadDir, + }) + } + ignorePromise(f()) + }) + // needs to be called, TODO could make this better + s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged() + + s.dispatch.dynamic.finishedRegularDownloadMobile = wrapErrors((downloadID: string, mimeType: string) => { + const f = async () => { + // This is fired from a hook and can happen more than once per downloadID. + // So just deduplicate them here. This is small enough and won't happen + // constantly, so don't worry about clearing them. + if (finishedRegularDownloadIDs.has(downloadID)) { + return + } + finishedRegularDownloadIDs.add(downloadID) + + const {downloads} = useFSState.getState() - ignorePromise(useFSState.getState().dispatch.setupSubscriptions()) + const downloadState = downloads.state.get(downloadID) || FS.emptyDownloadState + const downloadInfo = downloads.info.get(downloadID) || FS.emptyDownloadInfo + if (downloadState === FS.emptyDownloadState || downloadInfo === FS.emptyDownloadInfo) { + logger.warn('missing download', downloadID) + return + } + if (downloadState.error) { + return + } + try { + await androidAddCompleteDownload({ + description: `Keybase downloaded ${downloadInfo.filename}`, + mime: mimeType, + path: downloadState.localPath, + showNotification: true, + title: downloadInfo.filename, + }) + } catch { + logger.warn('Failed to addCompleteDownload') + } + // No need to dismiss here as the download wrapper does it for Android. + } + ignorePromise(f()) + }) + }) + } + + initSharedSubscriptions() } export {onEngineConnected, onEngineDisconnected} from './shared' diff --git a/shared/constants/init/shared.tsx b/shared/constants/init/shared.tsx index 5a3c36820eb0..07306304d8bc 100644 --- a/shared/constants/init/shared.tsx +++ b/shared/constants/init/shared.tsx @@ -15,7 +15,7 @@ import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import {useDaemonState} from '@/stores/daemon' import {useDarkModeState} from '@/stores/darkmode' -import {handleKeybaseLink} from '../deeplinks' +import {handleKeybaseLink} from '@/constants/deeplinks' import {useFollowerState} from '@/stores/followers' import isEqual from 'lodash/isEqual' import type * as UseFSStateType from '@/stores/fs' diff --git a/shared/stores/convostate.tsx b/shared/stores/convostate.tsx index fd246ac0d5de..dd190e0caefe 100644 --- a/shared/stores/convostate.tsx +++ b/shared/stores/convostate.tsx @@ -298,7 +298,6 @@ export interface ConvoState extends ConvoStore { setReplyTo: (o: T.Chat.Ordinal) => void setThreadSearchQuery: (query: string) => void setTyping: DebouncedFunc<(t: Set) => void> - setupSubscriptions: () => void showInfoPanel: (show: boolean, tab: 'settings' | 'members' | 'attachments' | 'bots' | undefined) => void tabSelected: () => void threadSearch: (query: string) => void @@ -2845,7 +2844,6 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { } }) }, 1000), - setupSubscriptions: () => {}, showInfoPanel: (show, tab) => { storeRegistry.getState('chat').dispatch.updateInfoPanel(show, tab) const conversationIDKey = get().id @@ -3254,7 +3252,6 @@ const createConvoStore = (id: T.Chat.ConversationIDKey) => { const next = Z.createZustand(createSlice) next.setState({id}) chatStores.set(id, next) - next.getState().dispatch.setupSubscriptions() return next } diff --git a/shared/stores/fs.tsx b/shared/stores/fs.tsx index a7dbef4ad088..86ac6863c5a0 100644 --- a/shared/stores/fs.tsx +++ b/shared/stores/fs.tsx @@ -269,7 +269,6 @@ export interface State extends Store { setTlfsAsUnloaded: () => void setTlfSyncConfig: (tlfPath: T.FS.Path, enabled: boolean) => void setSorting: (path: T.FS.Path, sortSetting: T.FS.SortSetting) => void - setupSubscriptions: () => Promise showIncomingShare: (initialDestinationParentPath: T.FS.Path) => void showMoveOrCopy: (initialDestinationParentPath: T.FS.Path) => void startManualConflictResolution: (tlfPath: T.FS.Path) => void @@ -1596,11 +1595,7 @@ export const useFSState = Z.createZustand((set, get) => { set(s => { s.tlfs.loaded = false }) - }, - setupSubscriptions: async () => { - const initPlatformSpecific = await import('../constants/fs/platform-specific') - initPlatformSpecific.default() - }, + }, showIncomingShare: initialDestinationParentPath => { set(s => { if (s.destinationPicker.source.type !== T.FS.DestinationPickerSource.IncomingShare) { diff --git a/shared/stores/team-building.tsx b/shared/stores/team-building.tsx index cd65d9ee05de..d76b23e45847 100644 --- a/shared/stores/team-building.tsx +++ b/shared/stores/team-building.tsx @@ -1,6 +1,5 @@ import * as T from '@/constants/types' import {ignorePromise} from '@/constants/utils' -import * as Router2 from '@/stores/router2' import * as React from 'react' import * as Z from '@/util/zustand' import logger from '@/logger' @@ -12,7 +11,7 @@ import {type StoreApi, type UseBoundStore, useStore} from 'zustand' import {validateEmailAddress} from '@/util/email-address' import {registerDebugClear} from '@/util/debug' import {searchWaitingKey} from '@/constants/strings' -import {navigateUp} from '@/constants/router2' +import {navigateUp, getModalStack} from '@/constants/router2' export {allServices, selfToUser} from '@/constants/team-building' export {searchWaitingKey} from '@/constants/strings' @@ -301,7 +300,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { }) }, closeTeamBuilding: () => { - const modals = Router2.getModalStack() + const modals = getModalStack() const routeNames = [...namespaceToRoute.values()] const routeName = modals.at(-1)?.name if (routeNames.includes(routeName ?? '')) { From 035010e1b118d74ea0f48f845f2280143bc4f3d1 Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Tue, 13 Jan 2026 08:51:09 -0500 Subject: [PATCH 15/20] WIP: shift 16 (#28800) * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/chat/conversation/bottom-banner.tsx | 3 +- .../input-area/location-popup.native.tsx | 2 +- .../messages/special-top-message.tsx | 4 +- .../messages/system-git-push/container.tsx | 4 +- shared/constants/{fs/index.tsx => fs.tsx} | 306 ++++------------ shared/constants/index.tsx | 1 - shared/constants/init/index.desktop.tsx | 10 +- shared/constants/init/index.native.tsx | 79 +++-- shared/constants/notifications.tsx | 0 shared/constants/people.tsx | 0 shared/constants/recover-password.tsx | 1 - shared/constants/strings.tsx | 7 + shared/constants/tracker2.tsx | 0 shared/constants/unlock-folders.tsx | 0 shared/constants/users.tsx | 0 shared/constants/values.tsx | 9 + shared/constants/wallets.tsx | 2 - shared/constants/whats-new.tsx | 69 ---- shared/crypto/input.tsx | 2 +- shared/crypto/output.tsx | 2 +- shared/desktop/app/installer.desktop.tsx | 19 +- shared/fs/banner/reset-banner.tsx | 2 +- shared/fs/common/kbfs-path.tsx | 2 +- shared/git/row.tsx | 2 +- shared/profile/user/actions/index.tsx | 4 +- shared/settings/archive/index.tsx | 8 +- shared/stores/convostate.tsx | 6 +- shared/stores/fs.tsx | 327 ++++++++++++++---- shared/stores/wallets.tsx | 4 +- shared/stores/whats-new.tsx | 66 +++- .../search-result/people-result.tsx | 4 +- shared/teams/container.tsx | 2 +- shared/teams/team/menu-container.tsx | 2 +- .../platform-specific/index.d.ts | 2 +- .../platform-specific/index.desktop.tsx | 0 .../platform-specific/index.native.tsx | 4 +- .../input-monitor.desktop.tsx | 0 .../platform-specific/kbfs-notifications.tsx | 0 38 files changed, 487 insertions(+), 468 deletions(-) rename shared/constants/{fs/index.tsx => fs.tsx} (74%) delete mode 100644 shared/constants/notifications.tsx delete mode 100644 shared/constants/people.tsx delete mode 100644 shared/constants/recover-password.tsx delete mode 100644 shared/constants/tracker2.tsx delete mode 100644 shared/constants/unlock-folders.tsx delete mode 100644 shared/constants/users.tsx delete mode 100644 shared/constants/wallets.tsx delete mode 100644 shared/constants/whats-new.tsx rename shared/{constants => util}/platform-specific/index.d.ts (92%) rename shared/{constants => util}/platform-specific/index.desktop.tsx (100%) rename shared/{constants => util}/platform-specific/index.native.tsx (97%) rename shared/{constants => util}/platform-specific/input-monitor.desktop.tsx (100%) rename shared/{constants => util}/platform-specific/kbfs-notifications.tsx (100%) diff --git a/shared/chat/conversation/bottom-banner.tsx b/shared/chat/conversation/bottom-banner.tsx index 6d5fa9af7d4e..878d44341538 100644 --- a/shared/chat/conversation/bottom-banner.tsx +++ b/shared/chat/conversation/bottom-banner.tsx @@ -7,6 +7,7 @@ import {assertionToDisplay} from '@/common-adapters/usernames' import type {Props as TextProps} from '@/common-adapters/text' import {useUsersState} from '@/stores/users' import {useFollowerState} from '@/stores/followers' +import {showShareActionSheet} from '@/util/platform-specific' const installMessage = `I sent you encrypted messages on Keybase. You can install it here: https://keybase.io/phone-app` @@ -16,7 +17,7 @@ const Invite = () => { const users = participantInfoAll.filter(p => p.includes('@')) const openShareSheet = () => { - C.PlatformSpecific.showShareActionSheet({ + showShareActionSheet({ message: installMessage, mimeType: 'text/plain', }) diff --git a/shared/chat/conversation/input-area/location-popup.native.tsx b/shared/chat/conversation/input-area/location-popup.native.tsx index 1df813f11cf2..2327f955a1f0 100644 --- a/shared/chat/conversation/input-area/location-popup.native.tsx +++ b/shared/chat/conversation/input-area/location-popup.native.tsx @@ -7,7 +7,7 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import LocationMap from '@/chat/location-map' import {useCurrentUserState} from '@/stores/current-user' -import {requestLocationPermission} from '@/constants/platform-specific' +import {requestLocationPermission} from '@/util/platform-specific' import * as ExpoLocation from 'expo-location' const useWatchPosition = (conversationIDKey: T.Chat.ConversationIDKey) => { diff --git a/shared/chat/conversation/messages/special-top-message.tsx b/shared/chat/conversation/messages/special-top-message.tsx index 902b3c7f2bf0..e726d608a19c 100644 --- a/shared/chat/conversation/messages/special-top-message.tsx +++ b/shared/chat/conversation/messages/special-top-message.tsx @@ -10,7 +10,7 @@ import NewChatCard from './cards/new-chat' import ProfileResetNotice from './system-profile-reset-notice' import RetentionNotice from './retention-notice' import {usingFlashList} from '../list-area/flashlist-config' -import * as FS from '@/stores/fs' +import * as FS from '@/constants/fs' import {useCurrentUserState} from '@/stores/current-user' const ErrorMessage = () => { @@ -178,7 +178,7 @@ const SpecialTopMessage = React.memo(function SpecialTopMessage() { }, []) const openPrivateFolder = React.useCallback(() => { - FS.makeActionForOpenPathInFilesTab(T.FS.stringToPath(`/keybase/private/${username}`)) + FS.navToPath(T.FS.stringToPath(`/keybase/private/${username}`)) }, [username]) return ( diff --git a/shared/chat/conversation/messages/system-git-push/container.tsx b/shared/chat/conversation/messages/system-git-push/container.tsx index cd31144d737f..725af44edf1a 100644 --- a/shared/chat/conversation/messages/system-git-push/container.tsx +++ b/shared/chat/conversation/messages/system-git-push/container.tsx @@ -4,7 +4,7 @@ import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {useGitState} from '@/stores/git' import UserNotice from '../user-notice' -import * as FS from '@/stores/fs' +import * as FS from '@/constants/fs' import {useCurrentUserState} from '@/stores/current-user' type OwnProps = {message: T.Chat.MessageSystemGitPush} @@ -21,7 +21,7 @@ const GitContainer = React.memo(function GitContainer(p: OwnProps) { '/.kbfs_autogit_commit_' + commitHash ) - FS.makeActionForOpenPathInFilesTab(path) + FS.navToPath(path) }, [message] ) diff --git a/shared/constants/fs/index.tsx b/shared/constants/fs.tsx similarity index 74% rename from shared/constants/fs/index.tsx rename to shared/constants/fs.tsx index 790ed28645a9..13b1a8580584 100644 --- a/shared/constants/fs/index.tsx +++ b/shared/constants/fs.tsx @@ -1,42 +1,28 @@ -import type * as React from 'react' -import * as Tabs from '@/constants/tabs' import * as T from '@/constants/types' import {isLinux, isMobile} from '@/constants/platform' -import {settingsFsTab} from '@/constants/settings' import {navigateAppend} from '@/constants/router2' -export const makeActionForOpenPathInFilesTab = ( - // TODO: remove the second arg when we are done with migrating to nav2 - path: T.FS.Path -) => { - navigateAppend({props: {path}, selected: 'fsRoot'}) -} - -// Exit Codes -export const ExitCodeFuseKextError = 4 -export const ExitCodeFuseKextPermissionError = 5 -export const ExitCodeAuthCanceledError = 6 - -// Path Constants -export const defaultPath = T.FS.stringToPath('/keybase') - // Prefetch Constants -export const prefetchNotStarted: T.FS.PrefetchNotStarted = { +const prefetchNotStarted: T.FS.PrefetchNotStarted = { state: T.FS.PrefetchState.NotStarted, } -export const prefetchComplete: T.FS.PrefetchComplete = { +const prefetchComplete: T.FS.PrefetchComplete = { state: T.FS.PrefetchState.Complete, } -export const emptyPrefetchInProgress: T.FS.PrefetchInProgress = { - bytesFetched: 0, - bytesTotal: 0, - endEstimate: 0, - startTime: 0, - state: T.FS.PrefetchState.InProgress, +export {prefetchNotStarted, prefetchComplete} + +export const navToPath = ( + // TODO: remove the second arg when we are done with migrating to nav2 + path: T.FS.Path +) => { + navigateAppend({props: {path}, selected: 'fsRoot'}) } +// Path Constants +export const defaultPath = T.FS.stringToPath('/keybase') + // PathItem Constants const pathItemMetadataDefault = { lastModifiedTimestamp: 0, @@ -70,68 +56,53 @@ export const unknownPathItem: T.FS.UnknownPathItem = { type: T.FS.PathType.Unknown, } -// Sync Config Constants -export const tlfSyncEnabled: T.FS.TlfSyncEnabled = { - mode: T.FS.TlfSyncMode.Enabled, -} - -export const tlfSyncDisabled: T.FS.TlfSyncDisabled = { - mode: T.FS.TlfSyncMode.Disabled, -} - -export const makeTlfSyncPartial = ({ - enabledPaths, -}: { - enabledPaths?: T.FS.TlfSyncPartial['enabledPaths'] -}): T.FS.TlfSyncPartial => ({ - enabledPaths: [...(enabledPaths || [])], - mode: T.FS.TlfSyncMode.Partial, -}) - -// Conflict State Constants -export const makeConflictStateNormalView = ({ - localViewTlfPaths, - resolvingConflict, - stuckInConflict, -}: Partial): T.FS.ConflictStateNormalView => ({ - localViewTlfPaths: [...(localViewTlfPaths || [])], - resolvingConflict: resolvingConflict || false, - stuckInConflict: stuckInConflict || false, - type: T.FS.ConflictStateType.NormalView, -}) - -export const tlfNormalViewWithNoConflict = makeConflictStateNormalView({}) - -export const makeConflictStateManualResolvingLocalView = ({ - normalViewTlfPath, -}: Partial): T.FS.ConflictStateManualResolvingLocalView => ({ - normalViewTlfPath: normalViewTlfPath || defaultPath, - type: T.FS.ConflictStateType.ManualResolvingLocalView, -}) - // Factory Functions -export const makeTlf = (p: Partial): T.FS.Tlf => { - const {conflictState, isFavorite, isIgnored, isNew, name, resetParticipants, syncConfig, teamId, tlfMtime} = - p - return { - conflictState: conflictState || tlfNormalViewWithNoConflict, - isFavorite: isFavorite || false, - isIgnored: isIgnored || false, - isNew: isNew || false, - name: name || '', - resetParticipants: [...(resetParticipants || [])], - syncConfig: syncConfig || tlfSyncDisabled, - teamId: teamId || '', - tlfMtime: tlfMtime || 0, - /* See comment in constants/types/fs.js - needsRekey: false, - waitingForParticipantUnlock: I.List(), - youCanUnlock: I.List(), - */ +export const unknownTlf = (() => { + const tlfSyncDisabled: T.FS.TlfSyncDisabled = { + mode: T.FS.TlfSyncMode.Disabled, + } + const makeConflictStateNormalView = ({ + localViewTlfPaths, + resolvingConflict, + stuckInConflict, + }: Partial): T.FS.ConflictStateNormalView => ({ + localViewTlfPaths: [...(localViewTlfPaths || [])], + resolvingConflict: resolvingConflict || false, + stuckInConflict: stuckInConflict || false, + type: T.FS.ConflictStateType.NormalView, + }) + const tlfNormalViewWithNoConflict = makeConflictStateNormalView({}) + const makeTlf = (p: Partial): T.FS.Tlf => { + const { + conflictState, + isFavorite, + isIgnored, + isNew, + name, + resetParticipants, + syncConfig, + teamId, + tlfMtime, + } = p + return { + conflictState: conflictState || tlfNormalViewWithNoConflict, + isFavorite: isFavorite || false, + isIgnored: isIgnored || false, + isNew: isNew || false, + name: name || '', + resetParticipants: [...(resetParticipants || [])], + syncConfig: syncConfig || tlfSyncDisabled, + teamId: teamId || '', + tlfMtime: tlfMtime || 0, + /* See comment in constants/types/fs.js + needsRekey: false, + waitingForParticipantUnlock: I.List(), + youCanUnlock: I.List(), + */ + } } -} - -export const unknownTlf = makeTlf({}) + return makeTlf({}) +})() // Empty/Default Objects export const emptyNewFolder: T.FS.Edit = { @@ -205,19 +176,6 @@ export const emptyFileContext: T.FS.FileContext = { viewType: T.RPCGen.GUIViewType.default, } -export const emptyTlfUpdate: T.FS.TlfUpdate = { - history: [], - path: T.FS.stringToPath(''), - serverTime: 0, - writer: '', -} - -export const emptyTlfEdit: T.FS.TlfEdit = { - editType: T.FS.FileEditType.Unknown, - filename: '', - serverTime: 0, -} - // Driver Status Constants export const driverStatusUnknown: T.FS.DriverStatusUnknown = { type: T.FS.DriverStatusType.Unknown, @@ -243,45 +201,25 @@ export const unknownKbfsDaemonStatus: T.FS.KbfsDaemonStatus = { rpcStatus: T.FS.KbfsDaemonRpcStatus.Waiting, } -// Route Constants -export const fsRootRouteForNav1 = isMobile ? [Tabs.settingsTab, settingsFsTab] : [Tabs.fsTab] - -// Error Constants -export const invalidTokenError = new Error('invalid token') -export const notFoundError = new Error('not found') - // Parsed Path Constants -export const parsedPathRoot: T.FS.ParsedPathRoot = {kind: T.FS.PathKind.Root} +const parsedPathRoot: T.FS.ParsedPathRoot = {kind: T.FS.PathKind.Root} -export const parsedPathPrivateList: T.FS.ParsedPathTlfList = { +const parsedPathPrivateList: T.FS.ParsedPathTlfList = { kind: T.FS.PathKind.TlfList, tlfType: T.FS.TlfType.Private, } -export const parsedPathPublicList: T.FS.ParsedPathTlfList = { +const parsedPathPublicList: T.FS.ParsedPathTlfList = { kind: T.FS.PathKind.TlfList, tlfType: T.FS.TlfType.Public, } -export const parsedPathTeamList: T.FS.ParsedPathTlfList = { +const parsedPathTeamList: T.FS.ParsedPathTlfList = { kind: T.FS.PathKind.TlfList, tlfType: T.FS.TlfType.Team, } // Conversion Functions -export const rpcFolderTypeToTlfType = (rpcFolderType: T.RPCGen.FolderType) => { - switch (rpcFolderType) { - case T.RPCGen.FolderType.private: - return T.FS.TlfType.Private - case T.RPCGen.FolderType.public: - return T.FS.TlfType.Public - case T.RPCGen.FolderType.team: - return T.FS.TlfType.Team - default: - return null - } -} - export const pathToRPCPath = ( path: T.FS.Path ): {PathType: T.RPCGen.PathType.kbfs; kbfs: T.RPCGen.KBFSPath} => ({ @@ -292,80 +230,6 @@ export const pathToRPCPath = ( }, }) -export const rpcPathToPath = (rpcPath: T.RPCGen.KBFSPath) => T.FS.pathConcat(defaultPath, rpcPath.path) - -export const pathFromFolderRPC = (folder: T.RPCGen.Folder): T.FS.Path => { - const visibility = T.FS.getVisibilityFromRPCFolderType(folder.folderType) - if (!visibility) return T.FS.stringToPath('') - return T.FS.stringToPath(`/keybase/${visibility}/${folder.name}`) -} - -export const folderRPCFromPath = (path: T.FS.Path): T.RPCGen.FolderHandle | undefined => { - const pathElems = T.FS.getPathElements(path) - if (pathElems.length === 0) return undefined - - const visibility = T.FS.getVisibilityFromElems(pathElems) - if (visibility === undefined) return undefined - - const name = T.FS.getPathNameFromElems(pathElems) - if (name === '') return undefined - - return { - created: false, - folderType: T.FS.getRPCFolderTypeFromVisibility(visibility), - name, - } -} - -export const rpcConflictStateToConflictState = ( - rpcConflictState?: T.RPCGen.ConflictState -): T.FS.ConflictState => { - if (rpcConflictState) { - if (rpcConflictState.conflictStateType === T.RPCGen.ConflictStateType.normalview) { - const nv = rpcConflictState.normalview - return makeConflictStateNormalView({ - localViewTlfPaths: (nv.localViews || []).reduce>((arr, p) => { - p.PathType === T.RPCGen.PathType.kbfs && arr.push(rpcPathToPath(p.kbfs)) - return arr - }, []), - resolvingConflict: nv.resolvingConflict, - stuckInConflict: nv.stuckInConflict, - }) - } else { - const nv = rpcConflictState.manualresolvinglocalview.normalView - return makeConflictStateManualResolvingLocalView({ - normalViewTlfPath: nv.PathType === T.RPCGen.PathType.kbfs ? rpcPathToPath(nv.kbfs) : defaultPath, - }) - } - } else { - return tlfNormalViewWithNoConflict - } -} - -export const getSyncConfigFromRPC = ( - tlfName: string, - tlfType: T.FS.TlfType, - config?: T.RPCGen.FolderSyncConfig -): T.FS.TlfSyncConfig => { - if (!config) { - return tlfSyncDisabled - } - switch (config.mode) { - case T.RPCGen.FolderSyncMode.disabled: - return tlfSyncDisabled - case T.RPCGen.FolderSyncMode.enabled: - return tlfSyncEnabled - case T.RPCGen.FolderSyncMode.partial: - return makeTlfSyncPartial({ - enabledPaths: config.paths - ? config.paths.map(str => T.FS.getPathFromRelative(tlfName, tlfType, str)) - : [], - }) - default: - return tlfSyncDisabled - } -} - // Path/PathItem Utilities export const pathTypeToTextType = (type: T.FS.PathType) => type === T.FS.PathType.Folder ? 'BodySemibold' : 'Body' @@ -498,7 +362,7 @@ export const usernameInPath = (username: string, path: T.FS.Path) => { return elems.length >= 3 && elems[2]!.split(',').includes(username) } -export const splitTlfIntoReadersAndWriters = ( +const splitTlfIntoReadersAndWriters = ( tlf: string ): { readers?: Array @@ -898,8 +762,6 @@ export const hideOrDisableInDestinationPicker = ( ) => typeof destinationPickerIndex === 'number' && tlfType === T.FS.TlfType.Public && name !== username // Other Utilities -export const syntheticEventToTargetRect = (evt?: React.SyntheticEvent): DOMRect | undefined => - isMobile ? undefined : evt ? (evt.target as HTMLElement).getBoundingClientRect() : undefined export const showIgnoreFolder = (path: T.FS.Path, username?: string): boolean => { const elems = T.FS.getPathElements(path) @@ -908,47 +770,3 @@ export const showIgnoreFolder = (path: T.FS.Path, username?: string): boolean => } return ['public', 'private'].includes(elems[1]!) && elems[2]! !== username } - -// RPC to State Conversion -export const fsNotificationTypeToEditType = ( - fsNotificationType: T.RPCChat.Keybase1.FSNotificationType -): T.FS.FileEditType => { - switch (fsNotificationType) { - case T.RPCGen.FSNotificationType.fileCreated: - return T.FS.FileEditType.Created - case T.RPCGen.FSNotificationType.fileModified: - return T.FS.FileEditType.Modified - case T.RPCGen.FSNotificationType.fileDeleted: - return T.FS.FileEditType.Deleted - case T.RPCGen.FSNotificationType.fileRenamed: - return T.FS.FileEditType.Renamed - default: - return T.FS.FileEditType.Unknown - } -} - -export const userTlfHistoryRPCToState = ( - history: ReadonlyArray -): T.FS.UserTlfUpdates => { - let updates: Array = [] - history.forEach(folder => { - const updateServerTime = folder.serverTime - const path = pathFromFolderRPC(folder.folder) - const tlfUpdates = folder.history - ? folder.history.map(({writerName, edits}) => ({ - history: edits - ? edits.map(({filename, notificationType, serverTime}) => ({ - editType: fsNotificationTypeToEditType(notificationType), - filename, - serverTime, - })) - : [], - path, - serverTime: updateServerTime, - writer: writerName, - })) - : [] - updates = updates.concat(tlfUpdates) - }) - return updates -} diff --git a/shared/constants/index.tsx b/shared/constants/index.tsx index 7911ee17773b..7065a91ae687 100644 --- a/shared/constants/index.tsx +++ b/shared/constants/index.tsx @@ -6,5 +6,4 @@ export * as Router2 from '@/stores/router2' export * as Tabs from './tabs' export {useWaitingState} from '@/stores/waiting' export * as Waiting from '@/stores/waiting' -export * as PlatformSpecific from './platform-specific' export * from './utils' diff --git a/shared/constants/init/index.desktop.tsx b/shared/constants/init/index.desktop.tsx index 5c4283c71170..ea30f3e872ca 100644 --- a/shared/constants/init/index.desktop.tsx +++ b/shared/constants/init/index.desktop.tsx @@ -9,13 +9,13 @@ import {useProfileState} from '@/stores/profile' import {useRouterState} from '@/stores/router2' import * as EngineGen from '@/actions/engine-gen-gen' import * as T from '@/constants/types' -import InputMonitor from '@/constants/platform-specific/input-monitor.desktop' +import InputMonitor from '@/util/platform-specific/input-monitor.desktop' import KB2 from '@/util/electron.desktop' import logger from '@/logger' import type {RPCError} from '@/util/errors' import {getEngine} from '@/engine' import {isLinux, isWindows, isDarwin, pathSep} from '@/constants/platform.desktop' -import {kbfsNotification} from '@/constants/platform-specific/kbfs-notifications' +import {kbfsNotification} from '@/util/platform-specific/kbfs-notifications' import {skipAppFocusActions} from '@/local-debug.desktop' import NotifyPopup from '@/util/notify-popup' import {noKBFSFailReason} from '@/constants/config' @@ -27,6 +27,7 @@ import * as Path from '@/util/path' import {uint8ArrayToHex} from 'uint8array-extras' import {navigateAppend} from '@/constants/router2' import {errorToActionOrThrow} from '@/stores/fs' +import {ExitCodeFuseKextPermissionError} from '@/constants/values' const {showMainWindow, activeChanged, requestWindowsStartService, ctlQuit, dumpNodeLogger} = KB2.functions const {quitApp, exitApp, setOpenAtLogin, copyToClipboard} = KB2.functions @@ -184,7 +185,7 @@ const fuseStatusToActions = const fuseInstallResultIsKextPermissionError = (result: T.RPCGen.InstallResult): boolean => result.componentResults?.findIndex( - c => c.name === 'fuse' && c.exitCode === Constants.ExitCodeFuseKextPermissionError + c => c.name === 'fuse' && c.exitCode === ExitCodeFuseKextPermissionError ) !== -1 const driverEnableFuse = async (isRetry: boolean) => { @@ -546,7 +547,7 @@ export const initPlatformListener = () => { s.dispatch.dynamic.openFilesFromWidgetDesktop = wrapErrors((path: T.FS.Path) => { useConfigState.getState().dispatch.showMain() if (path) { - Constants.makeActionForOpenPathInFilesTab(path) + Constants.navToPath(path) } else { navigateAppend(Tabs.fsTab) } @@ -577,7 +578,6 @@ export const initPlatformListener = () => { }) initSharedSubscriptions() - } export {onEngineConnected, onEngineDisconnected} from './shared' diff --git a/shared/constants/init/index.native.tsx b/shared/constants/init/index.native.tsx index 8e2e2755b7bc..79986552ab64 100644 --- a/shared/constants/init/index.native.tsx +++ b/shared/constants/init/index.native.tsx @@ -39,8 +39,13 @@ import type {ImageInfo} from '@/util/expo-image-picker.native' import {noConversationIDKey} from '../types/chat2/common' import {getSelectedConversation} from '../chat2/common' import {getConvoState} from '@/stores/convostate' -import {requestLocationPermission, saveAttachmentToCameraRoll, showShareActionSheet} from '../platform-specific/index.native' -import * as FS from '@/stores/fs' +import { + requestLocationPermission, + saveAttachmentToCameraRoll, + showShareActionSheet, +} from '@/util/platform-specific/index.native' +import * as FS from '@/constants/fs' +import {errorToActionOrThrow} from '@/stores/fs' import * as Styles from '@/styles' const finishedRegularDownloadIDs = new Set() @@ -516,7 +521,7 @@ export const initPlatformListener = () => { useFSState.getState().dispatch.upload(parentPath, Styles.unnormalizePath(r.uri)) ) } catch (e) { - FS.errorToActionOrThrow(e) + errorToActionOrThrow(e) } } ignorePromise(f()) @@ -555,7 +560,7 @@ export const initPlatformListener = () => { return } } catch (err) { - FS.errorToActionOrThrow(err) + errorToActionOrThrow(err) } } ignorePromise(f()) @@ -579,42 +584,44 @@ export const initPlatformListener = () => { // needs to be called, TODO could make this better s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged() - s.dispatch.dynamic.finishedRegularDownloadMobile = wrapErrors((downloadID: string, mimeType: string) => { - const f = async () => { - // This is fired from a hook and can happen more than once per downloadID. - // So just deduplicate them here. This is small enough and won't happen - // constantly, so don't worry about clearing them. - if (finishedRegularDownloadIDs.has(downloadID)) { - return - } - finishedRegularDownloadIDs.add(downloadID) + s.dispatch.dynamic.finishedRegularDownloadMobile = wrapErrors( + (downloadID: string, mimeType: string) => { + const f = async () => { + // This is fired from a hook and can happen more than once per downloadID. + // So just deduplicate them here. This is small enough and won't happen + // constantly, so don't worry about clearing them. + if (finishedRegularDownloadIDs.has(downloadID)) { + return + } + finishedRegularDownloadIDs.add(downloadID) - const {downloads} = useFSState.getState() + const {downloads} = useFSState.getState() - const downloadState = downloads.state.get(downloadID) || FS.emptyDownloadState - const downloadInfo = downloads.info.get(downloadID) || FS.emptyDownloadInfo - if (downloadState === FS.emptyDownloadState || downloadInfo === FS.emptyDownloadInfo) { - logger.warn('missing download', downloadID) - return - } - if (downloadState.error) { - return - } - try { - await androidAddCompleteDownload({ - description: `Keybase downloaded ${downloadInfo.filename}`, - mime: mimeType, - path: downloadState.localPath, - showNotification: true, - title: downloadInfo.filename, - }) - } catch { - logger.warn('Failed to addCompleteDownload') + const downloadState = downloads.state.get(downloadID) || FS.emptyDownloadState + const downloadInfo = downloads.info.get(downloadID) || FS.emptyDownloadInfo + if (downloadState === FS.emptyDownloadState || downloadInfo === FS.emptyDownloadInfo) { + logger.warn('missing download', downloadID) + return + } + if (downloadState.error) { + return + } + try { + await androidAddCompleteDownload({ + description: `Keybase downloaded ${downloadInfo.filename}`, + mime: mimeType, + path: downloadState.localPath, + showNotification: true, + title: downloadInfo.filename, + }) + } catch { + logger.warn('Failed to addCompleteDownload') + } + // No need to dismiss here as the download wrapper does it for Android. } - // No need to dismiss here as the download wrapper does it for Android. + ignorePromise(f()) } - ignorePromise(f()) - }) + ) }) } diff --git a/shared/constants/notifications.tsx b/shared/constants/notifications.tsx deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/shared/constants/people.tsx b/shared/constants/people.tsx deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/shared/constants/recover-password.tsx b/shared/constants/recover-password.tsx deleted file mode 100644 index 8b137891791f..000000000000 --- a/shared/constants/recover-password.tsx +++ /dev/null @@ -1 +0,0 @@ - diff --git a/shared/constants/strings.tsx b/shared/constants/strings.tsx index dc63e5f6cd85..cceff363d6c6 100644 --- a/shared/constants/strings.tsx +++ b/shared/constants/strings.tsx @@ -98,6 +98,13 @@ export const waitingKeyFSStat = 'fs:stat' export const waitingKeyFSCommitEdit = 'fs:commitEditWaitingKey' export const waitingKeyFSSetSyncOnCellular = 'fs:setSyncOnCellular' +export const loadAccountsWaitingKey = 'wallets:loadAccounts' + +export const currentVersion: string = '5.5.0' +export const lastVersion: string = '5.4.0' +export const lastLastVersion: string = '5.3.0' +export const keybaseFM = 'Keybase FM 87.7' + export const waitingKeyGitLoading = 'git:loading' export const waitingKeyUsersGetUserBlocks = 'users:getUserBlocks' diff --git a/shared/constants/tracker2.tsx b/shared/constants/tracker2.tsx deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/shared/constants/unlock-folders.tsx b/shared/constants/unlock-folders.tsx deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/shared/constants/users.tsx b/shared/constants/users.tsx deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/shared/constants/values.tsx b/shared/constants/values.tsx index ddf79f1e2170..31ec39ad5cf5 100644 --- a/shared/constants/values.tsx +++ b/shared/constants/values.tsx @@ -1,2 +1,11 @@ export const maxHandshakeTries = 3 export const maxUsernameLength = 16 + +// Exit Codes +export const ExitCodeFuseKextError = 4 +export const ExitCodeFuseKextPermissionError = 5 +export const ExitCodeAuthCanceledError = 6 +// See Installer.m: KBExitFuseCriticalUpdate +export const ExitFuseCriticalUpdate = 8 +// See install_darwin.go: exitCodeFuseCriticalUpdateFailed +export const ExitFuseCriticalUpdateFailed = 300 diff --git a/shared/constants/wallets.tsx b/shared/constants/wallets.tsx deleted file mode 100644 index 6754f164b02d..000000000000 --- a/shared/constants/wallets.tsx +++ /dev/null @@ -1,2 +0,0 @@ -export const loadAccountsWaitingKey = 'wallets:loadAccounts' - diff --git a/shared/constants/whats-new.tsx b/shared/constants/whats-new.tsx deleted file mode 100644 index bc3a3e93f98e..000000000000 --- a/shared/constants/whats-new.tsx +++ /dev/null @@ -1,69 +0,0 @@ -const semver = { - gte: (a: string, b: string) => { - const arra = a.split('.').map(i => parseInt(i)) - const [a1, a2, a3] = arra - const arrb = b.split('.').map(i => parseInt(i)) - const [b1, b2, b3] = arrb - if (arra.length === 3 && arrb.length === 3) { - return a1! >= b1! && a2! >= b2! && a3! >= b3! - } else { - return false - } - }, - valid: (v: string) => - v.split('.').reduce((cnt, i) => { - if (parseInt(i) >= 0) { - return cnt + 1 - } - return cnt - }, 0) === 3, -} - -const noVersion: string = '0.0.0' -export const currentVersion: string = '5.5.0' -export const lastVersion: string = '5.4.0' -export const lastLastVersion: string = '5.3.0' -const versions = [currentVersion, lastVersion, lastLastVersion, noVersion] as const -export const keybaseFM = 'Keybase FM 87.7' - -type SeenVersionsMap = {[key in string]: boolean} - -const isVersionValid = (version: string) => { - return version ? semver.valid(version) : false -} - -export const getSeenVersions = (lastSeenVersion: string): SeenVersionsMap => { - const initialMap: SeenVersionsMap = { - [currentVersion]: true, - [lastLastVersion]: true, - [lastVersion]: true, - [noVersion]: true, - } - - if (!lastSeenVersion || !semver.valid(lastSeenVersion)) { - return initialMap - } - if (lastSeenVersion === noVersion) { - return { - [currentVersion]: false, - [lastLastVersion]: false, - [lastVersion]: false, - [noVersion]: false, - } - } - - const validVersions = versions.filter(isVersionValid) - - const seenVersions = validVersions.reduce( - (acc, version) => ({ - ...acc, - [version]: version === noVersion ? true : semver.gte(lastSeenVersion, version), - }), - initialMap - ) - - return seenVersions -} - -export {noVersion} - diff --git a/shared/crypto/input.tsx b/shared/crypto/input.tsx index 2a04e94765a3..273288164961 100644 --- a/shared/crypto/input.tsx +++ b/shared/crypto/input.tsx @@ -3,7 +3,7 @@ import * as Crypto from '@/stores/crypto' import * as React from 'react' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' -import * as FS from '@/stores/fs' +import * as FS from '@/constants/fs' import type {IconType} from '@/common-adapters/icon.constants-gen' import capitalize from 'lodash/capitalize' import {pickFiles} from '@/util/pick-files' diff --git a/shared/crypto/output.tsx b/shared/crypto/output.tsx index ca6efb87d482..435d0edd901c 100644 --- a/shared/crypto/output.tsx +++ b/shared/crypto/output.tsx @@ -9,7 +9,7 @@ import type * as T from '@/constants/types' import {pickFiles} from '@/util/pick-files' import type HiddenString from '@/util/hidden-string' import {useFSState} from '@/stores/fs' -import * as FS from '@/stores/fs' +import * as FS from '@/constants/fs' import {useConfigState} from '@/stores/config' type OutputProps = {operation: T.Crypto.Operations} diff --git a/shared/desktop/app/installer.desktop.tsx b/shared/desktop/app/installer.desktop.tsx index 3d6306fcbc41..3d4b50dd5e73 100644 --- a/shared/desktop/app/installer.desktop.tsx +++ b/shared/desktop/app/installer.desktop.tsx @@ -9,6 +9,13 @@ import {ctlQuit} from './ctl.desktop' import {isDarwin} from '@/constants/platform' import logger from '@/logger' import zlib from 'zlib' +import { + ExitCodeAuthCanceledError, + ExitCodeFuseKextError, + ExitCodeFuseKextPermissionError, + ExitFuseCriticalUpdate, + ExitFuseCriticalUpdateFailed, +} from '@/constants/values' const file = path.join(Electron.app.getPath('userData'), 'installer.json') @@ -56,18 +63,6 @@ type ResultType = | undefined const checkErrors = (result: ResultType, errors: Array, errorTypes: ErrorTypes) => { - // Copied from old constants/favorite.js - // See Installer.m: KBExitFuseKextError - const ExitCodeFuseKextError = 4 - // See Installer.m: KBExitFuseKextPermissionError - const ExitCodeFuseKextPermissionError = 5 - // See Installer.m: KBExitAuthCanceledError - const ExitCodeAuthCanceledError = 6 - // See Installer.m: KBExitFuseCriticalUpdate - const ExitFuseCriticalUpdate = 8 - // See install_darwin.go: exitCodeFuseCriticalUpdateFailed - const ExitFuseCriticalUpdateFailed = 300 - const results = result?.componentResults || [] results.forEach(cr => { if (cr.status?.code === 0) { diff --git a/shared/fs/banner/reset-banner.tsx b/shared/fs/banner/reset-banner.tsx index ab2366b4175d..3606d16b8f2c 100644 --- a/shared/fs/banner/reset-banner.tsx +++ b/shared/fs/banner/reset-banner.tsx @@ -21,7 +21,7 @@ const ConnectedBanner = (ownProps: OwnProps) => { if (pathElems.length < 3) return const filteredPathName = folderNameWithoutUsers(pathElems[2] ?? '', users) const filteredPath = T.FS.stringToPath(['', pathElems[0], pathElems[1], filteredPathName].join('/')) - FS.makeActionForOpenPathInFilesTab(filteredPath) + FS.navToPath(filteredPath) }, [] ) diff --git a/shared/fs/common/kbfs-path.tsx b/shared/fs/common/kbfs-path.tsx index 847405ef0104..c49cd7cd96e7 100644 --- a/shared/fs/common/kbfs-path.tsx +++ b/shared/fs/common/kbfs-path.tsx @@ -18,7 +18,7 @@ type PopupProps = Props & { } const useOpenInFilesTab = (path: T.FS.Path) => { - return React.useCallback(() => FS.makeActionForOpenPathInFilesTab(path), [path]) + return React.useCallback(() => FS.navToPath(path), [path]) } const KbfsPathPopup = (props: PopupProps) => { diff --git a/shared/git/row.tsx b/shared/git/row.tsx index 7151506dfb61..af0167090a53 100644 --- a/shared/git/row.tsx +++ b/shared/git/row.tsx @@ -28,7 +28,7 @@ const ConnectedRow = React.memo(function ConnectedRow(ownProps: OwnProps) { const isNew = React.useContext(NewContext).has(id) const you = useCurrentUserState(s => s.username) const setTeamRepoSettings = Git.useGitState(s => s.dispatch.setTeamRepoSettings) - const _onBrowseGitRepo = FS.makeActionForOpenPathInFilesTab + const _onBrowseGitRepo = FS.navToPath const navigateAppend = C.useRouterState(s => s.dispatch.navigateAppend) const {url: gitURL, repoID, channelName, teamname, chatDisabled} = git diff --git a/shared/profile/user/actions/index.tsx b/shared/profile/user/actions/index.tsx index ff79f621c55e..2dcf058334ef 100644 --- a/shared/profile/user/actions/index.tsx +++ b/shared/profile/user/actions/index.tsx @@ -28,7 +28,7 @@ const Container = (ownProps: OwnProps) => { const navigateAppend = C.useRouterState(s => s.dispatch.navigateAppend) const _onAddToTeam = (username: string) => navigateAppend({props: {username}, selected: 'profileAddToTeam'}) const _onBrowsePublicFolder = (username: string) => - FS.makeActionForOpenPathInFilesTab(T.FS.stringToPath(`/keybase/public/${username}`)) + FS.navToPath(T.FS.stringToPath(`/keybase/public/${username}`)) const _onEditProfile = () => navigateAppend('profileEdit') const changeFollow = useTrackerState(s => s.dispatch.changeFollow) @@ -39,7 +39,7 @@ const Container = (ownProps: OwnProps) => { const _onManageBlocking = (username: string) => navigateAppend({props: {username}, selected: 'chatBlockingModal'}) const _onOpenPrivateFolder = (myUsername: string, theirUsername: string) => - FS.makeActionForOpenPathInFilesTab(T.FS.stringToPath(`/keybase/private/${theirUsername},${myUsername}`)) + FS.navToPath(T.FS.stringToPath(`/keybase/private/${theirUsername},${myUsername}`)) const showUser = useTrackerState(s => s.dispatch.showUser) const _onReload = (username: string) => { showUser(username, false) diff --git a/shared/settings/archive/index.tsx b/shared/settings/archive/index.tsx index b69fa85c4fbf..b4953431cd93 100644 --- a/shared/settings/archive/index.tsx +++ b/shared/settings/archive/index.tsx @@ -6,6 +6,7 @@ import {formatTimeForConversationList, formatTimeForChat} from '@/util/timestamp import {useArchiveState} from '@/stores/archive' import * as FS from '@/stores/fs' import {useFSState} from '@/stores/fs' +import {showShareActionSheet} from '@/util/platform-specific' const ChatJob = React.memo(function ChatJob(p: {index: number; id: string}) { const {id, index} = p @@ -37,7 +38,7 @@ const ChatJob = React.memo(function ChatJob(p: {index: number; id: string}) { const onShare = React.useCallback(() => { if (!job?.outPath) return - C.PlatformSpecific.showShareActionSheet({ + showShareActionSheet({ filePath: job.outPath, mimeType: 'application/zip', }) @@ -164,10 +165,7 @@ const KBFSJob = React.memo(function KBFSJob(p: {index: number; id: string}) { if (!Kb.Styles.isMobile || !job) { return } - C.PlatformSpecific.showShareActionSheet({ - filePath: job.zipFilePath, - mimeType: 'application/zip', - }) + showShareActionSheet({filePath: job.zipFilePath, mimeType: 'application/zip'}) .then(() => {}) .catch(() => {}) }, [job]) diff --git a/shared/stores/convostate.tsx b/shared/stores/convostate.tsx index dd190e0caefe..bdd488b82c9b 100644 --- a/shared/stores/convostate.tsx +++ b/shared/stores/convostate.tsx @@ -1,7 +1,7 @@ // TODO remove useChatNavigateAppend // TODO remove import * as TeamsUtil from '@/constants/teams' -import * as PlatformSpecific from '@/constants/platform-specific' +import * as PlatformSpecific from '@/util/platform-specific' import { clearModals, navigateAppend, @@ -23,7 +23,7 @@ import * as Message from '@/constants/chat2/message' import * as Meta from '@/constants/chat2/meta' import * as React from 'react' import * as Z from '@/util/zustand' -import {makeActionForOpenPathInFilesTab} from '@/constants/fs' +import {navToPath} from '@/constants/fs' import HiddenString from '@/util/hidden-string' import isEqual from 'lodash/isEqual' import logger from '@/logger' @@ -2361,7 +2361,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { ? Config.teamFolder(meta.teamname) : Config.privateFolderWithUsers(participantInfo.name) ) - makeActionForOpenPathInFilesTab(path) + navToPath(path) }, paymentInfoReceived: (messageID, paymentInfo) => { set(s => { diff --git a/shared/stores/fs.tsx b/shared/stores/fs.tsx index 86ac6863c5a0..9189486e716a 100644 --- a/shared/stores/fs.tsx +++ b/shared/stores/fs.tsx @@ -1,7 +1,7 @@ import * as EngineGen from '@/actions/engine-gen-gen' import {ignorePromise, timeoutPromise} from '@/constants/utils' import * as S from '@/constants/strings' -import {requestPermissionsToWrite} from '@/constants/platform-specific' +import {requestPermissionsToWrite} from '@/util/platform-specific' import * as Tabs from '@/constants/tabs' import * as T from '@/constants/types' import * as Z from '@/util/zustand' @@ -15,10 +15,197 @@ import {navigateAppend, navigateUp} from '@/constants/router2' import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' -import * as Util from '@/constants/fs' +import * as Constants from '@/constants/fs' export * from '@/constants/fs' +const tlfSyncEnabled: T.FS.TlfSyncEnabled = { + mode: T.FS.TlfSyncMode.Enabled, +} + +const tlfSyncDisabled: T.FS.TlfSyncDisabled = { + mode: T.FS.TlfSyncMode.Disabled, +} + +const makeTlfSyncPartial = ({ + enabledPaths, +}: { + enabledPaths?: T.FS.TlfSyncPartial['enabledPaths'] +}): T.FS.TlfSyncPartial => ({ + enabledPaths: [...(enabledPaths || [])], + mode: T.FS.TlfSyncMode.Partial, +}) + +const makeConflictStateNormalView = ({ + localViewTlfPaths, + resolvingConflict, + stuckInConflict, +}: Partial): T.FS.ConflictStateNormalView => ({ + localViewTlfPaths: [...(localViewTlfPaths || [])], + resolvingConflict: resolvingConflict || false, + stuckInConflict: stuckInConflict || false, + type: T.FS.ConflictStateType.NormalView, +}) + +const tlfNormalViewWithNoConflict = makeConflictStateNormalView({}) + +const makeConflictStateManualResolvingLocalView = ({ + normalViewTlfPath, +}: Partial): T.FS.ConflictStateManualResolvingLocalView => ({ + normalViewTlfPath: normalViewTlfPath || Constants.defaultPath, + type: T.FS.ConflictStateType.ManualResolvingLocalView, +}) + +const makeTlf = (p: Partial): T.FS.Tlf => { + const {conflictState, isFavorite, isIgnored, isNew, name, resetParticipants, syncConfig, teamId, tlfMtime} = + p + return { + conflictState: conflictState || tlfNormalViewWithNoConflict, + isFavorite: isFavorite || false, + isIgnored: isIgnored || false, + isNew: isNew || false, + name: name || '', + resetParticipants: [...(resetParticipants || [])], + syncConfig: syncConfig || tlfSyncDisabled, + teamId: teamId || '', + tlfMtime: tlfMtime || 0, + /* See comment in constants/types/fs.js + needsRekey: false, + waitingForParticipantUnlock: I.List(), + youCanUnlock: I.List(), + */ + } +} + +const rpcFolderTypeToTlfType = (rpcFolderType: T.RPCGen.FolderType) => { + switch (rpcFolderType) { + case T.RPCGen.FolderType.private: + return T.FS.TlfType.Private + case T.RPCGen.FolderType.public: + return T.FS.TlfType.Public + case T.RPCGen.FolderType.team: + return T.FS.TlfType.Team + default: + return null + } +} + +const rpcPathToPath = (rpcPath: T.RPCGen.KBFSPath) => T.FS.pathConcat(Constants.defaultPath, rpcPath.path) + +const pathFromFolderRPC = (folder: T.RPCGen.Folder): T.FS.Path => { + const visibility = T.FS.getVisibilityFromRPCFolderType(folder.folderType) + if (!visibility) return T.FS.stringToPath('') + return T.FS.stringToPath(`/keybase/${visibility}/${folder.name}`) +} + +const folderRPCFromPath = (path: T.FS.Path): T.RPCGen.FolderHandle | undefined => { + const pathElems = T.FS.getPathElements(path) + if (pathElems.length === 0) return undefined + + const visibility = T.FS.getVisibilityFromElems(pathElems) + if (visibility === undefined) return undefined + + const name = T.FS.getPathNameFromElems(pathElems) + if (name === '') return undefined + + return { + created: false, + folderType: T.FS.getRPCFolderTypeFromVisibility(visibility), + name, + } +} + +const rpcConflictStateToConflictState = (rpcConflictState?: T.RPCGen.ConflictState): T.FS.ConflictState => { + if (rpcConflictState) { + if (rpcConflictState.conflictStateType === T.RPCGen.ConflictStateType.normalview) { + const nv = rpcConflictState.normalview + return makeConflictStateNormalView({ + localViewTlfPaths: (nv.localViews || []).reduce>((arr, p) => { + p.PathType === T.RPCGen.PathType.kbfs && arr.push(rpcPathToPath(p.kbfs)) + return arr + }, []), + resolvingConflict: nv.resolvingConflict, + stuckInConflict: nv.stuckInConflict, + }) + } else { + const nv = rpcConflictState.manualresolvinglocalview.normalView + return makeConflictStateManualResolvingLocalView({ + normalViewTlfPath: + nv.PathType === T.RPCGen.PathType.kbfs ? rpcPathToPath(nv.kbfs) : Constants.defaultPath, + }) + } + } else { + return tlfNormalViewWithNoConflict + } +} + +const getSyncConfigFromRPC = ( + tlfName: string, + tlfType: T.FS.TlfType, + config?: T.RPCGen.FolderSyncConfig +): T.FS.TlfSyncConfig => { + if (!config) { + return tlfSyncDisabled + } + switch (config.mode) { + case T.RPCGen.FolderSyncMode.disabled: + return tlfSyncDisabled + case T.RPCGen.FolderSyncMode.enabled: + return tlfSyncEnabled + case T.RPCGen.FolderSyncMode.partial: + return makeTlfSyncPartial({ + enabledPaths: config.paths + ? config.paths.map(str => T.FS.getPathFromRelative(tlfName, tlfType, str)) + : [], + }) + default: + return tlfSyncDisabled + } +} + +const fsNotificationTypeToEditType = ( + fsNotificationType: T.RPCChat.Keybase1.FSNotificationType +): T.FS.FileEditType => { + switch (fsNotificationType) { + case T.RPCGen.FSNotificationType.fileCreated: + return T.FS.FileEditType.Created + case T.RPCGen.FSNotificationType.fileModified: + return T.FS.FileEditType.Modified + case T.RPCGen.FSNotificationType.fileDeleted: + return T.FS.FileEditType.Deleted + case T.RPCGen.FSNotificationType.fileRenamed: + return T.FS.FileEditType.Renamed + default: + return T.FS.FileEditType.Unknown + } +} + +const userTlfHistoryRPCToState = ( + history: ReadonlyArray +): T.FS.UserTlfUpdates => { + let updates: Array = [] + history.forEach(folder => { + const updateServerTime = folder.serverTime + const path = pathFromFolderRPC(folder.folder) + const tlfUpdates = folder.history + ? folder.history.map(({writerName, edits}) => ({ + history: edits + ? edits.map(({filename, notificationType, serverTime}) => ({ + editType: fsNotificationTypeToEditType(notificationType), + filename, + serverTime, + })) + : [], + path, + serverTime: updateServerTime, + writer: writerName, + })) + : [] + updates = updates.concat(tlfUpdates) + }) + return updates +} + const subscriptionDeduplicateIntervalSecond = 1 // RPC expects a string that's interpreted as [16]byte on Go side and it has to @@ -42,7 +229,7 @@ export const clientID = makeUUID() export const makeEditID = (): T.FS.EditID => T.FS.stringToEditID(makeUUID()) export const resetBannerType = (s: State, path: T.FS.Path): T.FS.ResetBannerType => { - const resetParticipants = Util.getTlfFromPath(s.tlfs, path).resetParticipants + const resetParticipants = Constants.getTlfFromPath(s.tlfs, path).resetParticipants if (resetParticipants.length === 0) { return T.FS.ResetBannerNoOthersType.None } @@ -90,7 +277,7 @@ export const errorToActionOrThrow = (error: unknown, path?: T.FS.Path) => { return } if (path && code && noAccessErrorCodes.includes(code)) { - const tlfPath = Util.getTlfPath(path) + const tlfPath = Constants.getTlfPath(path) if (tlfPath) { useFSState.getState().dispatch.setTlfSoftError(tlfPath, T.FS.SoftError.NoAccess) return @@ -145,17 +332,17 @@ const initialStore: Store = { errors: [], fileContext: new Map(), folderViewFilter: undefined, - kbfsDaemonStatus: Util.unknownKbfsDaemonStatus, + kbfsDaemonStatus: Constants.unknownKbfsDaemonStatus, lastPublicBannerClosedTlf: '', - overallSyncStatus: Util.emptyOverallSyncStatus, + overallSyncStatus: Constants.emptyOverallSyncStatus, pathInfos: new Map(), - pathItemActionMenu: Util.emptyPathItemActionMenu, + pathItemActionMenu: Constants.emptyPathItemActionMenu, pathItems: new Map(), pathUserSettings: new Map(), - settings: Util.emptySettings, + settings: Constants.emptySettings, sfmi: { directMountDir: '', - driverStatus: Util.defaultDriverStatus, + driverStatus: Constants.defaultDriverStatus, preferredMountDirs: [], }, softErrors: { @@ -286,25 +473,33 @@ export interface State extends Store { getUploadIconForFilesTab: () => T.FS.UploadIcon | undefined } +const emptyPrefetchInProgress: T.FS.PrefetchInProgress = { + bytesFetched: 0, + bytesTotal: 0, + endEstimate: 0, + startTime: 0, + state: T.FS.PrefetchState.InProgress, +} + const getPrefetchStatusFromRPC = ( prefetchStatus: T.RPCGen.PrefetchStatus, prefetchProgress: T.RPCGen.PrefetchProgress ) => { switch (prefetchStatus) { case T.RPCGen.PrefetchStatus.notStarted: - return Util.prefetchNotStarted + return Constants.prefetchNotStarted case T.RPCGen.PrefetchStatus.inProgress: return { - ...Util.emptyPrefetchInProgress, + ...emptyPrefetchInProgress, bytesFetched: prefetchProgress.bytesFetched, bytesTotal: prefetchProgress.bytesTotal, endEstimate: prefetchProgress.endEstimate, startTime: prefetchProgress.start, } case T.RPCGen.PrefetchStatus.complete: - return Util.prefetchComplete + return Constants.prefetchComplete default: - return Util.prefetchNotStarted + return Constants.prefetchNotStarted } } @@ -321,21 +516,21 @@ const makeEntry = (d: T.RPCGen.Dirent, children?: Set): T.FS.PathItem => switch (d.direntType) { case T.RPCGen.DirentType.dir: return { - ...Util.emptyFolder, + ...Constants.emptyFolder, ...direntToMetadata(d), children: new Set(children || []), progress: children ? T.FS.ProgressType.Loaded : T.FS.ProgressType.Pending, } as T.FS.PathItem case T.RPCGen.DirentType.sym: return { - ...Util.emptySymlink, + ...Constants.emptySymlink, ...direntToMetadata(d), // TODO: plumb link target } as T.FS.PathItem case T.RPCGen.DirentType.file: case T.RPCGen.DirentType.exec: return { - ...Util.emptyFile, + ...Constants.emptyFile, ...direntToMetadata(d), } as T.FS.PathItem } @@ -447,7 +642,7 @@ export const useFSState = Z.createZustand((set, get) => { try { await T.RPCGen.SimpleFSSimpleFSOpenRpcPromise( { - dest: Util.pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.name)), + dest: Constants.pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.name)), flags: T.RPCGen.OpenFlags.directory, opID: makeUUID(), }, @@ -463,10 +658,10 @@ export const useFSState = Z.createZustand((set, get) => { try { const opID = makeUUID() await T.RPCGen.SimpleFSSimpleFSMoveRpcPromise({ - dest: Util.pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.name)), + dest: Constants.pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.name)), opID, overwriteExistingFiles: false, - src: Util.pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.originalName)), + src: Constants.pathToRPCPath(T.FS.pathConcat(edit.parentPath, edit.originalName)), }) await T.RPCGen.SimpleFSSimpleFSWaitRpcPromise({opID}, S.waitingKeyFSCommitEdit) get().dispatch.editSuccess(editID) @@ -496,7 +691,7 @@ export const useFSState = Z.createZustand((set, get) => { try { await T.RPCGen.SimpleFSSimpleFSRemoveRpcPromise({ opID, - path: Util.pathToRPCPath(path), + path: Constants.pathToRPCPath(path), recursive: true, }) await T.RPCGen.SimpleFSSimpleFSWaitRpcPromise({opID}) @@ -535,7 +730,7 @@ export const useFSState = Z.createZustand((set, get) => { await requestPermissionsToWrite() const downloadID = await T.RPCGen.SimpleFSSimpleFSStartDownloadRpcPromise({ isRegularDownload: type === 'download', - path: Util.pathToRPCPath(path).kbfs, + path: Constants.pathToRPCPath(path).kbfs, }) if (type !== 'download') { get().dispatch.setPathItemActionMenuDownload( @@ -604,7 +799,7 @@ export const useFSState = Z.createZustand((set, get) => { }, favoriteIgnore: path => { const f = async () => { - const folder = Util.folderRPCFromPath(path) + const folder = folderRPCFromPath(path) if (!folder) { throw new Error('No folder specified') } @@ -622,7 +817,7 @@ export const useFSState = Z.createZustand((set, get) => { s.tlfs[visibility].set( elems[2] ?? '', T.castDraft({ - ...(s.tlfs[visibility].get(elems[2] ?? '') || Util.unknownTlf), + ...(s.tlfs[visibility].get(elems[2] ?? '') || Constants.unknownTlf), isIgnored: false, }) ) @@ -639,7 +834,7 @@ export const useFSState = Z.createZustand((set, get) => { s.tlfs[visibility].set( elems[2] ?? '', T.castDraft({ - ...(s.tlfs[visibility].get(elems[2] ?? '') || Util.unknownTlf), + ...(s.tlfs[visibility].get(elems[2] ?? '') || Constants.unknownTlf), isIgnored: true, }) ) @@ -671,7 +866,7 @@ export const useFSState = Z.createZustand((set, get) => { ] fs.forEach(({folders, isFavorite, isIgnored, isNew}) => folders.forEach(folder => { - const tlfType = Util.rpcFolderTypeToTlfType(folder.folderType) + const tlfType = rpcFolderTypeToTlfType(folder.folderType) const tlfName = tlfType === T.FS.TlfType.Private || tlfType === T.FS.TlfType.Public ? tlfToPreferredOrder(folder.name, useCurrentUserState.getState().username) @@ -679,14 +874,14 @@ export const useFSState = Z.createZustand((set, get) => { tlfType && payload[tlfType].set( tlfName, - Util.makeTlf({ - conflictState: Util.rpcConflictStateToConflictState(folder.conflictState || undefined), + makeTlf({ + conflictState: rpcConflictStateToConflictState(folder.conflictState || undefined), isFavorite, isIgnored, isNew, name: tlfName, resetParticipants: (folder.reset_members || []).map(({username}) => username), - syncConfig: Util.getSyncConfigFromRPC(tlfName, tlfType, folder.syncConfig || undefined), + syncConfig: getSyncConfigFromRPC(tlfName, tlfType, folder.syncConfig || undefined), teamId: folder.team_id || '', tlfMtime: folder.mtime || 0, }) @@ -702,7 +897,7 @@ export const useFSState = Z.createZustand((set, get) => { s.tlfs.loaded = true }) const counts = new Map() - counts.set(Tabs.fsTab, Util.computeBadgeNumberForAll(get().tlfs)) + counts.set(Tabs.fsTab, Constants.computeBadgeNumberForAll(get().tlfs)) storeRegistry.getState('notifications').dispatch.setBadgeCounts(counts) } } catch (e) { @@ -715,7 +910,7 @@ export const useFSState = Z.createZustand((set, get) => { finishManualConflictResolution: localViewTlfPath => { const f = async () => { await T.RPCGen.SimpleFSSimpleFSFinishResolvingConflictRpcPromise({ - path: Util.pathToRPCPath(localViewTlfPath), + path: Constants.pathToRPCPath(localViewTlfPath), }) get().dispatch.favoritesLoad() } @@ -730,14 +925,14 @@ export const useFSState = Z.createZustand((set, get) => { depth: 1, filter: T.RPCGen.ListFilter.filterSystemHidden, opID, - path: Util.pathToRPCPath(rootPath), + path: Constants.pathToRPCPath(rootPath), refreshSubscription: false, }) } else { await T.RPCGen.SimpleFSSimpleFSListRpcPromise({ filter: T.RPCGen.ListFilter.filterSystemHidden, opID, - path: Util.pathToRPCPath(rootPath), + path: Constants.pathToRPCPath(rootPath), refreshSubscription: false, }) } @@ -787,11 +982,11 @@ export const useFSState = Z.createZustand((set, get) => { // Get metadata fields of the directory that we just loaded from state to // avoid overriding them. - const rootPathItem = Util.getPathItem(get().pathItems, rootPath) + const rootPathItem = Constants.getPathItem(get().pathItems, rootPath) const rootFolder: T.FS.FolderPathItem = { ...(rootPathItem.type === T.FS.PathType.Folder ? rootPathItem - : {...Util.emptyFolder, name: T.FS.getPathName(rootPath)}), + : {...Constants.emptyFolder, name: T.FS.getPathName(rootPath)}), children: new Set(childMap.get(rootPath)), progress: T.FS.ProgressType.Loaded, } @@ -802,7 +997,7 @@ export const useFSState = Z.createZustand((set, get) => { ] as const) set(s => { pathItems.forEach((pathItemFromAction, path) => { - const oldPathItem = Util.getPathItem(s.pathItems, path) + const oldPathItem = Constants.getPathItem(s.pathItems, path) const newPathItem = updatePathItem(oldPathItem, pathItemFromAction) oldPathItem.type === T.FS.PathType.Folder && oldPathItem.children.forEach( @@ -819,7 +1014,7 @@ export const useFSState = Z.createZustand((set, get) => { if (edit.type !== T.FS.EditType.Rename) { return true } - const parent = Util.getPathItem(s.pathItems, edit.parentPath) + const parent = Constants.getPathItem(s.pathItems, edit.parentPath) if (parent.type === T.FS.PathType.Folder && parent.children.has(edit.name)) { return true } @@ -966,9 +1161,9 @@ export const useFSState = Z.createZustand((set, get) => { } try { const {folder, isFavorite, isIgnored, isNew} = await T.RPCGen.SimpleFSSimpleFSGetFolderRpcPromise({ - path: Util.pathToRPCPath(tlfPath).kbfs, + path: Constants.pathToRPCPath(tlfPath).kbfs, }) - const tlfType = Util.rpcFolderTypeToTlfType(folder.folderType) + const tlfType = rpcFolderTypeToTlfType(folder.folderType) const tlfName = tlfType === T.FS.TlfType.Private || tlfType === T.FS.TlfType.Public ? tlfToPreferredOrder(folder.name, useCurrentUserState.getState().username) @@ -979,14 +1174,14 @@ export const useFSState = Z.createZustand((set, get) => { s.tlfs.additionalTlfs.set( tlfPath, T.castDraft( - Util.makeTlf({ - conflictState: Util.rpcConflictStateToConflictState(folder.conflictState || undefined), + makeTlf({ + conflictState: rpcConflictStateToConflictState(folder.conflictState || undefined), isFavorite, isIgnored, isNew, name: tlfName, resetParticipants: (folder.reset_members || []).map(({username}) => username), - syncConfig: Util.getSyncConfigFromRPC(tlfName, tlfType, folder.syncConfig || undefined), + syncConfig: getSyncConfigFromRPC(tlfName, tlfType, folder.syncConfig || undefined), teamId: folder.team_id || '', tlfMtime: folder.mtime || 0, }) @@ -1073,7 +1268,7 @@ export const useFSState = Z.createZustand((set, get) => { const f = async () => { try { const res = await T.RPCGen.SimpleFSSimpleFSGetGUIFileContextRpcPromise({ - path: Util.pathToRPCPath(path).kbfs, + path: Constants.pathToRPCPath(path).kbfs, }) set(s => { @@ -1126,7 +1321,7 @@ export const useFSState = Z.createZustand((set, get) => { try { const dirent = await T.RPCGen.SimpleFSSimpleFSStatRpcPromise( { - path: Util.pathToRPCPath(path), + path: Constants.pathToRPCPath(path), refreshSubscription: false, }, S.waitingKeyFSStat @@ -1134,7 +1329,7 @@ export const useFSState = Z.createZustand((set, get) => { const pathItem = makeEntry(dirent) set(s => { - const oldPathItem = Util.getPathItem(s.pathItems, path) + const oldPathItem = Constants.getPathItem(s.pathItems, path) s.pathItems.set(path, T.castDraft(updatePathItem(oldPathItem, pathItem))) s.softErrors.pathErrors.delete(path) s.softErrors.tlfErrors.delete(path) @@ -1171,31 +1366,31 @@ export const useFSState = Z.createZustand((set, get) => { }, loadTlfSyncConfig: tlfPath => { const f = async () => { - const parsedPath = Util.parsePath(tlfPath) + const parsedPath = Constants.parsePath(tlfPath) if (parsedPath.kind !== T.FS.PathKind.GroupTlf && parsedPath.kind !== T.FS.PathKind.TeamTlf) { return } try { const result = await T.RPCGen.SimpleFSSimpleFSFolderSyncConfigAndStatusRpcPromise({ - path: Util.pathToRPCPath(tlfPath), + path: Constants.pathToRPCPath(tlfPath), }) - const syncConfig = Util.getSyncConfigFromRPC(parsedPath.tlfName, parsedPath.tlfType, result.config) + const syncConfig = getSyncConfigFromRPC(parsedPath.tlfName, parsedPath.tlfType, result.config) const tlfName = parsedPath.tlfName const tlfType = parsedPath.tlfType set(s => { const oldTlfList = s.tlfs[tlfType] - const oldTlfFromFavorites = oldTlfList.get(tlfName) || Util.unknownTlf - if (oldTlfFromFavorites !== Util.unknownTlf) { + const oldTlfFromFavorites = oldTlfList.get(tlfName) || Constants.unknownTlf + if (oldTlfFromFavorites !== Constants.unknownTlf) { s.tlfs[tlfType] = T.castDraft( new Map([...oldTlfList, [tlfName, {...oldTlfFromFavorites, syncConfig}]]) ) return } - const tlfPath = T.FS.pathConcat(T.FS.pathConcat(Util.defaultPath, tlfType), tlfName) - const oldTlfFromAdditional = s.tlfs.additionalTlfs.get(tlfPath) || Util.unknownTlf - if (oldTlfFromAdditional !== Util.unknownTlf) { + const tlfPath = T.FS.pathConcat(T.FS.pathConcat(Constants.defaultPath, tlfType), tlfName) + const oldTlfFromAdditional = s.tlfs.additionalTlfs.get(tlfPath) || Constants.unknownTlf + if (oldTlfFromAdditional !== Constants.unknownTlf) { s.tlfs.additionalTlfs = T.castDraft( new Map([...s.tlfs.additionalTlfs, [tlfPath, {...oldTlfFromAdditional, syncConfig}]]) ) @@ -1218,7 +1413,7 @@ export const useFSState = Z.createZustand((set, get) => { const writingToJournal = new Map( uploadStates?.map(uploadState => { - const path = Util.rpcPathToPath(uploadState.targetPath) + const path = rpcPathToPath(uploadState.targetPath) const oldUploadState = s.uploads.writingToJournal.get(path) return [ path, @@ -1257,7 +1452,7 @@ export const useFSState = Z.createZustand((set, get) => { zState.destinationPicker.source.type === T.FS.DestinationPickerSource.MoveOrCopy ? [ { - dest: Util.pathToRPCPath( + dest: Constants.pathToRPCPath( T.FS.pathConcat( destinationParentPath, T.FS.getPathName(zState.destinationPicker.source.path) @@ -1265,14 +1460,14 @@ export const useFSState = Z.createZustand((set, get) => { ), opID: makeUUID(), overwriteExistingFiles: false, - src: Util.pathToRPCPath(zState.destinationPicker.source.path), + src: Constants.pathToRPCPath(zState.destinationPicker.source.path), }, ] : zState.destinationPicker.source.source .map(item => ({originalPath: item.originalPath ?? '', scaledPath: item.scaledPath})) .filter(({originalPath}) => !!originalPath) .map(({originalPath, scaledPath}) => ({ - dest: Util.pathToRPCPath( + dest: Constants.pathToRPCPath( T.FS.pathConcat( destinationParentPath, T.FS.getLocalPathName(originalPath) @@ -1309,7 +1504,7 @@ export const useFSState = Z.createZustand((set, get) => { ignorePromise(f()) }, newFolderRow: parentPath => { - const parentPathItem = Util.getPathItem(get().pathItems, parentPath) + const parentPathItem = Constants.getPathItem(get().pathItems, parentPath) if (parentPathItem.type !== T.FS.PathType.Folder) { console.warn(`bad parentPath: ${parentPathItem.type}`) return @@ -1326,7 +1521,7 @@ export const useFSState = Z.createZustand((set, get) => { set(s => { s.edits.set(makeEditID(), { - ...Util.emptyNewFolder, + ...Constants.emptyNewFolder, name: newFolderName, originalName: newFolderName, parentPath, @@ -1556,7 +1751,7 @@ export const useFSState = Z.createZustand((set, get) => { if (old) { old.sort = sortSetting } else { - s.pathUserSettings.set(path, {...Util.defaultPathUserSetting, sort: sortSetting}) + s.pathUserSettings.set(path, {...Constants.defaultPathUserSetting, sort: sortSetting}) } }) }, @@ -1583,7 +1778,7 @@ export const useFSState = Z.createZustand((set, get) => { await T.RPCGen.SimpleFSSimpleFSSetFolderSyncConfigRpcPromise( { config: {mode: enabled ? T.RPCGen.FolderSyncMode.enabled : T.RPCGen.FolderSyncMode.disabled}, - path: Util.pathToRPCPath(tlfPath), + path: Constants.pathToRPCPath(tlfPath), }, S.waitingKeyFSSyncToggle ) @@ -1595,7 +1790,7 @@ export const useFSState = Z.createZustand((set, get) => { set(s => { s.tlfs.loaded = false }) - }, + }, showIncomingShare: initialDestinationParentPath => { set(s => { if (s.destinationPicker.source.type !== T.FS.DestinationPickerSource.IncomingShare) { @@ -1611,7 +1806,7 @@ export const useFSState = Z.createZustand((set, get) => { s.destinationPicker.source.type === T.FS.DestinationPickerSource.MoveOrCopy ? s.destinationPicker.source : { - path: Util.defaultPath, + path: Constants.defaultPath, type: T.FS.DestinationPickerSource.MoveOrCopy, } @@ -1623,7 +1818,7 @@ export const useFSState = Z.createZustand((set, get) => { startManualConflictResolution: tlfPath => { const f = async () => { await T.RPCGen.SimpleFSSimpleFSClearConflictStateRpcPromise({ - path: Util.pathToRPCPath(tlfPath), + path: Constants.pathToRPCPath(tlfPath), }) get().dispatch.favoritesLoad() } @@ -1706,7 +1901,7 @@ export const useFSState = Z.createZustand((set, get) => { } case T.FS.DiskSpaceStatus.Warning: { - const threshold = Util.humanizeBytes(get().settings.spaceAvailableNotificationThreshold, 0) + const threshold = Constants.humanizeBytes(get().settings.spaceAvailableNotificationThreshold, 0) NotifyPopup('Disk Space Low', { body: `You have less than ${threshold} of storage space left.`, }) @@ -1742,7 +1937,7 @@ export const useFSState = Z.createZustand((set, get) => { try { await T.RPCGen.SimpleFSSimpleFSStartUploadRpcPromise({ sourceLocalPath: T.FS.getNormalizedLocalPath(localPath), - targetParentPath: Util.pathToRPCPath(parentPath).kbfs, + targetParentPath: Constants.pathToRPCPath(parentPath).kbfs, }) } catch (err) { errorToActionOrThrow(err) @@ -1755,7 +1950,7 @@ export const useFSState = Z.createZustand((set, get) => { try { const writerEdits = await T.RPCGen.SimpleFSSimpleFSUserEditHistoryRpcPromise() set(s => { - s.tlfUpdates = T.castDraft(Util.userTlfHistoryRPCToState(writerEdits || [])) + s.tlfUpdates = T.castDraft(userTlfHistoryRPCToState(writerEdits || [])) }) } catch (error) { errorToActionOrThrow(error) diff --git a/shared/stores/wallets.tsx b/shared/stores/wallets.tsx index 6fffb6c14dd2..0305e954dfd6 100644 --- a/shared/stores/wallets.tsx +++ b/shared/stores/wallets.tsx @@ -1,10 +1,10 @@ import * as T from '@/constants/types' import {ignorePromise} from '@/constants/utils' import * as Z from '@/util/zustand' -import {loadAccountsWaitingKey} from '@/constants/wallets' +import {loadAccountsWaitingKey} from '@/constants/strings' import {useConfigState} from '@/stores/config' -export {loadAccountsWaitingKey} from '@/constants/wallets' +export {loadAccountsWaitingKey} from '@/constants/strings' export type Account = { accountID: string diff --git a/shared/stores/whats-new.tsx b/shared/stores/whats-new.tsx index e52289d7527c..c32512b33505 100644 --- a/shared/stores/whats-new.tsx +++ b/shared/stores/whats-new.tsx @@ -1,13 +1,75 @@ import type * as T from '@/constants/types' import * as Z from '@/util/zustand' import {uint8ArrayToString} from 'uint8array-extras' -import {noVersion, getSeenVersions} from '@/constants/whats-new' +import {currentVersion, lastVersion, lastLastVersion} from '@/constants/strings' +export {currentVersion, lastVersion, lastLastVersion, keybaseFM} from '@/constants/strings' -export {currentVersion, lastVersion, lastLastVersion, keybaseFM} from '@/constants/whats-new' +const noVersion: string = '0.0.0' +export {noVersion} // This store has no dependencies on other stores and is safe to import directly from other stores. type SeenVersionsMap = {[key in string]: boolean} +const semver = { + gte: (a: string, b: string) => { + const arra = a.split('.').map(i => parseInt(i)) + const [a1, a2, a3] = arra + const arrb = b.split('.').map(i => parseInt(i)) + const [b1, b2, b3] = arrb + if (arra.length === 3 && arrb.length === 3) { + return a1! >= b1! && a2! >= b2! && a3! >= b3! + } else { + return false + } + }, + valid: (v: string) => + v.split('.').reduce((cnt, i) => { + if (parseInt(i) >= 0) { + return cnt + 1 + } + return cnt + }, 0) === 3, +} + +const versions = [currentVersion, lastVersion, lastLastVersion, noVersion] as const + +const isVersionValid = (version: string) => { + return version ? semver.valid(version) : false +} + +const getSeenVersions = (lastSeenVersion: string): SeenVersionsMap => { + const initialMap: SeenVersionsMap = { + [currentVersion]: true, + [lastLastVersion]: true, + [lastVersion]: true, + [noVersion]: true, + } + + if (!lastSeenVersion || !semver.valid(lastSeenVersion)) { + return initialMap + } + if (lastSeenVersion === noVersion) { + return { + [currentVersion]: false, + [lastLastVersion]: false, + [lastVersion]: false, + [noVersion]: false, + } + } + + const validVersions = versions.filter(isVersionValid) + + const seenVersions = validVersions.reduce( + (acc, version) => ({ + ...acc, + [version]: version === noVersion ? true : semver.gte(lastSeenVersion, version), + }), + initialMap + ) + + return seenVersions +} + type Store = T.Immutable<{ lastSeenVersion: string seenVersions: SeenVersionsMap diff --git a/shared/team-building/search-result/people-result.tsx b/shared/team-building/search-result/people-result.tsx index 7292f26ffae4..7925b8767ac3 100644 --- a/shared/team-building/search-result/people-result.tsx +++ b/shared/team-building/search-result/people-result.tsx @@ -32,14 +32,14 @@ const PeopleResult = React.memo(function PeopleResult(props: ResultProps) { const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) const onOpenPrivateFolder = React.useCallback(() => { navigateUp() - FS.makeActionForOpenPathInFilesTab( + FS.navToPath( T.FS.stringToPath(`/keybase/private/${decoratedUsername},${myUsername}`) ) }, [navigateUp, decoratedUsername, myUsername]) const onBrowsePublicFolder = React.useCallback(() => { navigateUp() - FS.makeActionForOpenPathInFilesTab(T.FS.stringToPath(`/keybase/public/${decoratedUsername}`)) + FS.navToPath(T.FS.stringToPath(`/keybase/public/${decoratedUsername}`)) }, [navigateUp, decoratedUsername]) const onManageBlocking = React.useCallback(() => { diff --git a/shared/teams/container.tsx b/shared/teams/container.tsx index e298f8692896..890288fea27c 100644 --- a/shared/teams/container.tsx +++ b/shared/teams/container.tsx @@ -78,7 +78,7 @@ const Connected = () => { updateGregorCategory('sawChatBanner', 'true') } const onOpenFolder = (teamname: T.Teams.Teamname) => { - FS.makeActionForOpenPathInFilesTab(T.FS.stringToPath(`/keybase/team/${teamname}`)) + FS.navToPath(T.FS.stringToPath(`/keybase/team/${teamname}`)) } const onReadMore = () => { openURL('https://keybase.io/blog/introducing-keybase-teams') diff --git a/shared/teams/team/menu-container.tsx b/shared/teams/team/menu-container.tsx index d618e52631eb..5ea551600be8 100644 --- a/shared/teams/team/menu-container.tsx +++ b/shared/teams/team/menu-container.tsx @@ -98,7 +98,7 @@ const Container = (ownProps: OwnProps) => { navigateAppend({props: {teamID}, selected: 'teamReallyLeaveTeam'}) } const onOpenFolder = (teamname: string) => { - FS.makeActionForOpenPathInFilesTab(T.FS.stringToPath(`/keybase/team/${teamname}`)) + FS.navToPath(T.FS.stringToPath(`/keybase/team/${teamname}`)) } const items: Kb.MenuItems = ['Divider'] diff --git a/shared/constants/platform-specific/index.d.ts b/shared/util/platform-specific/index.d.ts similarity index 92% rename from shared/constants/platform-specific/index.d.ts rename to shared/util/platform-specific/index.d.ts index a5c165a8b3c6..caecba1087ae 100644 --- a/shared/constants/platform-specific/index.d.ts +++ b/shared/util/platform-specific/index.d.ts @@ -1,4 +1,4 @@ -import type * as T from '../types' +import type * as T from '@/constants/types' type NextURI = string diff --git a/shared/constants/platform-specific/index.desktop.tsx b/shared/util/platform-specific/index.desktop.tsx similarity index 100% rename from shared/constants/platform-specific/index.desktop.tsx rename to shared/util/platform-specific/index.desktop.tsx diff --git a/shared/constants/platform-specific/index.native.tsx b/shared/util/platform-specific/index.native.tsx similarity index 97% rename from shared/constants/platform-specific/index.native.tsx rename to shared/util/platform-specific/index.native.tsx index 3f0a71e13dfc..8b1f620d5d75 100644 --- a/shared/constants/platform-specific/index.native.tsx +++ b/shared/util/platform-specific/index.native.tsx @@ -1,10 +1,10 @@ -import * as T from '../types' +import * as T from '@/constants/types' import * as ExpoLocation from 'expo-location' import * as MediaLibrary from 'expo-media-library' import {addNotificationRequest} from 'react-native-kb' import logger from '@/logger' import {ActionSheetIOS} from 'react-native' -import {isIOS, isAndroid} from '../platform.native' +import {isIOS, isAndroid} from '@/constants/platform.native' import {androidShare, androidShareText, androidUnlink} from 'react-native-kb' export const requestPermissionsToWrite = async () => { diff --git a/shared/constants/platform-specific/input-monitor.desktop.tsx b/shared/util/platform-specific/input-monitor.desktop.tsx similarity index 100% rename from shared/constants/platform-specific/input-monitor.desktop.tsx rename to shared/util/platform-specific/input-monitor.desktop.tsx diff --git a/shared/constants/platform-specific/kbfs-notifications.tsx b/shared/util/platform-specific/kbfs-notifications.tsx similarity index 100% rename from shared/constants/platform-specific/kbfs-notifications.tsx rename to shared/util/platform-specific/kbfs-notifications.tsx From 6c42322e3695f188d316b6375b99a1c5cafef0cc Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Thu, 15 Jan 2026 08:51:54 -0500 Subject: [PATCH 16/20] WIP: shift 17 (#28803) * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- .../normal2/set-explode-popup/hooks.tsx | 7 +- .../set-explode-popup/index.desktop.tsx | 4 +- shared/chat/inbox/container.tsx | 37 +++--- shared/chat/inbox/index.d.ts | 3 +- shared/chat/inbox/index.desktop.tsx | 5 +- shared/chat/inbox/index.native.tsx | 3 +- shared/chat/inbox/row/index.tsx | 4 +- shared/chat/inbox/row/sizes.tsx | 6 +- shared/chat/inbox/row/teams-divider.tsx | 3 +- .../types/chat2 => chat/inbox}/rowitem.tsx | 0 shared/constants/init/shared.tsx | 53 ++++++++ shared/constants/types/chat2/index.tsx | 11 -- shared/constants/types/chat2/message.tsx | 5 - shared/constants/types/config.tsx | 4 - shared/constants/types/crypto.tsx | 2 - shared/constants/types/git.tsx | 7 -- shared/constants/types/push.tsx | 2 - shared/constants/types/wallets.tsx | 5 - shared/stores/autoreset.tsx | 17 ++- shared/stores/chat2.tsx | 119 ++++++++++++------ shared/stores/config.tsx | 9 +- shared/stores/git.tsx | 10 +- shared/stores/teams.tsx | 2 +- 23 files changed, 207 insertions(+), 111 deletions(-) rename shared/{constants/types/chat2 => chat/inbox}/rowitem.tsx (100%) diff --git a/shared/chat/conversation/input-area/normal2/set-explode-popup/hooks.tsx b/shared/chat/conversation/input-area/normal2/set-explode-popup/hooks.tsx index 64ae5aca987a..781e2a289d60 100644 --- a/shared/chat/conversation/input-area/normal2/set-explode-popup/hooks.tsx +++ b/shared/chat/conversation/input-area/normal2/set-explode-popup/hooks.tsx @@ -3,7 +3,12 @@ import * as React from 'react' import type * as T from '@/constants/types' import type {Props} from '.' -const messageExplodeDescriptions: T.Chat.MessageExplodeDescription[] = [ +export type MessageExplodeDescription = { + text: string + seconds: number +} + +const messageExplodeDescriptions: MessageExplodeDescription[] = [ {seconds: 30, text: '30 seconds'}, {seconds: 300, text: '5 minutes'}, {seconds: 3600, text: '60 minutes'}, diff --git a/shared/chat/conversation/input-area/normal2/set-explode-popup/index.desktop.tsx b/shared/chat/conversation/input-area/normal2/set-explode-popup/index.desktop.tsx index ed46e8c6e1f2..255ad7b0c55e 100644 --- a/shared/chat/conversation/input-area/normal2/set-explode-popup/index.desktop.tsx +++ b/shared/chat/conversation/input-area/normal2/set-explode-popup/index.desktop.tsx @@ -1,7 +1,7 @@ -import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import type {Props} from '.' import useHooks from './hooks' +import type {MessageExplodeDescription} from './hooks' const quantityTextStyle = Kb.Styles.platformStyles({ common: { @@ -13,7 +13,7 @@ const quantityTextStyle = Kb.Styles.platformStyles({ }) type ItemProps = { - desc: T.Chat.MessageExplodeDescription + desc: MessageExplodeDescription selected: boolean } diff --git a/shared/chat/inbox/container.tsx b/shared/chat/inbox/container.tsx index 210348d199d1..1bd795aef1d2 100644 --- a/shared/chat/inbox/container.tsx +++ b/shared/chat/inbox/container.tsx @@ -4,6 +4,14 @@ import * as React from 'react' import * as T from '@/constants/types' import Inbox, {type Props} from '.' import {useIsFocused} from '@react-navigation/core' +import type { + ChatInboxRowItemBig, + ChatInboxRowItemBigHeader, + ChatInboxRowItemTeamBuilder, + ChatInboxRowItemSmall, + ChatInboxRowItemDivider, + ChatInboxRowItem, +} from './rowitem' type OwnProps = { navKey: string @@ -12,9 +20,7 @@ type OwnProps = { const makeBigRows = ( bigTeams: ReadonlyArray -): Array< - T.Chat.ChatInboxRowItemBig | T.Chat.ChatInboxRowItemBigHeader | T.Chat.ChatInboxRowItemTeamBuilder -> => { +): Array => { return bigTeams.map(t => { switch (t.state) { case T.RPCChat.UIInboxBigTeamRowTyp.channel: { @@ -43,7 +49,7 @@ const makeBigRows = ( const makeSmallRows = ( smallTeams: ReadonlyArray -): Array => { +): Array => { return smallTeams.map(t => { const conversationIDKey = T.Chat.stringToConversationIDKey(t.convID) return { @@ -180,18 +186,17 @@ const Connected = (ownProps: OwnProps) => { const hasAllSmallTeamConvs = (_inboxLayout?.smallTeams?.length ?? 0) === (_inboxLayout?.totalSmallTeams ?? 0) - const divider: Array = - React.useMemo(() => { - return bigRows.length !== 0 || !hasAllSmallTeamConvs - ? [{showButton: !hasAllSmallTeamConvs || smallTeamsBelowTheFold, type: 'divider'}] - : [] - }, [bigRows.length, hasAllSmallTeamConvs, smallTeamsBelowTheFold]) - - const rows: Array = React.useMemo(() => { - const builderAfterSmall = new Array() - const builderAfterDivider = new Array() - const builderAfterBig = new Array() - const teamBuilder: T.Chat.ChatInboxRowItemTeamBuilder = {type: 'teamBuilder'} + const divider: Array = React.useMemo(() => { + return bigRows.length !== 0 || !hasAllSmallTeamConvs + ? [{showButton: !hasAllSmallTeamConvs || smallTeamsBelowTheFold, type: 'divider'}] + : [] + }, [bigRows.length, hasAllSmallTeamConvs, smallTeamsBelowTheFold]) + + const rows: Array = React.useMemo(() => { + const builderAfterSmall = new Array() + const builderAfterDivider = new Array() + const builderAfterBig = new Array() + const teamBuilder: ChatInboxRowItemTeamBuilder = {type: 'teamBuilder'} if (smallRows.length !== 0) { if (bigRows.length === 0) { if (divider.length !== 0) { diff --git a/shared/chat/inbox/index.d.ts b/shared/chat/inbox/index.d.ts index 71bf8d45eba2..24737a0fdf77 100644 --- a/shared/chat/inbox/index.d.ts +++ b/shared/chat/inbox/index.d.ts @@ -1,5 +1,6 @@ import type * as React from 'react' import type * as T from '@/constants/types' +import type {ChatInboxRowItem} from './rowitem' export type Props = { allowShowFloatingButton: boolean @@ -10,7 +11,7 @@ export type Props = { neverLoaded: boolean onNewChat: () => void onUntrustedInboxVisible: (conversationIDKeys: Array) => void - rows: Array + rows: Array setInboxNumSmallRows: (rows: number) => void smallTeamsExpanded: boolean toggleSmallTeamsExpanded: () => void diff --git a/shared/chat/inbox/index.desktop.tsx b/shared/chat/inbox/index.desktop.tsx index 98eac06219af..c40b4875c1ea 100644 --- a/shared/chat/inbox/index.desktop.tsx +++ b/shared/chat/inbox/index.desktop.tsx @@ -4,6 +4,7 @@ import * as C from '@/constants' import * as React from 'react' import type * as TInbox from './index.d' import type * as T from '@/constants/types' +import type {ChatInboxRowItem} from './rowitem' import BigTeamsDivider from './row/big-teams-divider' import BuildTeam from './row/build-team' import TeamsDivider from './row/teams-divider' @@ -47,7 +48,7 @@ const DragLine = (p: { toggleSmallTeamsExpanded: () => void setInboxNumSmallRows: (n: number) => void style: object - rows: T.Chat.ChatInboxRowItem[] + rows: ChatInboxRowItem[] }) => { const {inboxNumSmallRows, showButton, style, scrollDiv} = p const {smallTeamsExpanded, toggleSmallTeamsExpanded, rows, setInboxNumSmallRows} = p @@ -185,7 +186,7 @@ const DragLine = (p: { type InboxRowData = { inboxNumSmallRows: number navKey: string - rows: T.Chat.ChatInboxRowItem[] + rows: ChatInboxRowItem[] scrollDiv: React.RefObject selectedConversationIDKey: string setInboxNumSmallRows: (rows: number) => void diff --git a/shared/chat/inbox/index.native.tsx b/shared/chat/inbox/index.native.tsx index 41cafa1c706e..e1aa6aaf9ceb 100644 --- a/shared/chat/inbox/index.native.tsx +++ b/shared/chat/inbox/index.native.tsx @@ -16,8 +16,9 @@ import {FlatList} from 'react-native-gesture-handler' // import {FlashList, type ListRenderItemInfo} from '@shopify/flash-list' import {makeRow} from './row' import {useOpenedRowState} from './row/opened-row-state' +import type {ChatInboxRowItem} from './rowitem' -type RowItem = T.Chat.ChatInboxRowItem +type RowItem = ChatInboxRowItem const usingFlashList = false as boolean const List = /*usingFlashList ? FlashList :*/ FlatList diff --git a/shared/chat/inbox/row/index.tsx b/shared/chat/inbox/row/index.tsx index 0cd35a8c9631..c47b53e3576c 100644 --- a/shared/chat/inbox/row/index.tsx +++ b/shared/chat/inbox/row/index.tsx @@ -3,9 +3,9 @@ import BigTeamHeader from './big-team-header' import BigTeamChannel from './big-team-channel' import {SmallTeam} from './small-team' import {BigTeamsLabel} from './big-teams-label' -import type * as T from '@/constants/types' +import type {ChatInboxRowItem} from '../rowitem' -const makeRow = (item: T.Chat.ChatInboxRowItem, navKey: string, selected: boolean) => { +const makeRow = (item: ChatInboxRowItem, navKey: string, selected: boolean) => { if (item.type === 'bigTeamsLabel') { return } diff --git a/shared/chat/inbox/row/sizes.tsx b/shared/chat/inbox/row/sizes.tsx index 584b245ccfed..027ee2a5c384 100644 --- a/shared/chat/inbox/row/sizes.tsx +++ b/shared/chat/inbox/row/sizes.tsx @@ -1,7 +1,7 @@ // In order for the inbox rows to be calculated quickly we use fixed sizes for each type so // in order for the list and the rows to ensure they're the same size we keep the sizes here import * as Kb from '@/common-adapters' -import type * as T from '@/constants/types' +import type {ChatInboxRowType} from '../rowitem' export const smallRowHeight = Kb.Styles.isMobile ? 64 : 56 export const bigRowHeight = Kb.Styles.isMobile ? 40 : 24 @@ -17,8 +17,8 @@ export const dividerHeight = (showingButton: boolean) => { } } -export const getRowHeight = (type: T.Chat.ChatInboxRowType, showingDividerButton: boolean) => { - const exhaustive = (type: T.Chat.ChatInboxRowType, showingDividerButton: boolean) => { +export const getRowHeight = (type: ChatInboxRowType, showingDividerButton: boolean) => { + const exhaustive = (type: ChatInboxRowType, showingDividerButton: boolean) => { switch (type) { case 'bigTeamsLabel': return bigHeaderHeight diff --git a/shared/chat/inbox/row/teams-divider.tsx b/shared/chat/inbox/row/teams-divider.tsx index a45090ee43b3..5c90d6eab859 100644 --- a/shared/chat/inbox/row/teams-divider.tsx +++ b/shared/chat/inbox/row/teams-divider.tsx @@ -4,11 +4,12 @@ import * as Kb from '@/common-adapters' import * as T from '@/constants/types' import * as React from 'react' import * as RowSizes from './sizes' +import type {ChatInboxRowItem} from '../rowitem' type Props = { hiddenCountDelta?: number smallTeamsExpanded: boolean - rows: Array + rows: Array showButton: boolean toggle: () => void style?: Kb.Styles.StylesCrossPlatform diff --git a/shared/constants/types/chat2/rowitem.tsx b/shared/chat/inbox/rowitem.tsx similarity index 100% rename from shared/constants/types/chat2/rowitem.tsx rename to shared/chat/inbox/rowitem.tsx diff --git a/shared/constants/init/shared.tsx b/shared/constants/init/shared.tsx index 07306304d8bc..0f06782d9388 100644 --- a/shared/constants/init/shared.tsx +++ b/shared/constants/init/shared.tsx @@ -5,6 +5,7 @@ import * as T from '../types' import {ignorePromise} from '../utils' import type * as UseArchiveStateType from '@/stores/archive' import type * as UseAutoResetStateType from '@/stores/autoreset' +import {useAutoResetState} from '@/stores/autoreset' import type * as UseDevicesStateType from '@/stores/devices' import {useAvatarState} from '@/common-adapters/avatar/store' import type * as UseBotsStateType from '@/stores/bots' @@ -150,6 +151,56 @@ export const initTeamBuildingCallbacks = () => { } } +export const initAutoResetCallbacks = () => { + const currentState = useAutoResetState.getState() + useAutoResetState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + onGetRecoverPasswordUsername: () => { + return storeRegistry.getState('recover-password').username + }, + onStartProvision: (username: string, fromReset: boolean) => { + storeRegistry.getState('provision').dispatch.startProvision(username, fromReset) + }, + }, + }, + }) +} + +export const initChat2Callbacks = () => { + const currentState = useChatState.getState() + useChatState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + onChatMetasReceived: (metas: ReadonlyArray) => { + storeRegistry.getState('chat').dispatch.metasReceived(metas) + }, + onGetDaemonState: () => { + const daemonState = storeRegistry.getState('daemon') + return {dispatch: daemonState.dispatch, handshakeVersion: daemonState.handshakeVersion} + }, + onGetTeamsTeamIDToMembers: (teamID: T.Teams.TeamID) => { + return storeRegistry.getState('teams').teamIDToMembers.get(teamID) + }, + onGetUsersInfoMap: () => { + return storeRegistry.getState('users').infoMap + }, + onTeamsGetMembers: (teamID: T.Teams.TeamID) => { + storeRegistry.getState('teams').dispatch.getMembers(teamID) + }, + onTeamsUpdateTeamRetentionPolicy: (metas: ReadonlyArray) => { + storeRegistry.getState('teams').dispatch.updateTeamRetentionPolicy(metas) + }, + onUsersUpdates: (updates: ReadonlyArray<{name: string; info: Partial}>) => { + storeRegistry.getState('users').dispatch.updates(updates) + }, + }, + }, + }) +} + export const initSharedSubscriptions = () => { useConfigState.subscribe((s, old) => { if (s.loadOnStartPhase !== old.loadOnStartPhase) { @@ -335,6 +386,8 @@ export const initSharedSubscriptions = () => { } }) + initAutoResetCallbacks() + initChat2Callbacks() initTeamBuildingCallbacks() } diff --git a/shared/constants/types/chat2/index.tsx b/shared/constants/types/chat2/index.tsx index 212ae677e11b..9742dd2548ca 100644 --- a/shared/constants/types/chat2/index.tsx +++ b/shared/constants/types/chat2/index.tsx @@ -5,11 +5,6 @@ import * as _Message from './message' import type * as Meta from './meta' import {uint8ArrayToHex, hexToUint8Array} from 'uint8array-extras' -export type PaymentConfirmInfo = { - error?: RPCTypes.Status - summary?: T.RPCChat.UIChatPaymentSummary -} - // Static config data we use for various things export type StaticConfig = { deletableByDeleteHistory: Set<_Message.MessageType> @@ -86,11 +81,6 @@ export type AttachmentViewInfo = { last: boolean } -export type AttachmentFullscreenSelection = { - autoPlay: boolean - message: _Message.Message -} - export type CommandStatusInfo = { displayText: string displayType: T.RPCChat.UICommandStatusDisplayTyp @@ -208,4 +198,3 @@ export const outboxIDToRpcOutboxID = (outboxID: _Message.OutboxID): T.RPCChat.Ou export * from './message' export * from './common' export type * from './meta' -export type * from './rowitem' diff --git a/shared/constants/types/chat2/message.tsx b/shared/constants/types/chat2/message.tsx index f7b7d1332f81..16a90713c8bb 100644 --- a/shared/constants/types/chat2/message.tsx +++ b/shared/constants/types/chat2/message.tsx @@ -51,11 +51,6 @@ export const outboxIDToString = (o: OutboxID): string => o export type MentionsAt = ReadonlySet export type MentionsChannel = 'none' | 'all' | 'here' -export interface MessageExplodeDescription { - text: string - seconds: number -} - export interface PathAndOutboxID { path: string outboxID?: T.RPCChat.OutboxID diff --git a/shared/constants/types/config.tsx b/shared/constants/types/config.tsx index fdebccf3474d..837ec64ebb5e 100644 --- a/shared/constants/types/config.tsx +++ b/shared/constants/types/config.tsx @@ -1,5 +1,3 @@ -import type * as NetInfo from '@react-native-community/netinfo' - export type OutOfDate = { critical: boolean message: string @@ -12,5 +10,3 @@ export type ConfiguredAccount = { hasStoredSecret: boolean username: string } -// 'notavailable' is the desktop default -export type ConnectionType = NetInfo.NetInfoStateType | 'notavailable' diff --git a/shared/constants/types/crypto.tsx b/shared/constants/types/crypto.tsx index db2f4c451ffb..ad568add5e73 100644 --- a/shared/constants/types/crypto.tsx +++ b/shared/constants/types/crypto.tsx @@ -1,4 +1,2 @@ -export type TextType = 'cipher' | 'plain' export type Operations = 'encrypt' | 'decrypt' | 'sign' | 'verify' export type InputTypes = 'text' | 'file' -export type OutputType = 'text' | 'file' diff --git a/shared/constants/types/git.tsx b/shared/constants/types/git.tsx index 3a0e54f885d1..c960905a7cdf 100644 --- a/shared/constants/types/git.tsx +++ b/shared/constants/types/git.tsx @@ -1,4 +1,3 @@ -import type * as T from '@/constants/types' export type GitInfo = { canDelete: boolean channelName?: string @@ -12,9 +11,3 @@ export type GitInfo = { teamname?: string url: string } - -export type State = T.Immutable<{ - readonly error?: Error - readonly idToInfo: Map - readonly isNew?: Set -}> diff --git a/shared/constants/types/push.tsx b/shared/constants/types/push.tsx index 8b35307b1543..ea0e33b9a4cc 100644 --- a/shared/constants/types/push.tsx +++ b/shared/constants/types/push.tsx @@ -1,8 +1,6 @@ import type * as ChatTypes from './chat2' import type * as RPCChatTypes from './rpc-chat-gen' -export type TokenType = 'apple' | 'appledev' | 'androidplay' - export type PushNotification = | { badges: number diff --git a/shared/constants/types/wallets.tsx b/shared/constants/types/wallets.tsx index 0be9a9ab413d..4c4b5488b782 100644 --- a/shared/constants/types/wallets.tsx +++ b/shared/constants/types/wallets.tsx @@ -1,10 +1,5 @@ import type * as StellarRPCTypes from './rpc-stellar-gen' -export type Reserve = { - amount: string - description: string // e.g. 'account' or 'KEYZ/keybase.io trust line' -} - export type AccountID = string export const noAccountID = 'NOACCOUNTID' export type PaymentID = StellarRPCTypes.PaymentID diff --git a/shared/stores/autoreset.tsx b/shared/stores/autoreset.tsx index ebb8f4d61f74..1120b55e5b04 100644 --- a/shared/stores/autoreset.tsx +++ b/shared/stores/autoreset.tsx @@ -6,7 +6,6 @@ import * as EngineGen from '@/actions/engine-gen-gen' import logger from '@/logger' import {RPCError} from '@/util/errors' import {navigateAppend, navUpToScreen} from '@/constants/router2' -import {storeRegistry} from '@/stores/store-registry' type Store = T.Immutable<{ active: boolean @@ -33,6 +32,10 @@ const initialStore: Store = { export interface State extends Store { dispatch: { cancelReset: () => void + dynamic: { + onGetRecoverPasswordUsername: () => string + onStartProvision: (username: string, fromReset: boolean) => void + } onEngineIncomingImpl: (action: EngineGen.Actions) => void resetState: 'default' resetAccount: (password?: string) => void @@ -82,6 +85,14 @@ export const useAutoResetState = Z.createZustand((set, get) => { } ignorePromise(f()) }, + dynamic: { + onGetRecoverPasswordUsername: () => { + throw new Error('onGetRecoverPasswordUsername not properly initialized') + }, + onStartProvision: (_username: string, _fromReset: boolean) => { + throw new Error('onStartProvision not properly initialized') + }, + }, onEngineIncomingImpl: action => { switch (action.type) { case EngineGen.keybase1NotifyBadgesBadgeState: { @@ -118,7 +129,7 @@ export const useAutoResetState = Z.createZustand((set, get) => { set(s => { s.error = '' }) - storeRegistry.getState('provision').dispatch.startProvision(get().username, true) + get().dispatch.dynamic.onStartProvision(get().username, true) } else { navUpToScreen('login') } @@ -164,7 +175,7 @@ export const useAutoResetState = Z.createZustand((set, get) => { }, resetState: 'default', startAccountReset: (skipPassword, _username) => { - const username = _username || storeRegistry.getState('recover-password').username + const username = _username || get().dispatch.dynamic.onGetRecoverPasswordUsername() || '' set(s => { s.skipPassword = skipPassword s.error = '' diff --git a/shared/stores/chat2.tsx b/shared/stores/chat2.tsx index 68884adec3fd..a8d5f2ea3791 100644 --- a/shared/stores/chat2.tsx +++ b/shared/stores/chat2.tsx @@ -1,27 +1,35 @@ -import * as T from '@/constants/types' -import {ignorePromise, timeoutPromise, type ViewPropsToPageProps} from '@/constants/utils' -import * as Tabs from '@/constants/tabs' +import * as Common from '@/constants/chat2/common' import * as EngineGen from '@/actions/engine-gen-gen' -import type * as ConfigConstants from '@/stores/config' import * as Message from '@/constants/chat2/message' -import * as Router2 from '@/stores/router2' -import * as TeamConstants from '@/constants/teams' -import logger from '@/logger' -import {RPCError} from '@/util/errors' import * as Meta from '@/constants/chat2/meta' -import {isMobile, isPhone} from '@/constants/platform' +import * as S from '@/constants/strings' +import * as T from '@/constants/types' +import * as Tabs from '@/constants/tabs' +import * as TeamConstants from '@/constants/teams' import * as Z from '@/util/zustand' -import * as Common from '@/constants/chat2/common' -import {clearChatStores, chatStores} from '@/stores/convostate' -import {uint8ArrayToString} from 'uint8array-extras' import isEqual from 'lodash/isEqual' +import logger from '@/logger' +import type * as Router2 from '@/stores/router2' +import {type ChatProviderProps, ProviderScreen} from '@/stores/convostate' +import type {GetOptionsRet} from '@/constants/types/router2' +import {RPCError} from '@/util/errors' import {bodyToJSON} from '@/constants/rpc-utils' -import {navigateAppend, navUpToScreen, switchTab} from '@/constants/router2' +import {clearChatStores, chatStores} from '@/stores/convostate' +import {ignorePromise, timeoutPromise, type ViewPropsToPageProps} from '@/constants/utils' +import {isMobile, isPhone} from '@/constants/platform' +import { + navigateAppend, + navUpToScreen, + switchTab, + getModalStack, + getTab, + getVisibleScreen, +} from '@/constants/router2' import {storeRegistry} from '@/stores/store-registry' +import {uint8ArrayToString} from 'uint8array-extras' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import {useWaitingState} from '@/stores/waiting' -import * as S from '@/constants/strings' const defaultTopReacjis = [ {name: ':+1:'}, @@ -105,7 +113,8 @@ export const getBotsAndParticipants = ( ) => { const isAdhocTeam = meta.teamType === 'adhoc' const teamMembers = - storeRegistry.getState('teams').teamIDToMembers.get(meta.teamID) ?? new Map() + useChatState.getState().dispatch.dynamic.onGetTeamsTeamIDToMembers(meta.teamID) ?? + new Map() let bots: Array = [] if (isAdhocTeam) { bots = participantInfo.all.filter(p => !participantInfo.name.includes(p)) @@ -281,6 +290,17 @@ export interface State extends Store { dispatch: { badgesUpdated: (badgeState?: T.RPCGen.BadgeState) => void clearMetas: () => void + dynamic: { + onChatMetasReceived: (metas: ReadonlyArray) => void + onGetDaemonState: () => {handshakeVersion: number; dispatch: any} + onGetTeamsTeamIDToMembers: ( + teamID: T.Teams.TeamID + ) => ReadonlyMap | undefined + onGetUsersInfoMap: () => ReadonlyMap + onTeamsGetMembers: (teamID: T.Teams.TeamID) => void + onTeamsUpdateTeamRetentionPolicy: (metas: ReadonlyArray) => void + onUsersUpdates: (updates: ReadonlyArray<{name: string; info: Partial}>) => void + } conversationErrored: ( allowedUsers: ReadonlyArray, disallowedUsers: ReadonlyArray, @@ -349,17 +369,22 @@ export interface State extends Store { setInboxNumSmallRows: (rows: number, ignoreWrite?: boolean) => void toggleInboxSearch: (enabled: boolean) => void toggleSmallTeamsExpanded: () => void - unboxRows: (ids: Array, force?: boolean) => void + unboxRows: (ids: ReadonlyArray, force?: boolean) => void updateCoinFlipStatus: (statuses: ReadonlyArray) => void updateInboxLayout: (layout: string) => void updateLastCoord: (coord: T.Chat.Coordinate) => void updateUserReacjis: (userReacjis: T.RPCGen.UserReacjis) => void - updatedGregor: (items: ConfigConstants.State['gregorPushState']) => void + updatedGregor: ( + items: ReadonlyArray<{md: T.RPCGen.Gregor1.Metadata; item: T.RPCGen.Gregor1.Item}> + ) => void updateInfoPanel: (show: boolean, tab: 'settings' | 'members' | 'attachments' | 'bots' | undefined) => void } getBackCount: (conversationIDKey: T.Chat.ConversationIDKey) => number - getBadgeHiddenCount: (ids: Set) => {badgeCount: number; hiddenCount: number} - getUnreadIndicies: (ids: Array) => Map + getBadgeHiddenCount: (ids: ReadonlySet) => { + badgeCount: number + hiddenCount: number + } + getUnreadIndicies: (ids: ReadonlyArray) => Map } // Only get the untrusted conversations out @@ -468,6 +493,29 @@ export const useChatState = Z.createZustand((set, get) => { } ignorePromise(f()) }, + dynamic: { + onChatMetasReceived: (_metas: ReadonlyArray) => { + throw new Error('onChatMetasReceived not properly initialized') + }, + onGetDaemonState: () => { + throw new Error('onGetDaemonState not properly initialized') + }, + onGetTeamsTeamIDToMembers: (_teamID: T.Teams.TeamID) => { + throw new Error('onGetTeamsTeamIDToMembers not properly initialized') + }, + onGetUsersInfoMap: () => { + throw new Error('onGetUsersInfoMap not properly initialized') + }, + onTeamsGetMembers: (_teamID: T.Teams.TeamID) => { + throw new Error('onTeamsGetMembers not properly initialized') + }, + onTeamsUpdateTeamRetentionPolicy: (_metas: ReadonlyArray) => { + throw new Error('onTeamsUpdateTeamRetentionPolicy not properly initialized') + }, + onUsersUpdates: (_updates: ReadonlyArray<{name: string; info: Partial}>) => { + throw new Error('onUsersUpdates not properly initialized') + }, + }, ensureWidgetMetas: () => { const {inboxLayout} = get() if (!inboxLayout?.widgetList) { @@ -801,7 +849,7 @@ export const useChatState = Z.createZustand((set, get) => { if (get().staticConfig) { return } - const {handshakeVersion, dispatch} = storeRegistry.getState('daemon') + const {handshakeVersion, dispatch} = get().dispatch.dynamic.onGetDaemonState() const f = async () => { const name = 'chat.loadStatic' dispatch.wait(name, handshakeVersion, true) @@ -940,8 +988,8 @@ export const useChatState = Z.createZustand((set, get) => { const {isMetaGood, meta} = storeRegistry.getConvoState(selectedConversation) if (isMetaGood()) { const {teamID} = meta - if (!storeRegistry.getState('teams').teamIDToMembers.get(teamID) && meta.teamname) { - storeRegistry.getState('teams').dispatch.getMembers(teamID) + if (!get().dispatch.dynamic.onGetTeamsTeamIDToMembers(teamID) && meta.teamname) { + get().dispatch.dynamic.onTeamsGetMembers(teamID) } } }, @@ -1114,7 +1162,7 @@ export const useChatState = Z.createZustand((set, get) => { const usernames = update.CanonicalName.split(',') const broken = (update.breaks.breaks || []).map(b => b.user.username) const updates = usernames.map(name => ({info: {broken: broken.includes(name)}, name})) - storeRegistry.getState('users').dispatch.updates(updates) + get().dispatch.dynamic.onUsersUpdates(updates) break } case EngineGen.chat1ChatUiChatInboxUnverified: @@ -1301,7 +1349,7 @@ export const useChatState = Z.createZustand((set, get) => { cs.dispatch.setMeta(meta) } }) - storeRegistry.getState('teams').dispatch.updateTeamRetentionPolicy(metas) + get().dispatch.dynamic.onTeamsUpdateTeamRetentionPolicy(metas) } // this is a more serious problem, but we don't need to bug the user about it logger.error( @@ -1335,7 +1383,7 @@ export const useChatState = Z.createZustand((set, get) => { }, onGetInboxConvsUnboxed: (action: EngineGen.Chat1ChatUiChatInboxConversationPayload) => { // TODO not reactive - const {infoMap} = storeRegistry.getState('users') + const infoMap = get().dispatch.dynamic.onGetUsersInfoMap() const {convs} = action.payload.params const inboxUIItems = JSON.parse(convs) as Array const metas: Array = [] @@ -1363,7 +1411,7 @@ export const useChatState = Z.createZustand((set, get) => { }) }) if (added) { - storeRegistry.getState('users').dispatch.updates( + get().dispatch.dynamic.onUsersUpdates( Object.keys(usernameToFullname).map(name => ({ info: {fullname: usernameToFullname[name]}, name, @@ -1398,7 +1446,7 @@ export const useChatState = Z.createZustand((set, get) => { return map }, {}) - storeRegistry.getState('users').dispatch.updates( + get().dispatch.dynamic.onUsersUpdates( Object.keys(usernameToFullname).map(name => ({ info: {fullname: usernameToFullname[name]}, name, @@ -1411,14 +1459,14 @@ export const useChatState = Z.createZustand((set, get) => { }, onRouteChanged: (prev, next) => { const maybeChangeChatSelection = () => { - const wasModal = prev && Router2.getModalStack(prev).length > 0 - const isModal = next && Router2.getModalStack(next).length > 0 + const wasModal = prev && getModalStack(prev).length > 0 + const isModal = next && getModalStack(next).length > 0 // ignore if changes involve a modal if (wasModal || isModal) { return } - const p = Router2.getVisibleScreen(prev) - const n = Router2.getVisibleScreen(next) + const p = getVisibleScreen(prev) + const n = getVisibleScreen(next) const wasChat = p?.name === Common.threadRouteName const isChat = n?.name === Common.threadRouteName // nothing to do with chat @@ -1471,8 +1519,8 @@ export const useChatState = Z.createZustand((set, get) => { } const maybeChatTabSelected = () => { - if (Router2.getTab(prev) !== Tabs.chatTab && Router2.getTab(next) === Tabs.chatTab) { - const n = Router2.getVisibleScreen(next) + if (getTab(prev) !== Tabs.chatTab && getTab(next) === Tabs.chatTab) { + const n = getVisibleScreen(next) const nParams = n?.params as undefined | {conversationIDKey?: T.Chat.ConversationIDKey} const isID = nParams?.conversationIDKey isID && storeRegistry.getConvoState(isID).dispatch.tabSelected() @@ -1585,7 +1633,7 @@ export const useChatState = Z.createZustand((set, get) => { }) const meta = Meta.inboxUIItemToConversationMeta(results2.conv) if (meta) { - storeRegistry.getState('chat').dispatch.metasReceived([meta]) + get().dispatch.dynamic.onChatMetasReceived([meta]) } storeRegistry @@ -1966,9 +2014,6 @@ export const useChatState = Z.createZustand((set, get) => { } }) -import {type ChatProviderProps, ProviderScreen} from '@/stores/convostate' -import type {GetOptionsRet} from '@/constants/types/router2' - export function makeChatScreen>( Component: COM, options?: { diff --git a/shared/stores/config.tsx b/shared/stores/config.tsx index bed141114cad..1c4e6112c8ab 100644 --- a/shared/stores/config.tsx +++ b/shared/stores/config.tsx @@ -1,3 +1,4 @@ +import type * as NetInfo from '@react-native-community/netinfo' import * as T from '@/constants/types' import {ignorePromise, timeoutPromise} from '@/constants/utils' import {waitingKeyConfigLogin} from '@/constants/strings' @@ -14,6 +15,8 @@ import {type CommonResponseHandler} from '@/engine/types' import {invalidPasswordErrorString} from '@/constants/config' import {navigateAppend} from '@/constants/router2' +export type ConnectionType = NetInfo.NetInfoStateType | 'notavailable' + type Store = T.Immutable<{ active: boolean allowAnimatedEmojis: boolean @@ -47,7 +50,7 @@ type Store = T.Immutable<{ | 'reloggedIn' | 'startupOrReloginButNotInARush' mobileAppState: 'active' | 'background' | 'inactive' | 'unknown' - networkStatus?: {online: boolean; type: T.Config.ConnectionType; isInit?: boolean} + networkStatus?: {online: boolean; type: ConnectionType; isInit?: boolean} notifySound: boolean openAtLogin: boolean outOfDate: T.Config.OutOfDate @@ -173,7 +176,7 @@ export interface State extends Store { logoutAndTryToLogInAs: (username: string) => void onEngineConnected: () => void onEngineIncoming: (action: EngineGen.Actions) => void - osNetworkStatusChanged: (online: boolean, type: T.Config.ConnectionType, isInit?: boolean) => void + osNetworkStatusChanged: (online: boolean, type: ConnectionType, isInit?: boolean) => void openUnlockFolders: (devices: ReadonlyArray) => void powerMonitorEvent: (event: string) => void resetState: (isDebug?: boolean) => void @@ -559,7 +562,7 @@ export const useConfigState = Z.createZustand((set, get) => { })) }) }, - osNetworkStatusChanged: (online: boolean, type: T.Config.ConnectionType, isInit?: boolean) => { + osNetworkStatusChanged: (online: boolean, type: ConnectionType, isInit?: boolean) => { const old = get().networkStatus set(s => { if (!s.networkStatus) { diff --git a/shared/stores/git.tsx b/shared/stores/git.tsx index 3b09ac438bd7..6e7854c3ab9c 100644 --- a/shared/stores/git.tsx +++ b/shared/stores/git.tsx @@ -8,6 +8,12 @@ import debounce from 'lodash/debounce' import {navigateAppend} from '@/constants/router2' import {useConfigState} from '@/stores/config' +type Store = T.Immutable<{ + readonly error?: Error + readonly idToInfo: Map + readonly isNew?: Set +}> + const parseRepos = (results: ReadonlyArray) => { const errors: Array = [] const repos = new Map() @@ -57,13 +63,13 @@ const parseRepoError = (result: T.RPCGen.GitRepoResult): Error => { return new Error(`Git repo error: ${errStr}`) } -const initialStore: T.Git.State = { +const initialStore: Store = { error: undefined, idToInfo: new Map(), isNew: new Set(), } -export interface State extends T.Git.State { +export interface State extends Store { dispatch: { setError: (err?: Error) => void clearBadges: () => void diff --git a/shared/stores/teams.tsx b/shared/stores/teams.tsx index dd71b509190d..38a35ecbb556 100644 --- a/shared/stores/teams.tsx +++ b/shared/stores/teams.tsx @@ -1046,7 +1046,7 @@ export interface State extends Store { sendChatNotification: boolean, crop?: T.RPCGen.ImageCropRect ) => void - updateTeamRetentionPolicy: (metas: Array) => void + updateTeamRetentionPolicy: (metas: ReadonlyArray) => void } } From 7ac34f2a45c4dcf4969fb0df56941d35ec3d9139 Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Fri, 16 Jan 2026 08:41:26 -0500 Subject: [PATCH 17/20] WIP: shift 18 (#28811) * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/constants/deeplinks.tsx | 22 +- shared/constants/init/index.native.tsx | 2 +- .../init}/push-listener.native.tsx | 14 +- shared/constants/init/shared.tsx | 319 ++++++++++++++++-- .../router-v2/left-tab-navigator.desktop.tsx | 5 +- shared/stores/chat2.tsx | 6 +- shared/stores/convostate.tsx | 70 ++-- shared/stores/fs.tsx | 17 +- shared/stores/notifications.tsx | 11 +- shared/stores/profile.tsx | 42 ++- shared/stores/push.d.ts | 9 + shared/stores/push.desktop.tsx | 7 + shared/stores/push.native.tsx | 20 +- shared/stores/recover-password.tsx | 14 +- shared/stores/router2.tsx | 94 +----- shared/stores/signup.tsx | 19 +- shared/stores/store-registry.tsx | 72 ---- shared/stores/teams.tsx | 33 +- shared/stores/tracker2.tsx | 30 +- 19 files changed, 523 insertions(+), 283 deletions(-) rename shared/{stores => constants/init}/push-listener.native.tsx (95%) diff --git a/shared/constants/deeplinks.tsx b/shared/constants/deeplinks.tsx index dbcc975c6b42..1b207eff3219 100644 --- a/shared/constants/deeplinks.tsx +++ b/shared/constants/deeplinks.tsx @@ -4,6 +4,10 @@ import logger from '@/logger' import * as T from '@/constants/types' import {navigateAppend, switchTab} from './router2' import {storeRegistry} from '@/stores/store-registry' +import {useChatState} from '@/stores/chat2' +import {useProfileState} from '@/stores/profile' +import {useSettingsPhoneState} from '@/stores/settings-phone' +import {useTeamsState} from '@/stores/teams' const prefix = 'keybase://' export const linkFromConvAndMessage = (conv: string, messageID: number) => @@ -34,7 +38,7 @@ const validTeamnamePart = (s: string): boolean => { const validTeamname = (s: string) => s.split('.').every(validTeamnamePart) const handleShowUserProfileLink = (username: string) => { switchTab(Tabs.peopleTab) - storeRegistry.getState('profile').dispatch.showUserProfile(username) + useProfileState.getState().dispatch.showUserProfile(username) } const isKeybaseIoUrl = (url: URL) => { @@ -94,8 +98,8 @@ const urlToTeamDeepLink = (url: URL) => { } const handleTeamPageLink = (teamname: string, action?: TeamPageAction) => { - storeRegistry - .getState('teams') + useTeamsState + .getState() .dispatch.showTeamByName( teamname, action === 'manage_settings' ? 'settings' : undefined, @@ -113,7 +117,7 @@ export const handleAppLink = (link: string) => { const url = new URL(link) const username = urlToUsername(url) if (username === 'phone-app') { - const phoneState = storeRegistry.getState('settings-phone') + const phoneState = useSettingsPhoneState.getState() const phones = (phoneState as {phones?: Map}).phones if (!phones || phones.size > 0) { return @@ -141,8 +145,8 @@ export const handleKeybaseLink = (link: string) => { switch (parts[0]) { case 'profile': if (parts[1] === 'new-proof' && (parts.length === 3 || parts.length === 4)) { - parts.length === 4 && parts[3] && storeRegistry.getState('profile').dispatch.showUserProfile(parts[3]) - storeRegistry.getState('profile').dispatch.addProof(parts[2]!, 'appLink') + parts.length === 4 && parts[3] && useProfileState.getState().dispatch.showUserProfile(parts[3]) + useProfileState.getState().dispatch.addProof(parts[2]!, 'appLink') return } else if (parts[1] === 'show' && parts.length === 3) { // Username is basically a team name part, we can use the same logic to @@ -191,7 +195,7 @@ export const handleKeybaseLink = (link: string) => { } const highlightMessageID = T.Chat.numberToMessageID(_highlightMessageID) - const {previewConversation} = storeRegistry.getState('chat').dispatch + const {previewConversation} = useChatState.getState().dispatch previewConversation({ channelname, highlightMessageID, @@ -205,7 +209,7 @@ export const handleKeybaseLink = (link: string) => { logger.warn(`invalid chat message id: ${highlightMessageID}`) return } - const {previewConversation} = storeRegistry.getState('chat').dispatch + const {previewConversation} = useChatState.getState().dispatch previewConversation({ highlightMessageID: T.Chat.numberToMessageID(highlightMessageID), participants: parts[1]!.split(','), @@ -233,7 +237,7 @@ export const handleKeybaseLink = (link: string) => { }, 500) return case 'team-invite-link': - storeRegistry.getState('teams').dispatch.openInviteLink(parts[1] ?? '', parts[2] || '') + useTeamsState.getState().dispatch.openInviteLink(parts[1] ?? '', parts[2] || '') return case 'settingsPushPrompt': navigateAppend('settingsPushPrompt') diff --git a/shared/constants/init/index.native.tsx b/shared/constants/init/index.native.tsx index 79986552ab64..9504f03afe6c 100644 --- a/shared/constants/init/index.native.tsx +++ b/shared/constants/init/index.native.tsx @@ -33,7 +33,7 @@ import { guiConfig, shareListenersRegistered, } from 'react-native-kb' -import {initPushListener, getStartupDetailsFromInitialPush} from '@/stores/push-listener.native' +import {initPushListener, getStartupDetailsFromInitialPush} from './push-listener.native' import {initSharedSubscriptions, _onEngineIncoming} from './shared' import type {ImageInfo} from '@/util/expo-image-picker.native' import {noConversationIDKey} from '../types/chat2/common' diff --git a/shared/stores/push-listener.native.tsx b/shared/constants/init/push-listener.native.tsx similarity index 95% rename from shared/stores/push-listener.native.tsx rename to shared/constants/init/push-listener.native.tsx index e51c943a2245..13df6ba0e0b5 100644 --- a/shared/stores/push-listener.native.tsx +++ b/shared/constants/init/push-listener.native.tsx @@ -9,9 +9,9 @@ import { getInitialNotification, removeAllPendingNotificationRequests, } from 'react-native-kb' -import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useLogoutState} from '@/stores/logout' +import {usePushState} from '@/stores/push' type DataCommon = { userInteraction: boolean @@ -171,8 +171,8 @@ export const initPushListener = () => { return } logger.debug(`[PushCheck] checking on foreground`) - storeRegistry - .getState('push') + usePushState + .getState() .dispatch.checkPermissions() .then(() => {}) .catch(() => {}) @@ -181,7 +181,7 @@ export const initPushListener = () => { // Token handling useLogoutState.subscribe((s, old) => { if (s.version === old.version) return - storeRegistry.getState('push').dispatch.deleteToken(s.version) + usePushState.getState().dispatch.deleteToken(s.version) }) let lastCount = -1 @@ -197,7 +197,7 @@ export const initPushListener = () => { lastCount = count }) - storeRegistry.getState('push').dispatch.initialPermissionsCheck() + usePushState.getState().dispatch.initialPermissionsCheck() const listenNative = async () => { const RNEmitter = getNativeEmitter() @@ -211,7 +211,7 @@ export const initPushListener = () => { logger.warn('[onNotification]: normalized notification is null/undefined') return } - storeRegistry.getState('push').dispatch.handlePush(notification) + usePushState.getState().dispatch.handlePush(notification) } try { @@ -242,7 +242,7 @@ export const initPushListener = () => { try { const pushToken = await getRegistrationToken() logger.debug('[PushToken] received new token: ', pushToken) - storeRegistry.getState('push').dispatch.setPushToken(pushToken) + usePushState.getState().dispatch.setPushToken(pushToken) } catch (e) { logger.warn('[PushToken] failed to get token (will retry later): ', e) // Token will be retrieved later when permissions are checked diff --git a/shared/constants/init/shared.tsx b/shared/constants/init/shared.tsx index 0f06782d9388..747feabf1c07 100644 --- a/shared/constants/init/shared.tsx +++ b/shared/constants/init/shared.tsx @@ -1,43 +1,55 @@ import * as EngineGen from '@/actions/engine-gen-gen' -import logger from '@/logger' -import {isMobile, serverConfigFileName} from '../platform' import * as T from '../types' -import {ignorePromise} from '../utils' +import isEqual from 'lodash/isEqual' +import logger from '@/logger' +import * as Tabs from '@/constants/tabs' import type * as UseArchiveStateType from '@/stores/archive' import type * as UseAutoResetStateType from '@/stores/autoreset' -import {useAutoResetState} from '@/stores/autoreset' -import type * as UseDevicesStateType from '@/stores/devices' -import {useAvatarState} from '@/common-adapters/avatar/store' import type * as UseBotsStateType from '@/stores/bots' -import {useChatState} from '@/stores/chat2' -import {getSelectedConversation} from '@/constants/chat2/common' import type * as UseChatStateType from '@/stores/chat2' -import {useConfigState} from '@/stores/config' -import {useCurrentUserState} from '@/stores/current-user' -import {useDaemonState} from '@/stores/daemon' -import {useDarkModeState} from '@/stores/darkmode' -import {handleKeybaseLink} from '@/constants/deeplinks' -import {useFollowerState} from '@/stores/followers' -import isEqual from 'lodash/isEqual' +import type * as UseDevicesStateType from '@/stores/devices' import type * as UseFSStateType from '@/stores/fs' import type * as UseGitStateType from '@/stores/git' import type * as UseNotificationsStateType from '@/stores/notifications' import type * as UsePeopleStateType from '@/stores/people' import type * as UsePinentryStateType from '@/stores/pinentry' -import {useProvisionState} from '@/stores/provision' -import {storeRegistry} from '@/stores/store-registry' -import {useSettingsContactsState} from '@/stores/settings-contacts' -import {createTBStore} from '@/stores/team-building' -import {useCryptoState} from '@/stores/crypto' -import {useProfileState} from '@/stores/profile' -import {useUsersState} from '@/stores/users' +import type * as UseSettingsPasswordStateType from '@/stores/settings-password' import type * as UseSignupStateType from '@/stores/signup' import type * as UseTeamsStateType from '@/stores/teams' -import {useTeamsState} from '@/stores/teams' import type * as UseTracker2StateType from '@/stores/tracker2' import type * as UseUnlockFoldersStateType from '@/stores/unlock-folders' import type * as UseUsersStateType from '@/stores/users' +import {createTBStore} from '@/stores/team-building' +import {getSelectedConversation} from '@/constants/chat2/common' +import {handleKeybaseLink} from '@/constants/deeplinks' +import {ignorePromise} from '../utils' +import {isMobile, serverConfigFileName} from '../platform' +import {storeRegistry} from '@/stores/store-registry' +import {useAutoResetState} from '@/stores/autoreset' +import {useAvatarState} from '@/common-adapters/avatar/store' +import {useChatState} from '@/stores/chat2' +import {useConfigState} from '@/stores/config' +import {useCryptoState} from '@/stores/crypto' +import {useCurrentUserState} from '@/stores/current-user' +import {useDaemonState} from '@/stores/daemon' +import {useDarkModeState} from '@/stores/darkmode' +import {useFSState} from '@/stores/fs' +import {useFollowerState} from '@/stores/followers' +import {useNotifState} from '@/stores/notifications' +import {useProfileState} from '@/stores/profile' +import {useProvisionState} from '@/stores/provision' +import {usePushState} from '@/stores/push' +import {useSettingsContactsState} from '@/stores/settings-contacts' +import {useSettingsEmailState} from '@/stores/settings-email' +import {useSignupState} from '@/stores/signup' +import {useState as useRecoverPasswordState} from '@/stores/recover-password' +import {useTeamsState} from '@/stores/teams' +import {useTrackerState} from '@/stores/tracker2' +import {useUsersState} from '@/stores/users' import {useWhatsNewState} from '@/stores/whats-new' +import {useRouterState} from '@/stores/router2' +import * as Util from '@/constants/router2' +import {setOtherStores} from '@/stores/convostate' let _emitStartupOnLoadDaemonConnectedOnce = false let _devicesLoaded = false @@ -174,9 +186,6 @@ export const initChat2Callbacks = () => { dispatch: { ...currentState.dispatch, dynamic: { - onChatMetasReceived: (metas: ReadonlyArray) => { - storeRegistry.getState('chat').dispatch.metasReceived(metas) - }, onGetDaemonState: () => { const daemonState = storeRegistry.getState('daemon') return {dispatch: daemonState.dispatch, handshakeVersion: daemonState.handshakeVersion} @@ -201,7 +210,175 @@ export const initChat2Callbacks = () => { }) } +export const initTeamsCallbacks = () => { + const currentState = useTeamsState.getState() + useTeamsState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + ...currentState.dispatch.dynamic, + onChatNavigateToInbox: (allowSwitchTab?: boolean) => { + storeRegistry.getState('chat').dispatch.navigateToInbox(allowSwitchTab) + }, + onChatPreviewConversation: ( + p: Parameters['dispatch']['previewConversation']>[0] + ) => { + storeRegistry.getState('chat').dispatch.previewConversation(p) + }, + onUsersUpdates: (updates: ReadonlyArray<{name: string; info: Partial}>) => { + storeRegistry.getState('users').dispatch.updates(updates) + }, + }, + }, + }) +} + +export const initFSCallbacks = () => { + const currentState = useFSState.getState() + useFSState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + ...currentState.dispatch.dynamic, + onBadgeApp: (key: 'kbfsUploading' | 'outOfSpace', on: boolean) => { + useNotifState.getState().dispatch.badgeApp(key, on) + }, + onSetBadgeCounts: (counts: Map) => { + useNotifState.getState().dispatch.setBadgeCounts(counts) + }, + }, + }, + }) +} + +export const initNotificationsCallbacks = () => { + const currentState = useNotifState.getState() + useNotifState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + ...currentState.dispatch.dynamic, + onFavoritesLoad: () => { + useFSState.getState().dispatch.favoritesLoad() + }, + }, + }, + }) +} + +export const initProfileCallbacks = () => { + const currentState = useProfileState.getState() + useProfileState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + ...currentState.dispatch.dynamic, + onTracker2GetDetails: (username: string) => { + return useTrackerState.getState().getDetails(username) + }, + onTracker2Load: ( + params: Parameters['dispatch']['load']>[0] + ) => { + useTrackerState.getState().dispatch.load(params) + }, + onTracker2ShowUser: (username: string, asTracker: boolean, skipNav?: boolean) => { + useTrackerState.getState().dispatch.showUser(username, asTracker, skipNav) + }, + onTracker2UpdateResult: (guiID: string, result: T.Tracker.DetailsState, reason?: string) => { + useTrackerState.getState().dispatch.updateResult(guiID, result, reason) + }, + }, + }, + }) +} + +export const initPushCallbacks = () => { + const currentState = usePushState.getState() + usePushState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + ...currentState.dispatch.dynamic, + onGetDaemonHandshakeState: () => { + return useDaemonState.getState().handshakeState + }, + onNavigateToThread: ( + conversationIDKey: T.Chat.ConversationIDKey, + reason: 'push' | 'extension', + pushBody?: string + ) => { + storeRegistry + .getConvoState(conversationIDKey) + .dispatch.navigateToThread(reason, undefined, pushBody) + }, + onShowUserProfile: (username: string) => { + useProfileState.getState().dispatch.showUserProfile(username) + }, + }, + }, + }) +} + +export const initRecoverPasswordCallbacks = () => { + const currentState = useRecoverPasswordState.getState() + useRecoverPasswordState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + ...currentState.dispatch.dynamic, + onProvisionCancel: (ignoreWarning?: boolean) => { + useProvisionState.getState().dispatch.dynamic.cancel?.(ignoreWarning) + }, + onStartAccountReset: (skipPassword: boolean, username: string) => { + useAutoResetState.getState().dispatch.startAccountReset(skipPassword, username) + }, + }, + }, + }) +} + +export const initSignupCallbacks = () => { + const currentState = useSignupState.getState() + useSignupState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + ...currentState.dispatch.dynamic, + onEditEmail: (p: {email: string; makeSearchable: boolean}) => { + useSettingsEmailState.getState().dispatch.editEmail(p) + }, + onShowPermissionsPrompt: (p: {justSignedUp?: boolean}) => { + usePushState.getState().dispatch.showPermissionsPrompt(p) + }, + }, + }, + }) +} + +export const initTracker2Callbacks = () => { + const currentState = useTrackerState.getState() + useTrackerState.setState({ + dispatch: { + ...currentState.dispatch, + dynamic: { + ...currentState.dispatch.dynamic, + onShowUserProfile: (username: string) => { + useProfileState.getState().dispatch.showUserProfile(username) + }, + onUsersUpdates: (updates: ReadonlyArray<{name: string; info: Partial}>) => { + useUsersState.getState().dispatch.updates(updates) + }, + }, + }, + }) +} + export const initSharedSubscriptions = () => { + setOtherStores( + storeRegistry.getStore('chat'), + storeRegistry.getStore('teams'), + storeRegistry.getStore('users') + ) useConfigState.subscribe((s, old) => { if (s.loadOnStartPhase !== old.loadOnStartPhase) { if (s.loadOnStartPhase === 'startupOrReloginButNotInARush') { @@ -386,9 +563,96 @@ export const initSharedSubscriptions = () => { } }) + useRouterState.subscribe((s, old) => { + const next = s.navState as Util.NavState + const prev = old.navState as Util.NavState + if (prev === next) return + + const namespaces = ['chat2', 'crypto', 'teams', 'people'] as const + const namespaceToRoute = new Map([ + ['chat2', 'chatNewChat'], + ['crypto', 'cryptoTeamBuilder'], + ['teams', 'teamsTeamBuilder'], + ['people', 'peopleTeamBuilder'], + ]) + for (const namespace of namespaces) { + const wasTeamBuilding = namespaceToRoute.get(namespace) === Util.getVisibleScreen(prev)?.name + if (wasTeamBuilding) { + // team building or modal on top of that still + const isTeamBuilding = namespaceToRoute.get(namespace) === Util.getVisibleScreen(next)?.name + if (!isTeamBuilding) { + storeRegistry.getTBStore(namespace).dispatch.cancelTeamBuilding() + } + } + } + + // Clear critical update when we nav away from tab + if ( + prev && + Util.getTab(prev) === Tabs.fsTab && + next && + Util.getTab(next) !== Tabs.fsTab && + storeRegistry.getState('fs').criticalUpdate + ) { + const {dispatch} = storeRegistry.getState('fs') + dispatch.setCriticalUpdate(false) + } + const fsRrouteNames = ['fsRoot', 'barePreview'] + const wasScreen = fsRrouteNames.includes(Util.getVisibleScreen(prev)?.name ?? '') + const isScreen = fsRrouteNames.includes(Util.getVisibleScreen(next)?.name ?? '') + if (wasScreen !== isScreen) { + const {dispatch} = storeRegistry.getState('fs') + if (wasScreen) { + dispatch.userOut() + } else { + dispatch.userIn() + } + } + + // Clear "just signed up email" when you leave the people tab after signup + if ( + prev && + Util.getTab(prev) === Tabs.peopleTab && + next && + Util.getTab(next) !== Tabs.peopleTab && + storeRegistry.getState('signup').justSignedUpEmail + ) { + storeRegistry.getState('signup').dispatch.clearJustSignedUpEmail() + } + + if (prev && Util.getTab(prev) === Tabs.peopleTab && next && Util.getTab(next) !== Tabs.peopleTab) { + storeRegistry.getState('people').dispatch.markViewed() + } + + if (prev && Util.getTab(prev) === Tabs.teamsTab && next && Util.getTab(next) !== Tabs.teamsTab) { + storeRegistry.getState('teams').dispatch.clearNavBadges() + } + + // Clear "check your inbox" in settings when you leave the settings tab + if ( + prev && + Util.getTab(prev) === Tabs.settingsTab && + next && + Util.getTab(next) !== Tabs.settingsTab && + storeRegistry.getState('settings-email').addedEmail + ) { + storeRegistry.getState('settings-email').dispatch.resetAddedEmail() + } + + storeRegistry.getState('chat').dispatch.onRouteChanged(prev, next) + }) + initAutoResetCallbacks() initChat2Callbacks() initTeamBuildingCallbacks() + initTeamsCallbacks() + initFSCallbacks() + initNotificationsCallbacks() + initProfileCallbacks() + initPushCallbacks() + initRecoverPasswordCallbacks() + initSignupCallbacks() + initTracker2Callbacks() } // This is to defer loading stores we don't need immediately. @@ -491,7 +755,8 @@ export const _onEngineIncoming = (action: EngineGen.Actions) => { case EngineGen.keybase1NotifyUsersPasswordChanged: { const randomPW = action.payload.params.state === T.RPCGen.PassphraseState.random - storeRegistry.getState('settings-password').dispatch.notifyUsersPasswordChanged(randomPW) + const {usePWState} = require('@/stores/settings-password') as typeof UseSettingsPasswordStateType + usePWState.getState().dispatch.notifyUsersPasswordChanged(randomPW) } break case EngineGen.keybase1NotifyPhoneNumberPhoneNumbersChanged: { diff --git a/shared/router-v2/left-tab-navigator.desktop.tsx b/shared/router-v2/left-tab-navigator.desktop.tsx index bac3cb3c04a5..a30eceb6a845 100644 --- a/shared/router-v2/left-tab-navigator.desktop.tsx +++ b/shared/router-v2/left-tab-navigator.desktop.tsx @@ -4,7 +4,8 @@ import TabBar from './tab-bar.desktop' import {useNavigationBuilder, TabRouter, createNavigatorFactory} from '@react-navigation/core' import type {TypedNavigator, NavigatorTypeBagBase, StaticConfig} from '@react-navigation/native' import type * as Tabs from '@/constants/tabs' -import * as Router2 from '@/constants/router2' +import {useRouterState} from '@/stores/router2' +import {getModalStack} from '@/constants/router2' type BackBehavior = Parameters[0]['backBehavior'] type Props = Parameters[1] & {backBehavior: BackBehavior} @@ -50,7 +51,7 @@ const LeftTabNavigator = React.memo(function LeftTabNavigator({ setRendered(next) }, [selectedRoute, rendered]) - const hasModals = Router2.useRouterState(() => Router2.getModalStack().length > 0) + const hasModals = useRouterState(() => getModalStack().length > 0) return ( diff --git a/shared/stores/chat2.tsx b/shared/stores/chat2.tsx index a8d5f2ea3791..6c83479ae0f7 100644 --- a/shared/stores/chat2.tsx +++ b/shared/stores/chat2.tsx @@ -291,7 +291,6 @@ export interface State extends Store { badgesUpdated: (badgeState?: T.RPCGen.BadgeState) => void clearMetas: () => void dynamic: { - onChatMetasReceived: (metas: ReadonlyArray) => void onGetDaemonState: () => {handshakeVersion: number; dispatch: any} onGetTeamsTeamIDToMembers: ( teamID: T.Teams.TeamID @@ -494,9 +493,6 @@ export const useChatState = Z.createZustand((set, get) => { ignorePromise(f()) }, dynamic: { - onChatMetasReceived: (_metas: ReadonlyArray) => { - throw new Error('onChatMetasReceived not properly initialized') - }, onGetDaemonState: () => { throw new Error('onGetDaemonState not properly initialized') }, @@ -1633,7 +1629,7 @@ export const useChatState = Z.createZustand((set, get) => { }) const meta = Meta.inboxUIItemToConversationMeta(results2.conv) if (meta) { - get().dispatch.dynamic.onChatMetasReceived([meta]) + get().dispatch.metasReceived([meta]) } storeRegistry diff --git a/shared/stores/convostate.tsx b/shared/stores/convostate.tsx index d608909e36d6..189056f6512f 100644 --- a/shared/stores/convostate.tsx +++ b/shared/stores/convostate.tsx @@ -46,9 +46,11 @@ import {isMobile} from '@/constants/platform' import {enumKeys, ignorePromise, shallowEqual} from '@/constants/utils' import * as Strings from '@/constants/strings' -import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' +import type {useChatState} from '@/stores/chat2' +import type {useTeamsState} from '@/stores/teams' +import type {useUsersState} from '@/stores/users' const {darwinCopyToChatTempUploadFile} = KB2.functions @@ -373,11 +375,15 @@ type ScrollDirection = 'none' | 'back' | 'forward' export const numMessagesOnInitialLoad = isMobile ? 20 : 100 export const numMessagesOnScrollback = isMobile ? 100 : 100 -const createSlice: Z.ImmerStateCreator = (set, get) => { +const createSlice = ( + chatStateHook: typeof useChatState, + teamsStateHook: typeof useTeamsState, + usersStateHook: typeof useUsersState +): Z.ImmerStateCreator => (set, get) => { const closeBotModal = () => { clearModals() if (get().meta.teamname) { - storeRegistry.getState('teams').dispatch.getMembers(get().meta.teamID) + teamsStateHook.getState().dispatch.getMembers(get().meta.teamID) } } @@ -495,7 +501,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const onClick = () => { useConfigState.getState().dispatch.showMain() - storeRegistry.getState('chat').dispatch.navigateToInbox() + chatStateHook.getState().dispatch.navigateToInbox() get().dispatch.navigateToThread('desktopNotification') } const onClose = () => {} @@ -632,7 +638,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { logger.error(errMsg) throw new Error(errMsg) } - storeRegistry.getState('chat').dispatch.paymentInfoReceived(paymentInfo) + chatStateHook.getState().dispatch.paymentInfoReceived(paymentInfo) getConvoState(conversationIDKey).dispatch.paymentInfoReceived(msgID, paymentInfo) } @@ -1070,7 +1076,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { } // If there are block buttons on this conversation, clear them. - if (storeRegistry.getState('chat').blockButtonsMap.has(meta.teamID)) { + if (chatStateHook.getState().blockButtonsMap.has(meta.teamID)) { get().dispatch.dismissBlockButtons(meta.teamID) } @@ -1238,7 +1244,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { }, blockConversation: reportUser => { const f = async () => { - storeRegistry.getState('chat').dispatch.navigateToInbox() + chatStateHook.getState().dispatch.navigateToInbox() useConfigState.getState().dispatch.dynamic.persistRoute?.() await T.RPCChat.localSetConversationStatusLocalRpcPromise({ conversationID: get().getConvID(), @@ -1342,7 +1348,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { // Nav to inbox but don't use findNewConversation since changeSelectedConversation // does that with better information. It knows the conversation is hidden even before // that state bounces back. - storeRegistry.getState('chat').dispatch.navigateToInbox() + chatStateHook.getState().dispatch.navigateToInbox() get().dispatch.showInfoPanel(false, undefined) } @@ -1395,7 +1401,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const params = vs?.params as undefined | {conversationIDKey?: T.Chat.ConversationIDKey} if (params?.conversationIDKey === get().id) { // select a convo - const next = storeRegistry.getState('chat').inboxLayout?.smallTeams?.[0]?.convID + const next = chatStateHook.getState().inboxLayout?.smallTeams?.[0]?.convID if (next) { getConvoState(next).dispatch.navigateToThread('findNewestConversationFromLayout') } @@ -1660,9 +1666,8 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { logger.warn(`loadMoreMessages: error: ${error.desc}`) // no longer in team if (error.code === T.RPCGen.StatusCode.scchatnotinteam) { - const {inboxRefresh, navigateToInbox} = storeRegistry.getState('chat').dispatch - inboxRefresh('maybeKickedFromTeam') - navigateToInbox() + chatStateHook.getState().dispatch.inboxRefresh('maybeKickedFromTeam') + chatStateHook.getState().dispatch.navigateToInbox() } if (error.code !== T.RPCGen.StatusCode.scteamreaderror) { // scteamreaderror = user is not in team. they'll see the rekey screen so don't throw for that @@ -1989,7 +1994,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const text = formatTextForQuoting(message.text.stringValue()) getConvoState(newThreadCID).dispatch.injectIntoInput(text) - storeRegistry.getState('chat').dispatch.metasReceived([meta]) + chatStateHook.getState().dispatch.metasReceived([meta]) getConvoState(newThreadCID).dispatch.navigateToThread('createdMessagePrivately') } ignorePromise(f()) @@ -2134,7 +2139,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { loadMessages() // load meta - storeRegistry.getState('chat').dispatch.unboxRows([get().id], true) + chatStateHook.getState().dispatch.unboxRows([get().id], true) const updateNav = () => { const reason = _reason @@ -2460,7 +2465,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { // remove all bad people const goodParticipants = new Set(participantInfo.all) meta.resetParticipants.forEach(r => goodParticipants.delete(r)) - storeRegistry.getState('chat').dispatch.previewConversation({ + chatStateHook.getState().dispatch.previewConversation({ participants: [...goodParticipants], reason: 'resetChatWithoutThem', }) @@ -2503,7 +2508,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { return } - storeRegistry.getState('users').dispatch.getBio(username) + usersStateHook.getState().dispatch.getBio(username) } } @@ -2513,19 +2518,19 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { if (isMetaGood()) { const {teamID, teamname} = meta if (teamname) { - storeRegistry.getState('teams').dispatch.getMembers(teamID) + teamsStateHook.getState().dispatch.getMembers(teamID) } } } ensureSelectedTeamLoaded() const participantInfo = get().participants const force = !get().isMetaGood() || participantInfo.all.length === 0 - storeRegistry.getState('chat').dispatch.unboxRows([conversationIDKey], force) + chatStateHook.getState().dispatch.unboxRows([conversationIDKey], force) set(s => { s.threadLoadStatus = T.RPCChat.UIChatThreadStatusTyp.none }) fetchConversationBio() - storeRegistry.getState('chat').dispatch.resetConversationErrored() + chatStateHook.getState().dispatch.resetConversationErrored() }, sendAudioRecording: async (path, duration, amps) => { const outboxID = Common.generateOutboxID() @@ -2846,7 +2851,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { }) }, 1000), showInfoPanel: (show, tab) => { - storeRegistry.getState('chat').dispatch.updateInfoPanel(show, tab) + chatStateHook.getState().dispatch.updateInfoPanel(show, tab) const conversationIDKey = get().id if (Platform.isPhone) { const visibleScreen = getVisibleScreen() @@ -3247,10 +3252,33 @@ registerDebugClear(() => { clearChatStores() }) +let chatStore: typeof useChatState | undefined +let teamsStore: typeof useTeamsState | undefined +let usersStore: typeof useUsersState | undefined + +export const setOtherStores = ( + chat: typeof useChatState, + teams: typeof useTeamsState, + users: typeof useUsersState +) => { + chatStore = chat + teamsStore = teams + usersStore = users +} + const createConvoStore = (id: T.Chat.ConversationIDKey) => { const existing = chatStores.get(id) if (existing) return existing - const next = Z.createZustand(createSlice) + if (!chatStore || !teamsStore || !usersStore) { + throw new Error('Stores not initialized. Call setOtherStores before creating conversation stores.') + } + const next = Z.createZustand( + createSlice( + chatStore, + teamsStore, + usersStore + ) + ) next.setState({id}) chatStores.set(id, next) return next diff --git a/shared/stores/fs.tsx b/shared/stores/fs.tsx index 9189486e716a..ca53bdd9fa85 100644 --- a/shared/stores/fs.tsx +++ b/shared/stores/fs.tsx @@ -12,7 +12,6 @@ import {tlfToPreferredOrder} from '@/util/kbfs' import isObject from 'lodash/isObject' import isEqual from 'lodash/isEqual' import {navigateAppend, navigateUp} from '@/constants/router2' -import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import * as Constants from '@/constants/fs' @@ -401,6 +400,8 @@ export interface State extends Store { refreshMountDirsDesktop?: () => void setSfmiBannerDismissedDesktop?: (dismissed: boolean) => void uploadFromDragAndDropDesktop?: (parentPath: T.FS.Path, localPaths: Array) => void + onBadgeApp?: (key: 'kbfsUploading' | 'outOfSpace', on: boolean) => void + onSetBadgeCounts?: (counts: Map) => void } editError: (editID: T.FS.EditID, error: string) => void editSuccess: (editID: T.FS.EditID) => void @@ -775,6 +776,12 @@ export const useFSState = Z.createZustand((set, get) => { afterKbfsDaemonRpcStatusChanged: undefined, finishedDownloadWithIntentMobile: undefined, finishedRegularDownloadMobile: undefined, + onBadgeApp: () => { + throw new Error('onBadgeApp not implemented') + }, + onSetBadgeCounts: () => { + throw new Error('onSetBadgeCounts not implemented') + }, openAndUploadDesktop: undefined, openFilesFromWidgetDesktop: undefined, openLocalPathInSystemFileManagerDesktop: undefined, @@ -898,7 +905,7 @@ export const useFSState = Z.createZustand((set, get) => { }) const counts = new Map() counts.set(Tabs.fsTab, Constants.computeBadgeNumberForAll(get().tlfs)) - storeRegistry.getState('notifications').dispatch.setBadgeCounts(counts) + get().dispatch.dynamic.onSetBadgeCounts?.(counts) } } catch (e) { errorToActionOrThrow(e) @@ -1638,12 +1645,12 @@ export const useFSState = Z.createZustand((set, get) => { if (totalSyncingBytes <= 0 && !syncingPaths?.length) { break } - storeRegistry.getState('notifications').dispatch.badgeApp('kbfsUploading', true) + get().dispatch.dynamic.onBadgeApp?.('kbfsUploading', true) await timeoutPromise(getWaitDuration(endEstimate || undefined, 100, 4000)) // 0.1s to 4s } } finally { pollJournalStatusPolling = false - storeRegistry.getState('notifications').dispatch.badgeApp('kbfsUploading', false) + get().dispatch.dynamic.onBadgeApp?.('kbfsUploading', false) get().dispatch.checkKbfsDaemonRpcStatus() } } @@ -1896,7 +1903,7 @@ export const useFSState = Z.createZustand((set, get) => { body: 'You are out of disk space. Some folders could not be synced.', sound: true, }) - storeRegistry.getState('notifications').dispatch.badgeApp('outOfSpace', status.outOfSyncSpace) + get().dispatch.dynamic.onBadgeApp?.('outOfSpace', status.outOfSyncSpace) break } case T.FS.DiskSpaceStatus.Warning: diff --git a/shared/stores/notifications.tsx b/shared/stores/notifications.tsx index 5a2304b81a77..1d472d36a83b 100644 --- a/shared/stores/notifications.tsx +++ b/shared/stores/notifications.tsx @@ -4,7 +4,6 @@ import type * as T from '@/constants/types' import {isMobile} from '@/constants/platform' import isEqual from 'lodash/isEqual' import * as Tabs from '@/constants/tabs' -import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' @@ -30,6 +29,9 @@ const initialStore: Store = { export interface State extends Store { dispatch: { + dynamic: { + onFavoritesLoad?: () => void + } onEngineIncomingImpl: (action: EngineGen.Actions) => void resetState: 'default' badgeApp: (key: NotificationKeys, on: boolean) => void @@ -101,6 +103,11 @@ export const useNotifState = Z.createZustand((set, get) => { updateWidgetBadge(s) }) }, + dynamic: { + onFavoritesLoad: () => { + throw new Error('onFavoritesLoad not implemented') + }, + }, onEngineIncomingImpl: action => { switch (action.type) { case EngineGen.keybase1NotifyAuditRootAuditError: @@ -126,7 +133,7 @@ export const useNotifState = Z.createZustand((set, get) => { const counts = badgeStateToBadgeCounts(badgeState) if (!isMobile && shouldTriggerTlfLoad(badgeState)) { - storeRegistry.getState('fs').dispatch.favoritesLoad() + get().dispatch.dynamic.onFavoritesLoad?.() } if (counts) { get().dispatch.setBadgeCounts(counts) diff --git a/shared/stores/profile.tsx b/shared/stores/profile.tsx index b0c7204ced98..40df3896e0c8 100644 --- a/shared/stores/profile.tsx +++ b/shared/stores/profile.tsx @@ -8,9 +8,9 @@ import openURL from '@/util/open-url' import {RPCError} from '@/util/errors' import {fixCrop} from '@/util/crop' import {clearModals, navigateAppend, navigateUp} from '@/constants/router2' -import {storeRegistry} from '@/stores/store-registry' import {useCurrentUserState} from '@/stores/current-user' import {navToProfile} from '@/constants/router2' +import type {useTrackerState} from '@/stores/tracker2' type ProveGenericParams = { logoBlack: T.Tracker.SiteIconSet @@ -104,6 +104,12 @@ export interface State extends Store { cancelPgpGen?: () => void finishedWithKeyGen?: (shouldStoreKeyOnServer: boolean) => void submitUsername?: () => void + onTracker2GetDetails?: (username: string) => T.Tracker.Details | undefined + onTracker2Load?: ( + params: Parameters['dispatch']['load']>[0] + ) => void + onTracker2ShowUser?: (username: string, asTracker: boolean, skipNav?: boolean) => void + onTracker2UpdateResult?: (guiID: string, result: T.Tracker.DetailsState, reason?: string) => void } addProof: (platform: string, reason: 'appLink' | 'profile') => void backToProfile: () => void @@ -266,7 +272,7 @@ export const useProfileState = Z.createZustand((set, get) => { let canceled = false const loadAfter = () => - storeRegistry.getState('tracker2').dispatch.load({ + get().dispatch.dynamic.onTracker2Load?.({ assertion: useCurrentUserState.getState().username, guiID: generateGUIID(), inTracker: false, @@ -489,6 +495,18 @@ export const useProfileState = Z.createZustand((set, get) => { cancelAddProof: _cancelAddProof, cancelPgpGen: undefined, finishedWithKeyGen: undefined, + onTracker2GetDetails: () => { + throw new Error('onTracker2GetDetails not implemented') + }, + onTracker2Load: () => { + throw new Error('onTracker2Load not implemented') + }, + onTracker2ShowUser: () => { + throw new Error('onTracker2ShowUser not implemented') + }, + onTracker2UpdateResult: () => { + throw new Error('onTracker2UpdateResult not implemented') + }, }, editAvatar: () => { throw new Error('This is overloaded by platform specific') @@ -503,7 +521,7 @@ export const useProfileState = Z.createZustand((set, get) => { finishRevoking: () => { const username = useCurrentUserState.getState().username get().dispatch.showUserProfile(username) - storeRegistry.getState('tracker2').dispatch.load({ + get().dispatch.dynamic.onTracker2Load?.({ assertion: useCurrentUserState.getState().username, guiID: generateGUIID(), inTracker: false, @@ -599,7 +617,7 @@ export const useProfileState = Z.createZustand((set, get) => { }) const f = async () => { await T.RPCGen.proveCheckProofRpcPromise({sigID}, S.waitingKeyProfile) - storeRegistry.getState('tracker2').dispatch.showUser(useCurrentUserState.getState().username, false) + get().dispatch.dynamic.onTracker2ShowUser?.(useCurrentUserState.getState().username, false) } ignorePromise(f()) }, @@ -626,7 +644,7 @@ export const useProfileState = Z.createZustand((set, get) => { set(s => { s.blockUserModal = undefined }) - storeRegistry.getState('tracker2').dispatch.load({ + get().dispatch.dynamic.onTracker2Load?.({ assertion: username, guiID: generateGUIID(), inTracker: false, @@ -647,8 +665,8 @@ export const useProfileState = Z.createZustand((set, get) => { }, submitRevokeProof: proofId => { const f = async () => { - const you = storeRegistry.getState('tracker2').getDetails(useCurrentUserState.getState().username) - if (!you.assertions) return + const you = get().dispatch.dynamic.onTracker2GetDetails?.(useCurrentUserState.getState().username) + if (!you?.assertions) return const proof = [...you.assertions.values()].find(a => a.sigID === proofId) if (!proof) return @@ -679,7 +697,7 @@ export const useProfileState = Z.createZustand((set, get) => { const f = async () => { try { await T.RPCGen.userUnblockUserRpcPromise({username}) - storeRegistry.getState('tracker2').dispatch.load({ + get().dispatch.dynamic.onTracker2Load?.({ assertion: username, guiID: generateGUIID(), inTracker: false, @@ -691,9 +709,11 @@ export const useProfileState = Z.createZustand((set, get) => { } const error = _error logger.warn(`Error unblocking user ${username}`, error) - storeRegistry - .getState('tracker2') - .dispatch.updateResult(guiID, 'error', `Failed to unblock ${username}: ${error.desc}`) + get().dispatch.dynamic.onTracker2UpdateResult?.( + guiID, + 'error', + `Failed to unblock ${username}: ${error.desc}` + ) } } ignorePromise(f()) diff --git a/shared/stores/push.d.ts b/shared/stores/push.d.ts index fc96b75135bf..690c3ebfe63d 100644 --- a/shared/stores/push.d.ts +++ b/shared/stores/push.d.ts @@ -10,6 +10,15 @@ type Store = T.Immutable<{ export type State = Store & { dispatch: { + dynamic: { + onGetDaemonHandshakeState?: () => T.Config.DaemonHandshakeState + onNavigateToThread?: ( + conversationIDKey: T.Chat.ConversationIDKey, + reason: 'push' | 'extension', + pushBody?: string + ) => void + onShowUserProfile?: (username: string) => void + } checkPermissions: () => Promise deleteToken: (version: number) => void handlePush: (notification: T.Push.PushNotification) => void diff --git a/shared/stores/push.desktop.tsx b/shared/stores/push.desktop.tsx index d4626a2e8af6..8596722c5f76 100644 --- a/shared/stores/push.desktop.tsx +++ b/shared/stores/push.desktop.tsx @@ -16,6 +16,13 @@ export const usePushState = Z.createZustand(() => { return Promise.resolve(false) }, deleteToken: () => {}, + dynamic: { + onGetDaemonHandshakeState: () => { + return 'done' + }, + onNavigateToThread: () => {}, + onShowUserProfile: () => {}, + }, handlePush: () => {}, initialPermissionsCheck: () => {}, rejectPermissions: () => {}, diff --git a/shared/stores/push.native.tsx b/shared/stores/push.native.tsx index 568e97478bf1..b1f131b7cde1 100644 --- a/shared/stores/push.native.tsx +++ b/shared/stores/push.native.tsx @@ -2,7 +2,6 @@ import * as Tabs from '@/constants/tabs' import * as S from '@/constants/strings' import {ignorePromise, neverThrowPromiseFunc, timeoutPromise} from '@/constants/utils' import {navigateAppend, navUpToScreen, switchTab} from '@/constants/router2' -import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import {useLogoutState} from '@/stores/logout' @@ -72,7 +71,7 @@ export const usePushState = Z.createZustand((set, get) => { const {conversationIDKey, unboxPayload, membersType} = notification - storeRegistry.getConvoState(conversationIDKey).dispatch.navigateToThread('push', undefined, unboxPayload) + get().dispatch.dynamic.onNavigateToThread?.(conversationIDKey, 'push', unboxPayload) if (unboxPayload && membersType && !isIOS) { try { await T.RPCChat.localUnboxMobilePushNotificationRpcPromise({ @@ -136,6 +135,17 @@ export const usePushState = Z.createZustand((set, get) => { } ignorePromise(f()) }, + dynamic: { + onGetDaemonHandshakeState: () => { + throw new Error('onGetDaemonHandshakeState not implemented') + }, + onNavigateToThread: () => { + throw new Error('onNavigateToThread not implemented') + }, + onShowUserProfile: () => { + throw new Error('onShowUserProfile not implemented') + }, + }, handlePush: notification => { const f = async () => { try { @@ -154,13 +164,13 @@ export const usePushState = Z.createZustand((set, get) => { // We only care if the user clicked while in session if (notification.userInteraction) { const {username} = notification - storeRegistry.getState('profile').dispatch.showUserProfile(username) + get().dispatch.dynamic.onShowUserProfile?.(username) } break case 'chat.extension': { const {conversationIDKey} = notification - storeRegistry.getConvoState(conversationIDKey).dispatch.navigateToThread('extension') + get().dispatch.dynamic.onNavigateToThread?.(conversationIDKey, 'extension') } break case 'settings.contacts': @@ -297,7 +307,7 @@ export const usePushState = Z.createZustand((set, get) => { if ( p.show && useConfigState.getState().loggedIn && - storeRegistry.getState('daemon').handshakeState === 'done' && + get().dispatch.dynamic.onGetDaemonHandshakeState?.() === 'done' && !get().justSignedUp && !get().hasPermissions ) { diff --git a/shared/stores/recover-password.tsx b/shared/stores/recover-password.tsx index 80e96c070b3a..2888b3f79dcb 100644 --- a/shared/stores/recover-password.tsx +++ b/shared/stores/recover-password.tsx @@ -7,7 +7,6 @@ import {RPCError} from '@/util/errors' import {type Device} from '@/stores/provision' import {rpcDeviceToDevice} from '@/constants/rpc-utils' import {clearModals, navigateAppend, navigateUp} from '@/constants/router2' -import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' type Store = T.Immutable<{ @@ -37,6 +36,8 @@ export interface State extends Store { dispatch: { dynamic: { cancel?: () => void + onProvisionCancel?: (ignoreWarning?: boolean) => void + onStartAccountReset?: (skipPassword: boolean, username: string) => void submitDeviceSelect?: (name: string) => void submitPaperKey?: (key: string) => void submitPassword?: (pw: string) => void @@ -51,6 +52,12 @@ export const useState = Z.createZustand((set, get) => { const dispatch: State['dispatch'] = { dynamic: { cancel: undefined, + onProvisionCancel: () => { + throw new Error('onProvisionCancel not implemented') + }, + onStartAccountReset: () => { + throw new Error('onStartAccountReset not implemented') + }, submitDeviceSelect: undefined, submitPaperKey: undefined, submitPassword: undefined, @@ -75,7 +82,7 @@ export const useState = Z.createZustand((set, get) => { const f = async () => { if (p.abortProvisioning) { - storeRegistry.getState('provision').dispatch.dynamic.cancel?.() + get().dispatch.dynamic.onProvisionCancel?.() } let hadError = false try { @@ -139,8 +146,7 @@ export const useState = Z.createZustand((set, get) => { }) }) } else { - const {startAccountReset} = storeRegistry.getState('autoreset').dispatch - startAccountReset(true, '') + get().dispatch.dynamic.onStartAccountReset?.(true, '') response.result(T.RPCGen.ResetPromptResponse.nothing) } }, diff --git a/shared/stores/router2.tsx b/shared/stores/router2.tsx index 0e5c0c8f2c6e..b2dc1cbac7d6 100644 --- a/shared/stores/router2.tsx +++ b/shared/stores/router2.tsx @@ -1,8 +1,7 @@ import type * as T from '@/constants/types' import * as Z from '@/util/zustand' -import * as Tabs from '@/constants/tabs' +import type * as Tabs from '@/constants/tabs' import type {RouteKeys} from '@/router-v2/route-params' -import {storeRegistry} from '@/stores/store-registry' import * as Util from '@/constants/router2' export { @@ -76,97 +75,6 @@ export const useRouterState = Z.createZustand((set, get) => { set(s => { s.navState = next }) - - const updateTeamBuilding = () => { - const namespaces = ['chat2', 'crypto', 'teams', 'people'] as const - const namespaceToRoute = new Map([ - ['chat2', 'chatNewChat'], - ['crypto', 'cryptoTeamBuilder'], - ['teams', 'teamsTeamBuilder'], - ['people', 'peopleTeamBuilder'], - ]) - for (const namespace of namespaces) { - const wasTeamBuilding = namespaceToRoute.get(namespace) === Util.getVisibleScreen(prev)?.name - if (wasTeamBuilding) { - // team building or modal on top of that still - const isTeamBuilding = namespaceToRoute.get(namespace) === Util.getVisibleScreen(next)?.name - if (!isTeamBuilding) { - storeRegistry.getTBStore(namespace).dispatch.cancelTeamBuilding() - } - } - } - } - updateTeamBuilding() - - const updateFS = () => { - // Clear critical update when we nav away from tab - if ( - prev && - Util.getTab(prev) === Tabs.fsTab && - next && - Util.getTab(next) !== Tabs.fsTab && - storeRegistry.getState('fs').criticalUpdate - ) { - const {dispatch} = storeRegistry.getState('fs') - dispatch.setCriticalUpdate(false) - } - const fsRrouteNames = ['fsRoot', 'barePreview'] - const wasScreen = fsRrouteNames.includes(Util.getVisibleScreen(prev)?.name ?? '') - const isScreen = fsRrouteNames.includes(Util.getVisibleScreen(next)?.name ?? '') - if (wasScreen !== isScreen) { - const {dispatch} = storeRegistry.getState('fs') - if (wasScreen) { - dispatch.userOut() - } else { - dispatch.userIn() - } - } - } - updateFS() - - const updateSignup = () => { - // Clear "just signed up email" when you leave the people tab after signup - if ( - prev && - Util.getTab(prev) === Tabs.peopleTab && - next && - Util.getTab(next) !== Tabs.peopleTab && - storeRegistry.getState('signup').justSignedUpEmail - ) { - storeRegistry.getState('signup').dispatch.clearJustSignedUpEmail() - } - } - updateSignup() - - const updatePeople = () => { - if (prev && Util.getTab(prev) === Tabs.peopleTab && next && Util.getTab(next) !== Tabs.peopleTab) { - storeRegistry.getState('people').dispatch.markViewed() - } - } - updatePeople() - - const updateTeams = () => { - if (prev && Util.getTab(prev) === Tabs.teamsTab && next && Util.getTab(next) !== Tabs.teamsTab) { - storeRegistry.getState('teams').dispatch.clearNavBadges() - } - } - updateTeams() - - const updateSettings = () => { - // Clear "check your inbox" in settings when you leave the settings tab - if ( - prev && - Util.getTab(prev) === Tabs.settingsTab && - next && - Util.getTab(next) !== Tabs.settingsTab && - storeRegistry.getState('settings-email').addedEmail - ) { - storeRegistry.getState('settings-email').dispatch.resetAddedEmail() - } - } - updateSettings() - - storeRegistry.getState('chat').dispatch.onRouteChanged(prev, next) }, switchTab: Util.switchTab, } diff --git a/shared/stores/signup.tsx b/shared/stores/signup.tsx index 6e9c390979f6..f42110c7072d 100644 --- a/shared/stores/signup.tsx +++ b/shared/stores/signup.tsx @@ -9,7 +9,6 @@ import trim from 'lodash/trim' import {RPCError} from '@/util/errors' import {isValidEmail, isValidName, isValidUsername} from '@/util/simple-validators' import {navigateAppend, navigateUp} from '@/constants/router2' -import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' type Store = T.Immutable<{ @@ -46,6 +45,10 @@ const initialStore: Store = { export interface State extends Store { dispatch: { + dynamic: { + onEditEmail?: (p: {email: string; makeSearchable: boolean}) => void + onShowPermissionsPrompt?: (p: {justSignedUp?: boolean}) => void + } checkDeviceName: (devicename: string) => void checkInviteCode: () => void checkUsername: (username: string) => void @@ -81,7 +84,7 @@ export const useSignupState = Z.createZustand((set, get) => { } try { - storeRegistry.getState('push').dispatch.showPermissionsPrompt({justSignedUp: true}) + get().dispatch.dynamic.onShowPermissionsPrompt?.({justSignedUp: true}) await T.RPCGen.signupSignupRpcListener({ customResponseIncomingCallMap: { @@ -122,7 +125,7 @@ export const useSignupState = Z.createZustand((set, get) => { } // If the email was set to be visible during signup, we need to set that with a separate RPC. if (noErrors() && get().emailVisible) { - storeRegistry.getState('settings-email').dispatch.editEmail({email: get().email, makeSearchable: true}) + get().dispatch.dynamic.onEditEmail?.({email: get().email, makeSearchable: true}) } } catch (_error) { if (_error instanceof RPCError) { @@ -131,7 +134,7 @@ export const useSignupState = Z.createZustand((set, get) => { s.signupError = error }) navigateAppend('signupError') - storeRegistry.getState('push').dispatch.showPermissionsPrompt({justSignedUp: false}) + get().dispatch.dynamic.onShowPermissionsPrompt?.({justSignedUp: false}) } } } @@ -229,6 +232,14 @@ export const useSignupState = Z.createZustand((set, get) => { s.justSignedUpEmail = '' }) }, + dynamic: { + onEditEmail: () => { + throw new Error('onEditEmail not implemented') + }, + onShowPermissionsPrompt: () => { + throw new Error('onShowPermissionsPrompt not implemented') + }, + }, goBackAndClearErrors: () => { set(s => { s.devicenameError = '' diff --git a/shared/stores/store-registry.tsx b/shared/stores/store-registry.tsx index a54a04a129dd..8fe0eb68399a 100644 --- a/shared/stores/store-registry.tsx +++ b/shared/stores/store-registry.tsx @@ -4,14 +4,9 @@ import type * as T from '@/constants/types' import type * as TBType from '@/stores/team-building' import type * as ConvoStateType from '@/stores/convostate' import type {ConvoState} from '@/stores/convostate' -import type {State as AutoResetState, useAutoResetState} from '@/stores/autoreset' -import type {State as BotsState, useBotsState} from '@/stores/bots' import type {State as ChatState, useChatState} from '@/stores/chat2' import type {State as DaemonState, useDaemonState} from '@/stores/daemon' -import type {State as DevicesState, useDevicesState} from '@/stores/devices' import type {State as FSState, useFSState} from '@/stores/fs' -import type {State as GitState, useGitState} from '@/stores/git' -import type {State as NotificationsState, useNotifState} from '@/stores/notifications' import type {State as PeopleState, usePeopleState} from '@/stores/people' import type {State as ProfileState, useProfileState} from '@/stores/profile' import type {State as ProvisionState, useProvisionState} from '@/stores/provision' @@ -21,94 +16,63 @@ import type { useState as useRecoverPasswordState, } from '@/stores/recover-password' import type {State as SettingsState, useSettingsState} from '@/stores/settings' -import type {State as SettingsChatState, useSettingsChatState} from '@/stores/settings-chat' -import type {State as SettingsContactsState, useSettingsContactsState} from '@/stores/settings-contacts' import type {State as SettingsEmailState, useSettingsEmailState} from '@/stores/settings-email' -import type {State as SettingsPasswordState, usePWState} from '@/stores/settings-password' import type {State as SettingsPhoneState, useSettingsPhoneState} from '@/stores/settings-phone' import type {State as SignupState, useSignupState} from '@/stores/signup' import type {State as TeamsState, useTeamsState} from '@/stores/teams' import type {State as Tracker2State, useTrackerState} from '@/stores/tracker2' -import type {State as UnlockFoldersState, useUnlockFoldersState} from '@/stores/unlock-folders' import type {State as UsersState, useUsersState} from '@/stores/users' type StoreName = - | 'autoreset' - | 'bots' | 'chat' | 'daemon' - | 'devices' | 'fs' - | 'git' - | 'notifications' | 'people' | 'profile' | 'provision' | 'push' | 'recover-password' | 'settings' - | 'settings-chat' - | 'settings-contacts' | 'settings-email' - | 'settings-password' | 'settings-phone' | 'signup' | 'teams' | 'tracker2' - | 'unlock-folders' | 'users' type StoreStates = { - autoreset: AutoResetState - bots: BotsState chat: ChatState daemon: DaemonState - devices: DevicesState fs: FSState - git: GitState - notifications: NotificationsState people: PeopleState profile: ProfileState provision: ProvisionState push: PushState 'recover-password': RecoverPasswordState settings: SettingsState - 'settings-chat': SettingsChatState - 'settings-contacts': SettingsContactsState 'settings-email': SettingsEmailState - 'settings-password': SettingsPasswordState 'settings-phone': SettingsPhoneState signup: SignupState teams: TeamsState tracker2: Tracker2State - 'unlock-folders': UnlockFoldersState users: UsersState } type StoreHooks = { - autoreset: typeof useAutoResetState - bots: typeof useBotsState chat: typeof useChatState daemon: typeof useDaemonState - devices: typeof useDevicesState fs: typeof useFSState - git: typeof useGitState - notifications: typeof useNotifState people: typeof usePeopleState profile: typeof useProfileState provision: typeof useProvisionState push: typeof usePushState 'recover-password': typeof useRecoverPasswordState settings: typeof useSettingsState - 'settings-chat': typeof useSettingsChatState - 'settings-contacts': typeof useSettingsContactsState 'settings-email': typeof useSettingsEmailState - 'settings-password': typeof usePWState 'settings-phone': typeof useSettingsPhoneState signup: typeof useSignupState teams: typeof useTeamsState tracker2: typeof useTrackerState - 'unlock-folders': typeof useUnlockFoldersState users: typeof useUsersState } @@ -116,14 +80,6 @@ class StoreRegistry { getStore(storeName: T): StoreHooks[T] { /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-return */ switch (storeName) { - case 'autoreset': { - const {useAutoResetState} = require('@/stores/autoreset') - return useAutoResetState - } - case 'bots': { - const {useBotsState} = require('@/stores/bots') - return useBotsState - } case 'chat': { const {useChatState} = require('@/stores/chat2') return useChatState @@ -132,22 +88,10 @@ class StoreRegistry { const {useDaemonState} = require('@/stores/daemon') return useDaemonState } - case 'devices': { - const {useDevicesState} = require('@/stores/devices') - return useDevicesState - } case 'fs': { const {useFSState} = require('@/stores/fs') return useFSState } - case 'git': { - const {useGitState} = require('@/stores/git') - return useGitState - } - case 'notifications': { - const {useNotifState} = require('@/stores/notifications') - return useNotifState - } case 'people': { const {usePeopleState} = require('@/stores/people') return usePeopleState @@ -172,22 +116,10 @@ class StoreRegistry { const {useSettingsState} = require('@/stores/settings') return useSettingsState } - case 'settings-chat': { - const {useSettingsChatState} = require('@/stores/settings-chat') - return useSettingsChatState - } - case 'settings-contacts': { - const {useSettingsContactsState} = require('@/stores/settings-contacts') - return useSettingsContactsState - } case 'settings-email': { const {useSettingsEmailState} = require('@/stores/settings-email') return useSettingsEmailState } - case 'settings-password': { - const {usePWState} = require('@/stores/settings-password') - return usePWState - } case 'settings-phone': { const {useSettingsPhoneState} = require('@/stores/settings-phone') return useSettingsPhoneState @@ -204,10 +136,6 @@ class StoreRegistry { const {useTrackerState} = require('@/stores/tracker2') return useTrackerState } - case 'unlock-folders': { - const {useUnlockFoldersState} = require('@/stores/unlock-folders') - return useUnlockFoldersState - } case 'users': { const {useUsersState} = require('@/stores/users') return useUsersState diff --git a/shared/stores/teams.tsx b/shared/stores/teams.tsx index 38a35ecbb556..b240ef5a7dad 100644 --- a/shared/stores/teams.tsx +++ b/shared/stores/teams.tsx @@ -21,6 +21,7 @@ import {bodyToJSON} from '@/constants/rpc-utils' import {fixCrop} from '@/util/crop' import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' +import {type useChatState} from '@/stores/chat2' import {useCurrentUserState} from '@/stores/current-user' import * as Util from '@/constants/teams' import {getTab} from '@/constants/router2' @@ -865,6 +866,11 @@ const initialStore: Store = { export interface State extends Store { dispatch: { dynamic: { + onChatNavigateToInbox?: (allowSwitchTab?: boolean) => void + onChatPreviewConversation?: ( + p: Parameters['dispatch']['previewConversation']>[0] + ) => void + onUsersUpdates?: (updates: ReadonlyArray<{name: string; info: Partial}>) => void respondToInviteLink?: (accept: boolean) => void } addMembersWizardPushMembers: (members: Array) => void @@ -1425,7 +1431,7 @@ export const useTeamsState = Z.createZustand((set, get) => { get().dispatch.loadTeamChannelList(teamID) // Select the new channel, and switch to the chat tab. if (navToChatOnSuccess) { - storeRegistry.getState('chat').dispatch.previewConversation({ + get().dispatch.dynamic.onChatPreviewConversation?.({ channelname, conversationIDKey: newConversationIDKey, reason: 'newChannel', @@ -1495,9 +1501,12 @@ export const useTeamsState = Z.createZustand((set, get) => { if (fromChat) { clearModals() - const {previewConversation, navigateToInbox} = storeRegistry.getState('chat').dispatch - navigateToInbox() - previewConversation({channelname: 'general', reason: 'convertAdHoc', teamname}) + get().dispatch.dynamic.onChatNavigateToInbox?.() + get().dispatch.dynamic.onChatPreviewConversation?.({ + channelname: 'general', + reason: 'convertAdHoc', + teamname, + }) } else { clearModals() navigateAppend({props: {teamID}, selected: 'team'}) @@ -1585,6 +1594,20 @@ export const useTeamsState = Z.createZustand((set, get) => { ignorePromise(f()) }, dynamic: { + onChatNavigateToInbox: (_allowSwitchTab?: boolean) => { + throw new Error('onChatNavigateToInbox not implemented') + }, + onChatPreviewConversation: (_p: { + channelname?: string + conversationIDKey?: T.Chat.ConversationIDKey + reason?: string + teamname?: string + }) => { + throw new Error('onChatPreviewConversation not implemented') + }, + onUsersUpdates: (_updates: ReadonlyArray<{name: string; info: Partial}>) => { + throw new Error('onUsersUpdates not implemented') + }, respondToInviteLink: undefined, }, eagerLoadTeams: () => { @@ -1725,7 +1748,7 @@ export const useTeamsState = Z.createZustand((set, get) => { set(s => { s.teamIDToMembers.set(teamID, members) }) - storeRegistry.getState('users').dispatch.updates( + get().dispatch.dynamic.onUsersUpdates?.( [...members.values()].map(m => ({ info: {fullname: m.fullName}, name: m.username, diff --git a/shared/stores/tracker2.tsx b/shared/stores/tracker2.tsx index 60712f586ef3..506941d024ef 100644 --- a/shared/stores/tracker2.tsx +++ b/shared/stores/tracker2.tsx @@ -7,7 +7,6 @@ import * as T from '@/constants/types' import {RPCError} from '@/util/errors' import {mapGetEnsureValue} from '@/util/map' import {navigateAppend, navigateUp} from '@/constants/router2' -import {storeRegistry} from '@/stores/store-registry' import {useCurrentUserState} from '@/stores/current-user' export const noDetails: T.Tracker.Details = { @@ -164,6 +163,10 @@ const initialStore: Store = { export interface State extends Store { dispatch: { + dynamic: { + onShowUserProfile?: (username: string) => void + onUsersUpdates?: (updates: ReadonlyArray<{name: string; info: Partial}>) => void + } changeFollow: (guiID: string, follow: boolean) => void closeTracker: (guiID: string) => void getProofSuggestions: () => void @@ -228,6 +231,14 @@ export const useTrackerState = Z.createZustand((set, get) => { s.showTrackerSet.delete(username) }) }, + dynamic: { + onShowUserProfile: () => { + throw new Error('onShowUserProfile not implemented') + }, + onUsersUpdates: () => { + throw new Error('onUsersUpdates not implemented') + }, + }, getProofSuggestions: () => { const f = async () => { try { @@ -320,9 +331,9 @@ export const useTrackerState = Z.createZustand((set, get) => { d.followersCount = d.followers.size }) if (fs.users) { - storeRegistry - .getState('users') - .dispatch.updates(fs.users.map(u => ({info: {fullname: u.fullName}, name: u.username}))) + get().dispatch.dynamic.onUsersUpdates?.( + fs.users.map(u => ({info: {fullname: u.fullName}, name: u.username})) + ) } } catch (error) { if (error instanceof RPCError) { @@ -346,9 +357,9 @@ export const useTrackerState = Z.createZustand((set, get) => { d.followingCount = d.following.size }) if (fs.users) { - storeRegistry - .getState('users') - .dispatch.updates(fs.users.map(u => ({info: {fullname: u.fullName}, name: u.username}))) + get().dispatch.dynamic.onUsersUpdates?.( + fs.users.map(u => ({info: {fullname: u.fullName}, name: u.username})) + ) } } catch (error) { if (error instanceof RPCError) { @@ -436,8 +447,7 @@ export const useTrackerState = Z.createZustand((set, get) => { ) d.hidFromFollowers = hidFromFollowers }) - username && - storeRegistry.getState('users').dispatch.updates([{info: {fullname: card.fullName}, name: username}]) + username && get().dispatch.dynamic.onUsersUpdates?.([{info: {fullname: card.fullName}, name: username}]) }, notifyReset: guiID => { set(s => { @@ -596,7 +606,7 @@ export const useTrackerState = Z.createZustand((set, get) => { }) if (!skipNav) { // go to profile page - storeRegistry.getState('profile').dispatch.showUserProfile(username) + get().dispatch.dynamic.onShowUserProfile?.(username) } }, updateResult: (guiID, result, reason) => { From 16663287e2595cffdf333ac9b235dee2780f63f1 Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Wed, 28 Jan 2026 16:39:27 -0500 Subject: [PATCH 18/20] WIP: shift 20 defer dynamic (#28837) * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/app/global-errors/hook.tsx | 2 +- shared/app/out-of-date.tsx | 2 +- .../attachment-fullscreen/hooks.tsx | 2 +- shared/chat/conversation/command-status.tsx | 2 +- .../conversation/info-panel/attachments.tsx | 2 +- .../input-area/location-popup.native.tsx | 2 +- .../conversation/list-area/index.desktop.tsx | 2 +- .../messages/attachment/audio.tsx | 2 +- .../conversation/messages/attachment/file.tsx | 2 +- .../messages/attachment/shared.tsx | 2 +- .../messages/message-popup/attachment.tsx | 2 +- .../messages/message-popup/hooks.tsx | 2 +- .../messages/message-popup/text.tsx | 2 +- shared/chat/pdf/index.desktop.tsx | 2 +- shared/chat/pdf/index.native.tsx | 2 +- shared/common-adapters/copy-text.tsx | 4 +- shared/constants/init/index.desktop.tsx | 54 +++++++-------- shared/constants/init/index.native.tsx | 26 +++---- shared/constants/init/shared.tsx | 40 +++++------ shared/crypto/output.tsx | 6 +- shared/desktop/renderer/main2.desktop.tsx | 4 +- shared/fs/banner/conflict-banner.tsx | 2 +- .../container.tsx | 4 +- .../kext-permission-popup.tsx | 2 +- shared/fs/browser/index.tsx | 2 +- shared/fs/common/hooks.tsx | 4 +- .../fs/common/open-in-system-file-manager.tsx | 2 +- .../path-item-action/menu-container.tsx | 2 +- .../common/refresh-driver-status-on-mount.tsx | 2 +- shared/fs/common/upload-button.tsx | 4 +- shared/fs/filepreview/default-view.tsx | 2 +- shared/fs/footer/download.tsx | 2 +- shared/fs/footer/downloads.tsx | 2 +- shared/profile/post-proof.tsx | 2 +- .../code-page/qr-scan/not-authorized.tsx | 2 +- shared/router-v2/router.native.tsx | 2 +- shared/settings/archive/index.tsx | 4 +- shared/settings/files/index.desktop.tsx | 2 +- shared/settings/manage-contacts.tsx | 2 +- shared/stores/autoreset.tsx | 8 +-- shared/stores/chat2.tsx | 22 +++--- shared/stores/config.tsx | 16 ++--- shared/stores/convostate.tsx | 2 +- shared/stores/fs.tsx | 68 +++++++++---------- shared/stores/notifications.tsx | 6 +- shared/stores/profile.tsx | 38 ++++++----- shared/stores/push.d.ts | 2 +- shared/stores/push.desktop.tsx | 4 +- shared/stores/push.native.tsx | 34 +++++----- shared/stores/recover-password.tsx | 16 +++-- shared/stores/router2.tsx | 4 +- shared/stores/signup.tsx | 10 +-- shared/stores/team-building.tsx | 20 +++--- shared/stores/teams.tsx | 42 ++++++------ shared/stores/tracker2.tsx | 12 ++-- shared/teams/common/enable-contacts.tsx | 2 +- shared/tracker2/assertion.tsx | 2 +- shared/util/zustand.tsx | 11 ++- shared/wallets/really-remove-account.tsx | 2 +- 59 files changed, 274 insertions(+), 255 deletions(-) diff --git a/shared/app/global-errors/hook.tsx b/shared/app/global-errors/hook.tsx index d8e9d9701d30..df6a580e4787 100644 --- a/shared/app/global-errors/hook.tsx +++ b/shared/app/global-errors/hook.tsx @@ -26,7 +26,7 @@ const useData = () => { navigateAppend('feedback') } }, [navigateAppend, clearModals, loggedIn, setGlobalError]) - const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard) + const copyToClipboard = useConfigState(s => s.dispatch.defer.copyToClipboard) const onDismiss = React.useCallback(() => { setGlobalError() }, [setGlobalError]) diff --git a/shared/app/out-of-date.tsx b/shared/app/out-of-date.tsx index d77926f918bc..70b33bb01693 100644 --- a/shared/app/out-of-date.tsx +++ b/shared/app/out-of-date.tsx @@ -62,7 +62,7 @@ const OutOfDate = () => { C.ignorePromise(f()) }) - const onOpenAppStore = useConfigState(s => s.dispatch.dynamic.openAppStore) + const onOpenAppStore = useConfigState(s => s.dispatch.defer.openAppStore) return status !== 'critical' ? null : ( diff --git a/shared/chat/conversation/attachment-fullscreen/hooks.tsx b/shared/chat/conversation/attachment-fullscreen/hooks.tsx index cd16b218c638..3c6c21497450 100644 --- a/shared/chat/conversation/attachment-fullscreen/hooks.tsx +++ b/shared/chat/conversation/attachment-fullscreen/hooks.tsx @@ -37,7 +37,7 @@ export const useData = (initialOrdinal: T.Chat.Ordinal) => { }, [onSwitchAttachment]) const openLocalPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop + s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop ) const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) const showInfoPanel = Chat.useChatContext(s => s.dispatch.showInfoPanel) diff --git a/shared/chat/conversation/command-status.tsx b/shared/chat/conversation/command-status.tsx index d27ab60a9bf3..dc67888d461c 100644 --- a/shared/chat/conversation/command-status.tsx +++ b/shared/chat/conversation/command-status.tsx @@ -13,7 +13,7 @@ const Container = () => { const info = Chat.useChatContext(s => s.commandStatus) const _info = info || empty - const onOpenAppSettings = useConfigState(s => s.dispatch.dynamic.openAppSettings) + const onOpenAppSettings = useConfigState(s => s.dispatch.defer.openAppSettings) const setCommandStatusInfo = Chat.useChatContext(s => s.dispatch.setCommandStatusInfo) const onCancel = () => { setCommandStatusInfo() diff --git a/shared/chat/conversation/info-panel/attachments.tsx b/shared/chat/conversation/info-panel/attachments.tsx index 1deea243bb7d..61b7fb7608a9 100644 --- a/shared/chat/conversation/info-panel/attachments.tsx +++ b/shared/chat/conversation/info-panel/attachments.tsx @@ -499,7 +499,7 @@ export const useAttachmentSections = ( } const openLocalPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop + s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop ) const onShowInFinder = (message: T.Chat.MessageAttachment) => message.downloadPath && openLocalPathInSystemFileManagerDesktop?.(message.downloadPath) diff --git a/shared/chat/conversation/input-area/location-popup.native.tsx b/shared/chat/conversation/input-area/location-popup.native.tsx index 2327f955a1f0..ec5fef04455f 100644 --- a/shared/chat/conversation/input-area/location-popup.native.tsx +++ b/shared/chat/conversation/input-area/location-popup.native.tsx @@ -62,7 +62,7 @@ const LocationPopup = () => { const onClose = () => { clearModals() } - const onSettings = useConfigState(s => s.dispatch.dynamic.openAppSettings) + const onSettings = useConfigState(s => s.dispatch.defer.openAppSettings) const sendMessage = Chat.useChatContext(s => s.dispatch.sendMessage) const onLocationShare = (duration: string) => { onClose() diff --git a/shared/chat/conversation/list-area/index.desktop.tsx b/shared/chat/conversation/list-area/index.desktop.tsx index 2dd8fc5f700a..f9375aeba2d0 100644 --- a/shared/chat/conversation/list-area/index.desktop.tsx +++ b/shared/chat/conversation/list-area/index.desktop.tsx @@ -493,7 +493,7 @@ const ThreadWrapper = React.memo(function ThreadWrapper() { ) const {conversationIDKey, editingOrdinal, centeredOrdinal} = data const {containsLatestMessage, messageOrdinals, loaded, messageTypeMap} = data - const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard) + const copyToClipboard = useConfigState(s => s.dispatch.defer.copyToClipboard) const listRef = React.useRef(null) const _setListRef = React.useCallback((r: HTMLDivElement | null) => { listRef.current = r diff --git a/shared/chat/conversation/messages/attachment/audio.tsx b/shared/chat/conversation/messages/attachment/audio.tsx index 1de12a908a91..cd32586199c4 100644 --- a/shared/chat/conversation/messages/attachment/audio.tsx +++ b/shared/chat/conversation/messages/attachment/audio.tsx @@ -25,7 +25,7 @@ const AudioAttachment = () => { const progressLabel = Chat.messageAttachmentTransferStateToProgressLabel(message.transferState) const hasProgress = messageAttachmentHasProgress(message) const openLocalPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop + s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop ) const onShowInFinder = () => { message.downloadPath && openLocalPathInSystemFileManagerDesktop?.(message.downloadPath) diff --git a/shared/chat/conversation/messages/attachment/file.tsx b/shared/chat/conversation/messages/attachment/file.tsx index ce6d9e15c985..bfcbe3bbc11f 100644 --- a/shared/chat/conversation/messages/attachment/file.tsx +++ b/shared/chat/conversation/messages/attachment/file.tsx @@ -57,7 +57,7 @@ const FileContainer = React.memo(function FileContainer(p: OwnProps) { [switchTab, saltpackOpenFile] ) const openLocalPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop + s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop ) const _onShowInFinder = React.useCallback(() => { downloadPath && openLocalPathInSystemFileManagerDesktop?.(downloadPath) diff --git a/shared/chat/conversation/messages/attachment/shared.tsx b/shared/chat/conversation/messages/attachment/shared.tsx index d0937dde1167..3f0efebc0588 100644 --- a/shared/chat/conversation/messages/attachment/shared.tsx +++ b/shared/chat/conversation/messages/attachment/shared.tsx @@ -103,7 +103,7 @@ export const TransferIcon = (p: {style: Kb.Styles.StylesCrossPlatform}) => { download(ordinal) }, [ordinal, download]) - const openFinder = useFSState(s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop) + const openFinder = useFSState(s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop) const onFinder = React.useCallback(() => { downloadPath && openFinder?.(downloadPath) }, [openFinder, downloadPath]) diff --git a/shared/chat/conversation/messages/message-popup/attachment.tsx b/shared/chat/conversation/messages/message-popup/attachment.tsx index 19227db84c07..b6da989e6deb 100644 --- a/shared/chat/conversation/messages/message-popup/attachment.tsx +++ b/shared/chat/conversation/messages/message-popup/attachment.tsx @@ -84,7 +84,7 @@ const PopAttach = (ownProps: OwnProps) => { const onShareAttachment = C.isMobile ? _onShareAttachment : undefined const openLocalPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop + s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop ) const _onShowInFinder = React.useCallback(() => { downloadPath && openLocalPathInSystemFileManagerDesktop?.(downloadPath) diff --git a/shared/chat/conversation/messages/message-popup/hooks.tsx b/shared/chat/conversation/messages/message-popup/hooks.tsx index 5a55ddf164ab..48b40ada8b7f 100644 --- a/shared/chat/conversation/messages/message-popup/hooks.tsx +++ b/shared/chat/conversation/messages/message-popup/hooks.tsx @@ -104,7 +104,7 @@ export const useItems = (ordinal: T.Chat.Ordinal, onHidden: () => void) => { : [] const convLabel = getConversationLabel(participantInfo, meta, true) - const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard) + const copyToClipboard = useConfigState(s => s.dispatch.defer.copyToClipboard) const onCopyLink = React.useCallback(() => { copyToClipboard(linkFromConvAndMessage(convLabel, id)) }, [copyToClipboard, id, convLabel]) diff --git a/shared/chat/conversation/messages/message-popup/text.tsx b/shared/chat/conversation/messages/message-popup/text.tsx index ac05c2730cce..66425418691d 100644 --- a/shared/chat/conversation/messages/message-popup/text.tsx +++ b/shared/chat/conversation/messages/message-popup/text.tsx @@ -75,7 +75,7 @@ const PopText = (ownProps: OwnProps) => { // you can reply privately *if* text message, someone else's message, and not in a 1-on-1 chat const canReplyPrivately = ['small', 'big'].includes(teamType) || numPart > 2 const navigateAppend = C.useRouterState(s => s.dispatch.navigateAppend) - const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard) + const copyToClipboard = useConfigState(s => s.dispatch.defer.copyToClipboard) const onCopy = React.useCallback(() => { text && copyToClipboard(text) }, [copyToClipboard, text]) diff --git a/shared/chat/pdf/index.desktop.tsx b/shared/chat/pdf/index.desktop.tsx index 6fcee8301fc1..8866e8ec8316 100644 --- a/shared/chat/pdf/index.desktop.tsx +++ b/shared/chat/pdf/index.desktop.tsx @@ -11,7 +11,7 @@ const ChatPDF = (props: Props) => { const title = message?.title || message?.fileName || 'PDF' const url = message?.fileURL const openLocalPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop + s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop ) const attachmentDownload = Chat.useChatContext(s => s.dispatch.attachmentDownload) diff --git a/shared/chat/pdf/index.native.tsx b/shared/chat/pdf/index.native.tsx index 8f6253a027d2..d0900794f567 100644 --- a/shared/chat/pdf/index.native.tsx +++ b/shared/chat/pdf/index.native.tsx @@ -12,7 +12,7 @@ const ChatPDF = (props: Props) => { const [error, setError] = React.useState('') const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) const onBack = () => navigateUp() - const showShareActionSheet = useConfigState(s => s.dispatch.dynamic.showShareActionSheet) + const showShareActionSheet = useConfigState(s => s.dispatch.defer.showShareActionSheet) const onShare = () => { showShareActionSheet?.(url ?? '', '', 'application/pdf') } diff --git a/shared/common-adapters/copy-text.tsx b/shared/common-adapters/copy-text.tsx index 505513bd6efd..43a797333631 100644 --- a/shared/common-adapters/copy-text.tsx +++ b/shared/common-adapters/copy-text.tsx @@ -61,8 +61,8 @@ const CopyText = (props: Props) => { const popupAnchor = React.useRef(null) const textRef = React.useRef(null) - const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard) - const showShareActionSheet = useConfigState(s => s.dispatch.dynamic.showShareActionSheet) + const copyToClipboard = useConfigState(s => s.dispatch.defer.copyToClipboard) + const showShareActionSheet = useConfigState(s => s.dispatch.defer.showShareActionSheet) const copy = React.useCallback(() => { if (!text) { if (!loadText) { diff --git a/shared/constants/init/index.desktop.tsx b/shared/constants/init/index.desktop.tsx index ea30f3e872ca..08d952d63514 100644 --- a/shared/constants/init/index.desktop.tsx +++ b/shared/constants/init/index.desktop.tsx @@ -179,7 +179,7 @@ const fuseStatusToActions = if (status.kextStarted && previousStatusType === T.FS.DriverStatusType.Disabled) { useFSState .getState() - .dispatch.dynamic.openPathInSystemFileManagerDesktop?.(T.FS.stringToPath('/keybase')) + .dispatch.defer.openPathInSystemFileManagerDesktop?.(T.FS.stringToPath('/keybase')) } } @@ -198,7 +198,7 @@ const driverEnableFuse = async (isRetry: boolean) => { } else { await T.RPCGen.installInstallKBFSRpcPromise() // restarts kbfsfuse await T.RPCGen.kbfsMountWaitForMountsRpcPromise() - useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() + useFSState.getState().dispatch.defer.refreshDriverStatusDesktop?.() } } @@ -223,7 +223,7 @@ const uninstallDokanConfirm = async () => { } if (!driverStatus.dokanUninstallExecPath) { await uninstallDokanDialog?.() - useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() + useFSState.getState().dispatch.defer.refreshDriverStatusDesktop?.() return } useFSState.getState().dispatch.driverDisabling() @@ -237,7 +237,7 @@ const onUninstallDokan = async () => { try { await uninstallDokan?.(execPath) } catch {} - useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() + useFSState.getState().dispatch.defer.refreshDriverStatusDesktop?.() } // Invoking the cached installer package has to happen from the topmost process @@ -246,7 +246,7 @@ const onUninstallDokan = async () => { const onInstallCachedDokan = async () => { try { await installCachedDokan?.() - useFSState.getState().dispatch.dynamic.refreshDriverStatusDesktop?.() + useFSState.getState().dispatch.defer.refreshDriverStatusDesktop?.() } catch (e) { errorToActionOrThrow(e) } @@ -254,10 +254,10 @@ const onInstallCachedDokan = async () => { export const initPlatformListener = () => { useConfigState.setState(s => { - s.dispatch.dynamic.dumpLogsNative = dumpLogs - s.dispatch.dynamic.showMainNative = wrapErrors(() => showMainWindow?.()) - s.dispatch.dynamic.copyToClipboard = wrapErrors((s: string) => copyToClipboard?.(s)) - s.dispatch.dynamic.onEngineConnectedDesktop = wrapErrors(() => { + s.dispatch.defer.dumpLogsNative = dumpLogs + s.dispatch.defer.showMainNative = wrapErrors(() => showMainWindow?.()) + s.dispatch.defer.copyToClipboard = wrapErrors((s: string) => copyToClipboard?.(s)) + s.dispatch.defer.onEngineConnectedDesktop = wrapErrors(() => { // Introduce ourselves to the service const f = async () => { await T.RPCGen.configHelloIAmRpcPromise({details: KB2.constants.helloDetails}) @@ -410,7 +410,7 @@ export const initPlatformListener = () => { }) useFSState.setState(s => { - s.dispatch.dynamic.uploadFromDragAndDropDesktop = wrapErrors( + s.dispatch.defer.uploadFromDragAndDropDesktop = wrapErrors( (parentPath: T.FS.Path, localPaths: string[]) => { const {upload} = useFSState.getState().dispatch const f = async () => { @@ -428,7 +428,7 @@ export const initPlatformListener = () => { } ) - s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop = wrapErrors((localPath: string) => { + s.dispatch.defer.openLocalPathInSystemFileManagerDesktop = wrapErrors((localPath: string) => { const f = async () => { try { if (getPathType) { @@ -442,7 +442,7 @@ export const initPlatformListener = () => { ignorePromise(f()) }) - s.dispatch.dynamic.openPathInSystemFileManagerDesktop = wrapErrors((path: T.FS.Path) => { + s.dispatch.defer.openPathInSystemFileManagerDesktop = wrapErrors((path: T.FS.Path) => { const f = async () => { const {sfmi, pathItems} = useFSState.getState() return sfmi.driverStatus.type === T.FS.DriverStatusType.Enabled && sfmi.directMountDir @@ -466,7 +466,7 @@ export const initPlatformListener = () => { ignorePromise(f()) }) - s.dispatch.dynamic.refreshDriverStatusDesktop = wrapErrors(() => { + s.dispatch.defer.refreshDriverStatusDesktop = wrapErrors(() => { const f = async () => { let status = await T.RPCGen.installFuseStatusRpcPromise({ bundleVersion: '', @@ -480,7 +480,7 @@ export const initPlatformListener = () => { ignorePromise(f()) }) - s.dispatch.dynamic.refreshMountDirsDesktop = wrapErrors(() => { + s.dispatch.defer.refreshMountDirsDesktop = wrapErrors(() => { const f = async () => { const {sfmi, dispatch} = useFSState.getState() const driverStatus = sfmi.driverStatus @@ -495,16 +495,16 @@ export const initPlatformListener = () => { ignorePromise(f()) }) - s.dispatch.dynamic.setSfmiBannerDismissedDesktop = wrapErrors((dismissed: boolean) => { + s.dispatch.defer.setSfmiBannerDismissedDesktop = wrapErrors((dismissed: boolean) => { const f = async () => { await T.RPCGen.SimpleFSSimpleFSSetSfmiBannerDismissedRpcPromise({dismissed}) } ignorePromise(f()) }) - s.dispatch.dynamic.afterDriverEnabled = wrapErrors((isRetry: boolean) => { + s.dispatch.defer.afterDriverEnabled = wrapErrors((isRetry: boolean) => { const f = async () => { - useFSState.getState().dispatch.dynamic.setSfmiBannerDismissedDesktop?.(false) + useFSState.getState().dispatch.defer.setSfmiBannerDismissedDesktop?.(false) if (isWindows) { await onInstallCachedDokan() } else { @@ -514,9 +514,9 @@ export const initPlatformListener = () => { ignorePromise(f()) }) - s.dispatch.dynamic.afterDriverDisable = wrapErrors(() => { + s.dispatch.defer.afterDriverDisable = wrapErrors(() => { const f = async () => { - useFSState.getState().dispatch.dynamic.setSfmiBannerDismissedDesktop?.(false) + useFSState.getState().dispatch.defer.setSfmiBannerDismissedDesktop?.(false) if (isWindows) { await uninstallDokanConfirm() } else { @@ -526,7 +526,7 @@ export const initPlatformListener = () => { ignorePromise(f()) }) - s.dispatch.dynamic.afterDriverDisabling = wrapErrors(() => { + s.dispatch.defer.afterDriverDisabling = wrapErrors(() => { const f = async () => { if (isWindows) { await onUninstallDokan() @@ -537,14 +537,14 @@ export const initPlatformListener = () => { ignorePromise(f()) }) - s.dispatch.dynamic.openSecurityPreferencesDesktop = wrapErrors(() => { + s.dispatch.defer.openSecurityPreferencesDesktop = wrapErrors(() => { const f = async () => { await openURL?.('x-apple.systempreferences:com.apple.preference.security?General', {activate: true}) } ignorePromise(f()) }) - s.dispatch.dynamic.openFilesFromWidgetDesktop = wrapErrors((path: T.FS.Path) => { + s.dispatch.defer.openFilesFromWidgetDesktop = wrapErrors((path: T.FS.Path) => { useConfigState.getState().dispatch.showMain() if (path) { Constants.navToPath(path) @@ -553,7 +553,7 @@ export const initPlatformListener = () => { } }) - s.dispatch.dynamic.openAndUploadDesktop = wrapErrors( + s.dispatch.defer.openAndUploadDesktop = wrapErrors( (type: T.FS.OpenDialogType, parentPath: T.FS.Path) => { const f = async () => { const localPaths = await (selectFilesToUploadDialog?.(type, parentPath ?? undefined) ?? @@ -565,15 +565,15 @@ export const initPlatformListener = () => { ) if (!isLinux) { - s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged = wrapErrors(() => { + s.dispatch.defer.afterKbfsDaemonRpcStatusChanged = wrapErrors(() => { const {kbfsDaemonStatus, dispatch} = useFSState.getState() if (kbfsDaemonStatus.rpcStatus === T.FS.KbfsDaemonRpcStatus.Connected) { - dispatch.dynamic.refreshDriverStatusDesktop?.() + dispatch.defer.refreshDriverStatusDesktop?.() } - dispatch.dynamic.refreshMountDirsDesktop?.() + dispatch.defer.refreshMountDirsDesktop?.() }) // force call as it could have happened already - s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged() + s.dispatch.defer.afterKbfsDaemonRpcStatusChanged() } }) diff --git a/shared/constants/init/index.native.tsx b/shared/constants/init/index.native.tsx index 9504f03afe6c..73ac54d22fad 100644 --- a/shared/constants/init/index.native.tsx +++ b/shared/constants/init/index.native.tsx @@ -242,7 +242,7 @@ export const onEngineIncoming = (action: EngineGen.Actions) => { export const initPlatformListener = () => { let _lastPersist = '' useConfigState.setState(s => { - s.dispatch.dynamic.persistRoute = wrapErrors((path?: ReadonlyArray) => { + s.dispatch.defer.persistRoute = wrapErrors((path?: ReadonlyArray) => { const f = async () => { if (!useConfigState.getState().startup.loaded) { return @@ -313,7 +313,7 @@ export const initPlatformListener = () => { }) useConfigState.setState(s => { - s.dispatch.dynamic.copyToClipboard = wrapErrors((s: string) => { + s.dispatch.defer.copyToClipboard = wrapErrors((s: string) => { Clipboard.setStringAsync(s) .then(() => {}) .catch(() => {}) @@ -352,10 +352,10 @@ export const initPlatformListener = () => { }) useConfigState.setState(s => { - s.dispatch.dynamic.onFilePickerError = wrapErrors((error: Error) => { + s.dispatch.defer.onFilePickerError = wrapErrors((error: Error) => { Alert.alert('Error', String(error)) }) - s.dispatch.dynamic.openAppStore = wrapErrors(() => { + s.dispatch.defer.openAppStore = wrapErrors(() => { Linking.openURL( isAndroid ? 'http://play.google.com/store/apps/details?id=io.keybase.ossifrage' @@ -412,7 +412,7 @@ export const initPlatformListener = () => { }) useConfigState.setState(s => { - s.dispatch.dynamic.showShareActionSheet = wrapErrors( + s.dispatch.defer.showShareActionSheet = wrapErrors( (filePath: string, message: string, mimeType: string) => { const f = async () => { await showShareActionSheet({filePath, message, mimeType}) @@ -448,7 +448,7 @@ export const initPlatformListener = () => { const f = async () => { await timeoutPromise(1000) const path = getVisiblePath() - useConfigState.getState().dispatch.dynamic.persistRoute?.(path) + useConfigState.getState().dispatch.defer.persistRoute?.(path) } if (!calledShareListenersRegistered && logState().loggedIn) { @@ -479,7 +479,7 @@ export const initPlatformListener = () => { } useConfigState.setState(s => { - s.dispatch.dynamic.openAppSettings = wrapErrors(() => { + s.dispatch.defer.openAppSettings = wrapErrors(() => { const f = async () => { if (isAndroid) { androidOpenSettings() @@ -498,7 +498,7 @@ export const initPlatformListener = () => { }) useRouterState.setState(s => { - s.dispatch.dynamic.tabLongPress = wrapErrors((tab: string) => { + s.dispatch.defer.tabLongPress = wrapErrors((tab: string) => { if (tab !== Tabs.peopleTab) return const accountRows = useConfigState.getState().configuredAccounts const current = useCurrentUserState.getState().username @@ -511,7 +511,7 @@ export const initPlatformListener = () => { }) useFSState.setState(s => { - s.dispatch.dynamic.pickAndUploadMobile = wrapErrors( + s.dispatch.defer.pickAndUploadMobile = wrapErrors( (type: T.FS.MobilePickType, parentPath: T.FS.Path) => { const f = async () => { try { @@ -528,7 +528,7 @@ export const initPlatformListener = () => { } ) - s.dispatch.dynamic.finishedDownloadWithIntentMobile = wrapErrors( + s.dispatch.defer.finishedDownloadWithIntentMobile = wrapErrors( (downloadID: string, downloadIntent: T.FS.DownloadIntent, mimeType: string) => { const f = async () => { const {downloads, dispatch} = useFSState.getState() @@ -570,7 +570,7 @@ export const initPlatformListener = () => { if (isAndroid) { useFSState.setState(s => { - s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged = wrapErrors(() => { + s.dispatch.defer.afterKbfsDaemonRpcStatusChanged = wrapErrors(() => { const f = async () => { await T.RPCGen.SimpleFSSimpleFSConfigureDownloadRpcPromise({ // Android's cache dir is (when I tried) [app]/cache but Go side uses @@ -582,9 +582,9 @@ export const initPlatformListener = () => { ignorePromise(f()) }) // needs to be called, TODO could make this better - s.dispatch.dynamic.afterKbfsDaemonRpcStatusChanged() + s.dispatch.defer.afterKbfsDaemonRpcStatusChanged() - s.dispatch.dynamic.finishedRegularDownloadMobile = wrapErrors( + s.dispatch.defer.finishedRegularDownloadMobile = wrapErrors( (downloadID: string, mimeType: string) => { const f = async () => { // This is fired from a hook and can happen more than once per downloadID. diff --git a/shared/constants/init/shared.tsx b/shared/constants/init/shared.tsx index 747feabf1c07..8f7c99df08b7 100644 --- a/shared/constants/init/shared.tsx +++ b/shared/constants/init/shared.tsx @@ -140,8 +140,8 @@ export const initTeamBuildingCallbacks = () => { store.setState({ dispatch: { ...currentState.dispatch, - dynamic: { - ...currentState.dispatch.dynamic, + defer: { + ...currentState.dispatch.defer, ...commonCallbacks, ...(namespace === 'chat2' ? { @@ -168,7 +168,7 @@ export const initAutoResetCallbacks = () => { useAutoResetState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { + defer: { onGetRecoverPasswordUsername: () => { return storeRegistry.getState('recover-password').username }, @@ -185,7 +185,7 @@ export const initChat2Callbacks = () => { useChatState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { + defer: { onGetDaemonState: () => { const daemonState = storeRegistry.getState('daemon') return {dispatch: daemonState.dispatch, handshakeVersion: daemonState.handshakeVersion} @@ -215,8 +215,8 @@ export const initTeamsCallbacks = () => { useTeamsState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { - ...currentState.dispatch.dynamic, + defer: { + ...currentState.dispatch.defer, onChatNavigateToInbox: (allowSwitchTab?: boolean) => { storeRegistry.getState('chat').dispatch.navigateToInbox(allowSwitchTab) }, @@ -238,8 +238,8 @@ export const initFSCallbacks = () => { useFSState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { - ...currentState.dispatch.dynamic, + defer: { + ...currentState.dispatch.defer, onBadgeApp: (key: 'kbfsUploading' | 'outOfSpace', on: boolean) => { useNotifState.getState().dispatch.badgeApp(key, on) }, @@ -256,8 +256,8 @@ export const initNotificationsCallbacks = () => { useNotifState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { - ...currentState.dispatch.dynamic, + defer: { + ...currentState.dispatch.defer, onFavoritesLoad: () => { useFSState.getState().dispatch.favoritesLoad() }, @@ -271,8 +271,8 @@ export const initProfileCallbacks = () => { useProfileState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { - ...currentState.dispatch.dynamic, + defer: { + ...currentState.dispatch.defer, onTracker2GetDetails: (username: string) => { return useTrackerState.getState().getDetails(username) }, @@ -297,8 +297,8 @@ export const initPushCallbacks = () => { usePushState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { - ...currentState.dispatch.dynamic, + defer: { + ...currentState.dispatch.defer, onGetDaemonHandshakeState: () => { return useDaemonState.getState().handshakeState }, @@ -324,8 +324,8 @@ export const initRecoverPasswordCallbacks = () => { useRecoverPasswordState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { - ...currentState.dispatch.dynamic, + defer: { + ...currentState.dispatch.defer, onProvisionCancel: (ignoreWarning?: boolean) => { useProvisionState.getState().dispatch.dynamic.cancel?.(ignoreWarning) }, @@ -342,8 +342,8 @@ export const initSignupCallbacks = () => { useSignupState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { - ...currentState.dispatch.dynamic, + defer: { + ...currentState.dispatch.defer, onEditEmail: (p: {email: string; makeSearchable: boolean}) => { useSettingsEmailState.getState().dispatch.editEmail(p) }, @@ -360,8 +360,8 @@ export const initTracker2Callbacks = () => { useTrackerState.setState({ dispatch: { ...currentState.dispatch, - dynamic: { - ...currentState.dispatch.dynamic, + defer: { + ...currentState.dispatch.defer, onShowUserProfile: (username: string) => { useProfileState.getState().dispatch.showUserProfile(username) }, diff --git a/shared/crypto/output.tsx b/shared/crypto/output.tsx index 435d0edd901c..6510f136f84b 100644 --- a/shared/crypto/output.tsx +++ b/shared/crypto/output.tsx @@ -181,7 +181,7 @@ export const OutputActionsBar = (props: OutputActionsBarProps) => { const actionsDisabled = waiting || !outputValid const openLocalPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop + s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop ) const onShowInFinder = () => { openLocalPathInSystemFileManagerDesktop?.(output.stringValue()) @@ -194,7 +194,7 @@ export const OutputActionsBar = (props: OutputActionsBarProps) => { previewConversation({participants: [username.stringValue()], reason: 'search'}) } - const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard) + const copyToClipboard = useConfigState(s => s.dispatch.defer.copyToClipboard) const onCopyOutput = () => { copyToClipboard(output.stringValue()) } @@ -369,7 +369,7 @@ export const OperationOutput = (props: OutputProps) => { const output = _output.stringValue() const openLocalPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop + s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop ) const onShowInFinder = () => { if (!output) return diff --git a/shared/desktop/renderer/main2.desktop.tsx b/shared/desktop/renderer/main2.desktop.tsx index 329d55bb0b53..e2d29cd73822 100644 --- a/shared/desktop/renderer/main2.desktop.tsx +++ b/shared/desktop/renderer/main2.desktop.tsx @@ -120,7 +120,7 @@ const eventFromRemoteWindows = (action: RemoteGen.Actions) => { break } case RemoteGen.openFilesFromWidget: { - storeRegistry.getState('fs').dispatch.dynamic.openFilesFromWidgetDesktop?.(action.payload.path) + storeRegistry.getState('fs').dispatch.defer.openFilesFromWidgetDesktop?.(action.payload.path) break } case RemoteGen.saltpackFileOpen: { @@ -136,7 +136,7 @@ const eventFromRemoteWindows = (action: RemoteGen.Actions) => { break } case RemoteGen.openPathInSystemFileManager: { - storeRegistry.getState('fs').dispatch.dynamic.openPathInSystemFileManagerDesktop?.(action.payload.path) + storeRegistry.getState('fs').dispatch.defer.openPathInSystemFileManagerDesktop?.(action.payload.path) break } case RemoteGen.unlockFoldersSubmitPaperKey: { diff --git a/shared/fs/banner/conflict-banner.tsx b/shared/fs/banner/conflict-banner.tsx index c39440d9d96c..c43e0333121f 100644 --- a/shared/fs/banner/conflict-banner.tsx +++ b/shared/fs/banner/conflict-banner.tsx @@ -33,7 +33,7 @@ const ConnectedBanner = (ownProps: OwnProps) => { }, [startManualConflictResolution, path]) const openPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openPathInSystemFileManagerDesktop + s => s.dispatch.defer.openPathInSystemFileManagerDesktop ) const openInSystemFileManager = React.useCallback( diff --git a/shared/fs/banner/system-file-manager-integration-banner/container.tsx b/shared/fs/banner/system-file-manager-integration-banner/container.tsx index 0114e131cbad..232e32b74c5d 100644 --- a/shared/fs/banner/system-file-manager-integration-banner/container.tsx +++ b/shared/fs/banner/system-file-manager-integration-banner/container.tsx @@ -14,7 +14,7 @@ const SFMIContainer = (op: OwnProps) => { driverDisable: s.dispatch.driverDisable, driverEnable: s.dispatch.driverEnable, driverStatus: s.sfmi.driverStatus, - setSfmiBannerDismissedDesktop: s.dispatch.dynamic.setSfmiBannerDismissedDesktop, + setSfmiBannerDismissedDesktop: s.dispatch.defer.setSfmiBannerDismissedDesktop, settings: s.settings, })) ) @@ -218,7 +218,7 @@ const JustEnabled = ({onDismiss}: JustEnabledProps) => { const {displayingMountDir, openLocalPathInSystemFileManagerDesktop} = useFSState( C.useShallow(s => ({ displayingMountDir: s.sfmi.preferredMountDirs[0] ?? '', - openLocalPathInSystemFileManagerDesktop: s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop, + openLocalPathInSystemFileManagerDesktop: s.dispatch.defer.openLocalPathInSystemFileManagerDesktop, })) ) const open = displayingMountDir diff --git a/shared/fs/banner/system-file-manager-integration-banner/kext-permission-popup.tsx b/shared/fs/banner/system-file-manager-integration-banner/kext-permission-popup.tsx index 7898cf2ca82c..c294c7b776ea 100644 --- a/shared/fs/banner/system-file-manager-integration-banner/kext-permission-popup.tsx +++ b/shared/fs/banner/system-file-manager-integration-banner/kext-permission-popup.tsx @@ -6,7 +6,7 @@ import {useFSState} from '@/stores/fs' const InstallSecurityPrefs = () => { const driverStatus = useFSState(s => s.sfmi.driverStatus) - const openSecurityPreferencesDesktop = useFSState(s => s.dispatch.dynamic.openSecurityPreferencesDesktop) + const openSecurityPreferencesDesktop = useFSState(s => s.dispatch.defer.openSecurityPreferencesDesktop) const onCancel = C.useRouterState(s => s.dispatch.navigateUp) const openSecurityPrefs = React.useCallback( () => openSecurityPreferencesDesktop?.(), diff --git a/shared/fs/browser/index.tsx b/shared/fs/browser/index.tsx index b8dff985b6d0..29410ae9c1bc 100644 --- a/shared/fs/browser/index.tsx +++ b/shared/fs/browser/index.tsx @@ -68,7 +68,7 @@ const DragAndDrop = React.memo(function DragAndDrop(p: { rejectReason?: string }) { const {children, path, rejectReason} = p - const uploadFromDragAndDrop = useFSState(s => s.dispatch.dynamic.uploadFromDragAndDropDesktop) + const uploadFromDragAndDrop = useFSState(s => s.dispatch.defer.uploadFromDragAndDropDesktop) const onAttach = React.useCallback( (localPaths: Array) => uploadFromDragAndDrop?.(path, localPaths), [path, uploadFromDragAndDrop] diff --git a/shared/fs/common/hooks.tsx b/shared/fs/common/hooks.tsx index 95edbb6d8778..bb30566beb4f 100644 --- a/shared/fs/common/hooks.tsx +++ b/shared/fs/common/hooks.tsx @@ -185,8 +185,8 @@ export const useFsWatchDownloadForMobile = C.isMobile const {dlState, finishedDownloadWithIntentMobile, finishedRegularDownloadMobile} = useFSState( C.useShallow(s => ({ dlState: s.downloads.state.get(downloadID) || FS.emptyDownloadState, - finishedDownloadWithIntentMobile: s.dispatch.dynamic.finishedDownloadWithIntentMobile, - finishedRegularDownloadMobile: s.dispatch.dynamic.finishedRegularDownloadMobile, + finishedDownloadWithIntentMobile: s.dispatch.defer.finishedDownloadWithIntentMobile, + finishedRegularDownloadMobile: s.dispatch.defer.finishedRegularDownloadMobile, })) ) const finished = dlState !== FS.emptyDownloadState && !FS.downloadIsOngoing(dlState) diff --git a/shared/fs/common/open-in-system-file-manager.tsx b/shared/fs/common/open-in-system-file-manager.tsx index c45d43352971..44daf606fd2e 100644 --- a/shared/fs/common/open-in-system-file-manager.tsx +++ b/shared/fs/common/open-in-system-file-manager.tsx @@ -9,7 +9,7 @@ type Props = {path: T.FS.Path} const OpenInSystemFileManager = React.memo(function OpenInSystemFileManager({path}: Props) { const openPathInSystemFileManagerDesktop = useFSState( - s => s.dispatch.dynamic.openPathInSystemFileManagerDesktop + s => s.dispatch.defer.openPathInSystemFileManagerDesktop ) const openInSystemFileManager = React.useCallback( () => openPathInSystemFileManagerDesktop?.(path), diff --git a/shared/fs/common/path-item-action/menu-container.tsx b/shared/fs/common/path-item-action/menu-container.tsx index 9a7e2f751dd5..74d8f8c7180b 100644 --- a/shared/fs/common/path-item-action/menu-container.tsx +++ b/shared/fs/common/path-item-action/menu-container.tsx @@ -32,7 +32,7 @@ const Container = (op: OwnProps) => { const fileContext = s.fileContext.get(path) || FS.emptyFileContext const {cancelDownload, setPathItemActionMenuView, download, newFolderRow} = s.dispatch const {favoriteIgnore, startRename, dismissDownload} = s.dispatch - const {openPathInSystemFileManagerDesktop} = s.dispatch.dynamic + const {openPathInSystemFileManagerDesktop} = s.dispatch.defer const sfmiEnabled = s.sfmi.driverStatus.type === T.FS.DriverStatusType.Enabled return { cancelDownload, diff --git a/shared/fs/common/refresh-driver-status-on-mount.tsx b/shared/fs/common/refresh-driver-status-on-mount.tsx index c4739b49fa67..a710da6894c8 100644 --- a/shared/fs/common/refresh-driver-status-on-mount.tsx +++ b/shared/fs/common/refresh-driver-status-on-mount.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import {useFSState} from '@/stores/fs' const RefreshDriverStatusOnMount = () => { - const refreshDriverStatusDesktop = useFSState(s => s.dispatch.dynamic.refreshDriverStatusDesktop) + const refreshDriverStatusDesktop = useFSState(s => s.dispatch.defer.refreshDriverStatusDesktop) const refresh = React.useCallback(() => refreshDriverStatusDesktop?.(), [refreshDriverStatusDesktop]) React.useEffect(() => { diff --git a/shared/fs/common/upload-button.tsx b/shared/fs/common/upload-button.tsx index c335b8e84126..3021fbfbfa05 100644 --- a/shared/fs/common/upload-button.tsx +++ b/shared/fs/common/upload-button.tsx @@ -73,8 +73,8 @@ const UploadButton = (props: UploadButtonProps) => { const Container = (ownProps: OwnProps) => { const _pathItem = useFSState(s => FS.getPathItem(s.pathItems, ownProps.path)) - const openAndUploadDesktop = useFSState(s => s.dispatch.dynamic.openAndUploadDesktop) - const pickAndUploadMobile = useFSState(s => s.dispatch.dynamic.pickAndUploadMobile) + const openAndUploadDesktop = useFSState(s => s.dispatch.defer.openAndUploadDesktop) + const pickAndUploadMobile = useFSState(s => s.dispatch.defer.pickAndUploadMobile) const _openAndUploadBoth = () => { openAndUploadDesktop?.(T.FS.OpenDialogType.Both, ownProps.path) } diff --git a/shared/fs/filepreview/default-view.tsx b/shared/fs/filepreview/default-view.tsx index 70b01d0109ac..3fa036521c01 100644 --- a/shared/fs/filepreview/default-view.tsx +++ b/shared/fs/filepreview/default-view.tsx @@ -19,7 +19,7 @@ const Container = (ownProps: OwnProps) => { C.useShallow(s => ({ _download: s.dispatch.download, fileContext: s.fileContext.get(path) || FS.emptyFileContext, - openPathInSystemFileManagerDesktop: s.dispatch.dynamic.openPathInSystemFileManagerDesktop, + openPathInSystemFileManagerDesktop: s.dispatch.defer.openPathInSystemFileManagerDesktop, pathItem: FS.getPathItem(s.pathItems, path), sfmiEnabled: s.sfmi.driverStatus.type === T.FS.DriverStatusType.Enabled, })) diff --git a/shared/fs/footer/download.tsx b/shared/fs/footer/download.tsx index 062e69bc0a46..9cf91a45cefb 100644 --- a/shared/fs/footer/download.tsx +++ b/shared/fs/footer/download.tsx @@ -37,7 +37,7 @@ const Download = (props: Props) => { cancelDownload: s.dispatch.cancelDownload, dismissDownload: s.dispatch.dismissDownload, dlState: s.downloads.state.get(props.downloadID) || FS.emptyDownloadState, - openLocalPathInSystemFileManagerDesktop: s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop, + openLocalPathInSystemFileManagerDesktop: s.dispatch.defer.openLocalPathInSystemFileManagerDesktop, })) ) const open = dlState.localPath diff --git a/shared/fs/footer/downloads.tsx b/shared/fs/footer/downloads.tsx index bee401a9f534..f00942abd8b0 100644 --- a/shared/fs/footer/downloads.tsx +++ b/shared/fs/footer/downloads.tsx @@ -33,7 +33,7 @@ const Desktop = () => { const {downloadIDs, openLocalPathInSystemFileManagerDesktop} = useFSState( C.useShallow(s => ({ downloadIDs: s.downloads.regularDownloads, - openLocalPathInSystemFileManagerDesktop: s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop, + openLocalPathInSystemFileManagerDesktop: s.dispatch.defer.openLocalPathInSystemFileManagerDesktop, })) ) const openDownloadFolder = () => openLocalPathInSystemFileManagerDesktop?.(C.downloadFolder) diff --git a/shared/profile/post-proof.tsx b/shared/profile/post-proof.tsx index 7f52f1b555be..74f1cc9fd63c 100644 --- a/shared/profile/post-proof.tsx +++ b/shared/profile/post-proof.tsx @@ -49,7 +49,7 @@ const Container = () => { break } const platformUserName = username - const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard) + const copyToClipboard = useConfigState(s => s.dispatch.defer.copyToClipboard) const clearModals = C.useRouterState(s => s.dispatch.clearModals) const onCancel = () => { clearModals() diff --git a/shared/provision/code-page/qr-scan/not-authorized.tsx b/shared/provision/code-page/qr-scan/not-authorized.tsx index 35f641e2827a..cdd21978b3b4 100644 --- a/shared/provision/code-page/qr-scan/not-authorized.tsx +++ b/shared/provision/code-page/qr-scan/not-authorized.tsx @@ -2,7 +2,7 @@ import * as Kb from '@/common-adapters' import {useConfigState} from '@/stores/config' const QRScanNotAuthorized = () => { - const onOpenSettings = useConfigState(s => s.dispatch.dynamic.openAppSettings) + const onOpenSettings = useConfigState(s => s.dispatch.defer.openAppSettings) return ( diff --git a/shared/router-v2/router.native.tsx b/shared/router-v2/router.native.tsx index b6b3cf21b97c..53099d8043d7 100644 --- a/shared/router-v2/router.native.tsx +++ b/shared/router-v2/router.native.tsx @@ -68,7 +68,7 @@ const tabStacks = tabs.map(tab => ( name={tab} listeners={{ tabLongPress: () => { - C.useRouterState.getState().dispatch.dynamic.tabLongPress?.(tab) + C.useRouterState.getState().dispatch.defer.tabLongPress?.(tab) }, }} component={TabStack} diff --git a/shared/settings/archive/index.tsx b/shared/settings/archive/index.tsx index b4953431cd93..ab07df9512c9 100644 --- a/shared/settings/archive/index.tsx +++ b/shared/settings/archive/index.tsx @@ -30,7 +30,7 @@ const ChatJob = React.memo(function ChatJob(p: {index: number; id: string}) { resume(id) }, [resume, id]) - const openFinder = useFSState(s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop) + const openFinder = useFSState(s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop) const onShowFinder = React.useCallback(() => { if (!job) return openFinder?.(job.outPath) @@ -153,7 +153,7 @@ const KBFSJob = React.memo(function KBFSJob(p: {index: number; id: string}) { loadKBFSJobFreshness(id) }) - const openFinder = useFSState(s => s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop) + const openFinder = useFSState(s => s.dispatch.defer.openLocalPathInSystemFileManagerDesktop) const onShowFinder = React.useCallback(() => { if (Kb.Styles.isMobile || !job) { return diff --git a/shared/settings/files/index.desktop.tsx b/shared/settings/files/index.desktop.tsx index 02c9475c612e..f62f7811fba2 100644 --- a/shared/settings/files/index.desktop.tsx +++ b/shared/settings/files/index.desktop.tsx @@ -58,7 +58,7 @@ const FinderIntegration = () => { C.useShallow(s => ({ driverDisable: s.dispatch.driverDisable, driverStatus: s.sfmi.driverStatus, - openLocalPathInSystemFileManagerDesktop: s.dispatch.dynamic.openLocalPathInSystemFileManagerDesktop, + openLocalPathInSystemFileManagerDesktop: s.dispatch.defer.openLocalPathInSystemFileManagerDesktop, preferredMountDirs: s.sfmi.preferredMountDirs, })) ) diff --git a/shared/settings/manage-contacts.tsx b/shared/settings/manage-contacts.tsx index aca33a0abc2f..47cd4f558a43 100644 --- a/shared/settings/manage-contacts.tsx +++ b/shared/settings/manage-contacts.tsx @@ -72,7 +72,7 @@ const ManageContactsBanner = () => { status: s.permissionStatus, })) ) - const onOpenAppSettings = useConfigState(s => s.dispatch.dynamic.openAppSettings) + const onOpenAppSettings = useConfigState(s => s.dispatch.defer.openAppSettings) const {appendNewChatBuilder, navigateAppend, switchTab} = C.useRouterState( C.useShallow(s => ({ appendNewChatBuilder: s.appendNewChatBuilder, diff --git a/shared/stores/autoreset.tsx b/shared/stores/autoreset.tsx index 1120b55e5b04..5c066b41a4e5 100644 --- a/shared/stores/autoreset.tsx +++ b/shared/stores/autoreset.tsx @@ -32,7 +32,7 @@ const initialStore: Store = { export interface State extends Store { dispatch: { cancelReset: () => void - dynamic: { + defer: { onGetRecoverPasswordUsername: () => string onStartProvision: (username: string, fromReset: boolean) => void } @@ -85,7 +85,7 @@ export const useAutoResetState = Z.createZustand((set, get) => { } ignorePromise(f()) }, - dynamic: { + defer: { onGetRecoverPasswordUsername: () => { throw new Error('onGetRecoverPasswordUsername not properly initialized') }, @@ -129,7 +129,7 @@ export const useAutoResetState = Z.createZustand((set, get) => { set(s => { s.error = '' }) - get().dispatch.dynamic.onStartProvision(get().username, true) + get().dispatch.defer.onStartProvision(get().username, true) } else { navUpToScreen('login') } @@ -175,7 +175,7 @@ export const useAutoResetState = Z.createZustand((set, get) => { }, resetState: 'default', startAccountReset: (skipPassword, _username) => { - const username = _username || get().dispatch.dynamic.onGetRecoverPasswordUsername() || '' + const username = _username || get().dispatch.defer.onGetRecoverPasswordUsername() || '' set(s => { s.skipPassword = skipPassword s.error = '' diff --git a/shared/stores/chat2.tsx b/shared/stores/chat2.tsx index 6c83479ae0f7..24c548599ed0 100644 --- a/shared/stores/chat2.tsx +++ b/shared/stores/chat2.tsx @@ -113,7 +113,7 @@ export const getBotsAndParticipants = ( ) => { const isAdhocTeam = meta.teamType === 'adhoc' const teamMembers = - useChatState.getState().dispatch.dynamic.onGetTeamsTeamIDToMembers(meta.teamID) ?? + useChatState.getState().dispatch.defer.onGetTeamsTeamIDToMembers(meta.teamID) ?? new Map() let bots: Array = [] if (isAdhocTeam) { @@ -290,7 +290,7 @@ export interface State extends Store { dispatch: { badgesUpdated: (badgeState?: T.RPCGen.BadgeState) => void clearMetas: () => void - dynamic: { + defer: { onGetDaemonState: () => {handshakeVersion: number; dispatch: any} onGetTeamsTeamIDToMembers: ( teamID: T.Teams.TeamID @@ -492,7 +492,7 @@ export const useChatState = Z.createZustand((set, get) => { } ignorePromise(f()) }, - dynamic: { + defer: { onGetDaemonState: () => { throw new Error('onGetDaemonState not properly initialized') }, @@ -845,7 +845,7 @@ export const useChatState = Z.createZustand((set, get) => { if (get().staticConfig) { return } - const {handshakeVersion, dispatch} = get().dispatch.dynamic.onGetDaemonState() + const {handshakeVersion, dispatch} = get().dispatch.defer.onGetDaemonState() const f = async () => { const name = 'chat.loadStatic' dispatch.wait(name, handshakeVersion, true) @@ -984,8 +984,8 @@ export const useChatState = Z.createZustand((set, get) => { const {isMetaGood, meta} = storeRegistry.getConvoState(selectedConversation) if (isMetaGood()) { const {teamID} = meta - if (!get().dispatch.dynamic.onGetTeamsTeamIDToMembers(teamID) && meta.teamname) { - get().dispatch.dynamic.onTeamsGetMembers(teamID) + if (!get().dispatch.defer.onGetTeamsTeamIDToMembers(teamID) && meta.teamname) { + get().dispatch.defer.onTeamsGetMembers(teamID) } } }, @@ -1158,7 +1158,7 @@ export const useChatState = Z.createZustand((set, get) => { const usernames = update.CanonicalName.split(',') const broken = (update.breaks.breaks || []).map(b => b.user.username) const updates = usernames.map(name => ({info: {broken: broken.includes(name)}, name})) - get().dispatch.dynamic.onUsersUpdates(updates) + get().dispatch.defer.onUsersUpdates(updates) break } case EngineGen.chat1ChatUiChatInboxUnverified: @@ -1345,7 +1345,7 @@ export const useChatState = Z.createZustand((set, get) => { cs.dispatch.setMeta(meta) } }) - get().dispatch.dynamic.onTeamsUpdateTeamRetentionPolicy(metas) + get().dispatch.defer.onTeamsUpdateTeamRetentionPolicy(metas) } // this is a more serious problem, but we don't need to bug the user about it logger.error( @@ -1379,7 +1379,7 @@ export const useChatState = Z.createZustand((set, get) => { }, onGetInboxConvsUnboxed: (action: EngineGen.Chat1ChatUiChatInboxConversationPayload) => { // TODO not reactive - const infoMap = get().dispatch.dynamic.onGetUsersInfoMap() + const infoMap = get().dispatch.defer.onGetUsersInfoMap() const {convs} = action.payload.params const inboxUIItems = JSON.parse(convs) as Array const metas: Array = [] @@ -1407,7 +1407,7 @@ export const useChatState = Z.createZustand((set, get) => { }) }) if (added) { - get().dispatch.dynamic.onUsersUpdates( + get().dispatch.defer.onUsersUpdates( Object.keys(usernameToFullname).map(name => ({ info: {fullname: usernameToFullname[name]}, name, @@ -1442,7 +1442,7 @@ export const useChatState = Z.createZustand((set, get) => { return map }, {}) - get().dispatch.dynamic.onUsersUpdates( + get().dispatch.defer.onUsersUpdates( Object.keys(usernameToFullname).map(name => ({ info: {fullname: usernameToFullname[name]}, name, diff --git a/shared/stores/config.tsx b/shared/stores/config.tsx index 1c4e6112c8ab..e9f2aec25ef6 100644 --- a/shared/stores/config.tsx +++ b/shared/stores/config.tsx @@ -147,7 +147,7 @@ const initialStore: Store = { export interface State extends Store { dispatch: { - dynamic: { + defer: { copyToClipboard: (s: string) => void dumpLogsNative?: (reason: string) => Promise onFilePickerError?: (error: Error) => void @@ -295,10 +295,7 @@ export const useConfigState = Z.createZustand((set, get) => { } ignorePromise(f()) }, - dumpLogs: async reason => { - await get().dispatch.dynamic.dumpLogsNative?.(reason) - }, - dynamic: { + defer: { copyToClipboard: () => { throw new Error('copyToClipboard not implemented?????') }, @@ -312,8 +309,11 @@ export const useConfigState = Z.createZustand((set, get) => { showMainNative: undefined, showShareActionSheet: undefined, }, + dumpLogs: async reason => { + await get().dispatch.defer.dumpLogsNative?.(reason) + }, filePickerError: error => { - get().dispatch.dynamic.onFilePickerError?.(error) + get().dispatch.defer.onFilePickerError?.(error) }, initAppUpdateLoop: () => { const f = async () => { @@ -509,7 +509,7 @@ export const useConfigState = Z.createZustand((set, get) => { } ignorePromise(registerForGregorNotifications()) - get().dispatch.dynamic.onEngineConnectedDesktop?.() + get().dispatch.defer.onEngineConnectedDesktop?.() get().dispatch.loadOnStart('initialStartupAsEarlyAsPossible') }, onEngineIncoming: action => { @@ -854,7 +854,7 @@ export const useConfigState = Z.createZustand((set, get) => { }) }, showMain: () => { - get().dispatch.dynamic.showMainNative?.() + get().dispatch.defer.showMainNative?.() }, toggleRuntimeStats: () => { const f = async () => { diff --git a/shared/stores/convostate.tsx b/shared/stores/convostate.tsx index 189056f6512f..a48c54a4cc79 100644 --- a/shared/stores/convostate.tsx +++ b/shared/stores/convostate.tsx @@ -1245,7 +1245,7 @@ const createSlice = ( blockConversation: reportUser => { const f = async () => { chatStateHook.getState().dispatch.navigateToInbox() - useConfigState.getState().dispatch.dynamic.persistRoute?.() + useConfigState.getState().dispatch.defer.persistRoute?.() await T.RPCChat.localSetConversationStatusLocalRpcPromise({ conversationID: get().getConvID(), identifyBehavior: T.RPCGen.TLFIdentifyBehavior.chatGui, diff --git a/shared/stores/fs.tsx b/shared/stores/fs.tsx index ca53bdd9fa85..f3bdde88ab18 100644 --- a/shared/stores/fs.tsx +++ b/shared/stores/fs.tsx @@ -379,7 +379,7 @@ export interface State extends Store { driverDisabling: () => void driverEnable: (isRetry?: boolean) => void driverKextPermissionError: () => void - dynamic: { + defer: { afterDriverDisable?: () => void afterDriverDisabling?: () => void afterDriverEnabled?: (isRetry: boolean) => void @@ -686,6 +686,30 @@ export const useFSState = Z.createZustand((set, get) => { } ignorePromise(f()) }, + defer: { + afterDriverDisable: undefined, + afterDriverDisabling: undefined, + afterDriverEnabled: undefined, + afterKbfsDaemonRpcStatusChanged: undefined, + finishedDownloadWithIntentMobile: undefined, + finishedRegularDownloadMobile: undefined, + onBadgeApp: () => { + throw new Error('onBadgeApp not implemented') + }, + onSetBadgeCounts: () => { + throw new Error('onSetBadgeCounts not implemented') + }, + openAndUploadDesktop: undefined, + openFilesFromWidgetDesktop: undefined, + openLocalPathInSystemFileManagerDesktop: undefined, + openPathInSystemFileManagerDesktop: undefined, + openSecurityPreferencesDesktop: undefined, + pickAndUploadMobile: undefined, + refreshDriverStatusDesktop: undefined, + refreshMountDirsDesktop: undefined, + setSfmiBannerDismissedDesktop: undefined, + uploadFromDragAndDropDesktop: undefined, + }, deleteFile: path => { const f = async () => { const opID = makeUUID() @@ -743,7 +767,7 @@ export const useFSState = Z.createZustand((set, get) => { ignorePromise(f()) }, driverDisable: () => { - get().dispatch.dynamic.afterDriverDisable?.() + get().dispatch.defer.afterDriverDisable?.() }, driverDisabling: () => { set(s => { @@ -751,7 +775,7 @@ export const useFSState = Z.createZustand((set, get) => { s.sfmi.driverStatus.isDisabling = true } }) - get().dispatch.dynamic.afterDriverDisabling?.() + get().dispatch.defer.afterDriverDisabling?.() }, driverEnable: isRetry => { set(s => { @@ -759,7 +783,7 @@ export const useFSState = Z.createZustand((set, get) => { s.sfmi.driverStatus.isEnabling = true } }) - get().dispatch.dynamic.afterDriverEnabled?.(!!isRetry) + get().dispatch.defer.afterDriverEnabled?.(!!isRetry) }, driverKextPermissionError: () => { set(s => { @@ -769,30 +793,6 @@ export const useFSState = Z.createZustand((set, get) => { } }) }, - dynamic: { - afterDriverDisable: undefined, - afterDriverDisabling: undefined, - afterDriverEnabled: undefined, - afterKbfsDaemonRpcStatusChanged: undefined, - finishedDownloadWithIntentMobile: undefined, - finishedRegularDownloadMobile: undefined, - onBadgeApp: () => { - throw new Error('onBadgeApp not implemented') - }, - onSetBadgeCounts: () => { - throw new Error('onSetBadgeCounts not implemented') - }, - openAndUploadDesktop: undefined, - openFilesFromWidgetDesktop: undefined, - openLocalPathInSystemFileManagerDesktop: undefined, - openPathInSystemFileManagerDesktop: undefined, - openSecurityPreferencesDesktop: undefined, - pickAndUploadMobile: undefined, - refreshDriverStatusDesktop: undefined, - refreshMountDirsDesktop: undefined, - setSfmiBannerDismissedDesktop: undefined, - uploadFromDragAndDropDesktop: undefined, - }, editError: (editID, error) => { set(s => { const e = s.edits.get(editID) @@ -905,7 +905,7 @@ export const useFSState = Z.createZustand((set, get) => { }) const counts = new Map() counts.set(Tabs.fsTab, Constants.computeBadgeNumberForAll(get().tlfs)) - get().dispatch.dynamic.onSetBadgeCounts?.(counts) + get().dispatch.defer.onSetBadgeCounts?.(counts) } } catch (e) { errorToActionOrThrow(e) @@ -1148,7 +1148,7 @@ export const useFSState = Z.createZustand((set, get) => { } subscribeAndLoadJournalStatus() // how this works isn't great. This function gets called way early before we set this - get().dispatch.dynamic.afterKbfsDaemonRpcStatusChanged?.() + get().dispatch.defer.afterKbfsDaemonRpcStatusChanged?.() }, letResetUserBackIn: (id, username) => { const f = async () => { @@ -1645,12 +1645,12 @@ export const useFSState = Z.createZustand((set, get) => { if (totalSyncingBytes <= 0 && !syncingPaths?.length) { break } - get().dispatch.dynamic.onBadgeApp?.('kbfsUploading', true) + get().dispatch.defer.onBadgeApp?.('kbfsUploading', true) await timeoutPromise(getWaitDuration(endEstimate || undefined, 100, 4000)) // 0.1s to 4s } } finally { pollJournalStatusPolling = false - get().dispatch.dynamic.onBadgeApp?.('kbfsUploading', false) + get().dispatch.defer.onBadgeApp?.('kbfsUploading', false) get().dispatch.checkKbfsDaemonRpcStatus() } } @@ -1693,7 +1693,7 @@ export const useFSState = Z.createZustand((set, get) => { set(s => { s.sfmi.driverStatus = driverStatus }) - get().dispatch.dynamic.refreshMountDirsDesktop?.() + get().dispatch.defer.refreshMountDirsDesktop?.() }, setEditName: (editID, name) => { set(s => { @@ -1903,7 +1903,7 @@ export const useFSState = Z.createZustand((set, get) => { body: 'You are out of disk space. Some folders could not be synced.', sound: true, }) - get().dispatch.dynamic.onBadgeApp?.('outOfSpace', status.outOfSyncSpace) + get().dispatch.defer.onBadgeApp?.('outOfSpace', status.outOfSyncSpace) break } case T.FS.DiskSpaceStatus.Warning: diff --git a/shared/stores/notifications.tsx b/shared/stores/notifications.tsx index 1d472d36a83b..ba83285d4302 100644 --- a/shared/stores/notifications.tsx +++ b/shared/stores/notifications.tsx @@ -29,7 +29,7 @@ const initialStore: Store = { export interface State extends Store { dispatch: { - dynamic: { + defer: { onFavoritesLoad?: () => void } onEngineIncomingImpl: (action: EngineGen.Actions) => void @@ -103,7 +103,7 @@ export const useNotifState = Z.createZustand((set, get) => { updateWidgetBadge(s) }) }, - dynamic: { + defer: { onFavoritesLoad: () => { throw new Error('onFavoritesLoad not implemented') }, @@ -133,7 +133,7 @@ export const useNotifState = Z.createZustand((set, get) => { const counts = badgeStateToBadgeCounts(badgeState) if (!isMobile && shouldTriggerTlfLoad(badgeState)) { - get().dispatch.dynamic.onFavoritesLoad?.() + get().dispatch.defer.onFavoritesLoad?.() } if (counts) { get().dispatch.setBadgeCounts(counts) diff --git a/shared/stores/profile.tsx b/shared/stores/profile.tsx index 40df3896e0c8..154178603e1c 100644 --- a/shared/stores/profile.tsx +++ b/shared/stores/profile.tsx @@ -98,12 +98,7 @@ const initialStore: Store = { export interface State extends Store { dispatch: { - dynamic: { - afterCheckProof?: () => void - cancelAddProof?: () => void - cancelPgpGen?: () => void - finishedWithKeyGen?: (shouldStoreKeyOnServer: boolean) => void - submitUsername?: () => void + defer: { onTracker2GetDetails?: (username: string) => T.Tracker.Details | undefined onTracker2Load?: ( params: Parameters['dispatch']['load']>[0] @@ -111,6 +106,13 @@ export interface State extends Store { onTracker2ShowUser?: (username: string, asTracker: boolean, skipNav?: boolean) => void onTracker2UpdateResult?: (guiID: string, result: T.Tracker.DetailsState, reason?: string) => void } + dynamic: { + afterCheckProof?: () => void + cancelAddProof?: () => void + cancelPgpGen?: () => void + finishedWithKeyGen?: (shouldStoreKeyOnServer: boolean) => void + submitUsername?: () => void + } addProof: (platform: string, reason: 'appLink' | 'profile') => void backToProfile: () => void checkProof: () => void @@ -272,7 +274,7 @@ export const useProfileState = Z.createZustand((set, get) => { let canceled = false const loadAfter = () => - get().dispatch.dynamic.onTracker2Load?.({ + get().dispatch.defer.onTracker2Load?.({ assertion: useCurrentUserState.getState().username, guiID: generateGUIID(), inTracker: false, @@ -491,10 +493,7 @@ export const useProfileState = Z.createZustand((set, get) => { clearErrors(s) }) }, - dynamic: { - cancelAddProof: _cancelAddProof, - cancelPgpGen: undefined, - finishedWithKeyGen: undefined, + defer: { onTracker2GetDetails: () => { throw new Error('onTracker2GetDetails not implemented') }, @@ -508,6 +507,11 @@ export const useProfileState = Z.createZustand((set, get) => { throw new Error('onTracker2UpdateResult not implemented') }, }, + dynamic: { + cancelAddProof: _cancelAddProof, + cancelPgpGen: undefined, + finishedWithKeyGen: undefined, + }, editAvatar: () => { throw new Error('This is overloaded by platform specific') }, @@ -521,7 +525,7 @@ export const useProfileState = Z.createZustand((set, get) => { finishRevoking: () => { const username = useCurrentUserState.getState().username get().dispatch.showUserProfile(username) - get().dispatch.dynamic.onTracker2Load?.({ + get().dispatch.defer.onTracker2Load?.({ assertion: useCurrentUserState.getState().username, guiID: generateGUIID(), inTracker: false, @@ -617,7 +621,7 @@ export const useProfileState = Z.createZustand((set, get) => { }) const f = async () => { await T.RPCGen.proveCheckProofRpcPromise({sigID}, S.waitingKeyProfile) - get().dispatch.dynamic.onTracker2ShowUser?.(useCurrentUserState.getState().username, false) + get().dispatch.defer.onTracker2ShowUser?.(useCurrentUserState.getState().username, false) } ignorePromise(f()) }, @@ -644,7 +648,7 @@ export const useProfileState = Z.createZustand((set, get) => { set(s => { s.blockUserModal = undefined }) - get().dispatch.dynamic.onTracker2Load?.({ + get().dispatch.defer.onTracker2Load?.({ assertion: username, guiID: generateGUIID(), inTracker: false, @@ -665,7 +669,7 @@ export const useProfileState = Z.createZustand((set, get) => { }, submitRevokeProof: proofId => { const f = async () => { - const you = get().dispatch.dynamic.onTracker2GetDetails?.(useCurrentUserState.getState().username) + const you = get().dispatch.defer.onTracker2GetDetails?.(useCurrentUserState.getState().username) if (!you?.assertions) return const proof = [...you.assertions.values()].find(a => a.sigID === proofId) if (!proof) return @@ -697,7 +701,7 @@ export const useProfileState = Z.createZustand((set, get) => { const f = async () => { try { await T.RPCGen.userUnblockUserRpcPromise({username}) - get().dispatch.dynamic.onTracker2Load?.({ + get().dispatch.defer.onTracker2Load?.({ assertion: username, guiID: generateGUIID(), inTracker: false, @@ -709,7 +713,7 @@ export const useProfileState = Z.createZustand((set, get) => { } const error = _error logger.warn(`Error unblocking user ${username}`, error) - get().dispatch.dynamic.onTracker2UpdateResult?.( + get().dispatch.defer.onTracker2UpdateResult?.( guiID, 'error', `Failed to unblock ${username}: ${error.desc}` diff --git a/shared/stores/push.d.ts b/shared/stores/push.d.ts index 690c3ebfe63d..29e8b1ff366f 100644 --- a/shared/stores/push.d.ts +++ b/shared/stores/push.d.ts @@ -10,7 +10,7 @@ type Store = T.Immutable<{ export type State = Store & { dispatch: { - dynamic: { + defer: { onGetDaemonHandshakeState?: () => T.Config.DaemonHandshakeState onNavigateToThread?: ( conversationIDKey: T.Chat.ConversationIDKey, diff --git a/shared/stores/push.desktop.tsx b/shared/stores/push.desktop.tsx index 8596722c5f76..4a59a43a8a35 100644 --- a/shared/stores/push.desktop.tsx +++ b/shared/stores/push.desktop.tsx @@ -15,14 +15,14 @@ export const usePushState = Z.createZustand(() => { checkPermissions: async () => { return Promise.resolve(false) }, - deleteToken: () => {}, - dynamic: { + defer: { onGetDaemonHandshakeState: () => { return 'done' }, onNavigateToThread: () => {}, onShowUserProfile: () => {}, }, + deleteToken: () => {}, handlePush: () => {}, initialPermissionsCheck: () => {}, rejectPermissions: () => {}, diff --git a/shared/stores/push.native.tsx b/shared/stores/push.native.tsx index b1f131b7cde1..a2edcc1a8b48 100644 --- a/shared/stores/push.native.tsx +++ b/shared/stores/push.native.tsx @@ -71,7 +71,7 @@ export const usePushState = Z.createZustand((set, get) => { const {conversationIDKey, unboxPayload, membersType} = notification - get().dispatch.dynamic.onNavigateToThread?.(conversationIDKey, 'push', unboxPayload) + get().dispatch.defer.onNavigateToThread?.(conversationIDKey, 'push', unboxPayload) if (unboxPayload && membersType && !isIOS) { try { await T.RPCChat.localUnboxMobilePushNotificationRpcPromise({ @@ -109,6 +109,17 @@ export const usePushState = Z.createZustand((set, get) => { return false } }, + defer: { + onGetDaemonHandshakeState: () => { + throw new Error('onGetDaemonHandshakeState not implemented') + }, + onNavigateToThread: () => { + throw new Error('onNavigateToThread not implemented') + }, + onShowUserProfile: () => { + throw new Error('onShowUserProfile not implemented') + }, + }, deleteToken: version => { const f = async () => { const waitKey = 'push:deleteToken' @@ -135,17 +146,6 @@ export const usePushState = Z.createZustand((set, get) => { } ignorePromise(f()) }, - dynamic: { - onGetDaemonHandshakeState: () => { - throw new Error('onGetDaemonHandshakeState not implemented') - }, - onNavigateToThread: () => { - throw new Error('onNavigateToThread not implemented') - }, - onShowUserProfile: () => { - throw new Error('onShowUserProfile not implemented') - }, - }, handlePush: notification => { const f = async () => { try { @@ -164,13 +164,13 @@ export const usePushState = Z.createZustand((set, get) => { // We only care if the user clicked while in session if (notification.userInteraction) { const {username} = notification - get().dispatch.dynamic.onShowUserProfile?.(username) + get().dispatch.defer.onShowUserProfile?.(username) } break case 'chat.extension': { const {conversationIDKey} = notification - get().dispatch.dynamic.onNavigateToThread?.(conversationIDKey, 'extension') + get().dispatch.defer.onNavigateToThread?.(conversationIDKey, 'extension') } break case 'settings.contacts': @@ -233,13 +233,13 @@ export const usePushState = Z.createZustand((set, get) => { const shownPushPrompt = await askNativeIfSystemPushPromptHasBeenShown() if (shownPushPrompt) { // we've already shown the prompt, take them to settings - useConfigState.getState().dispatch.dynamic.openAppSettings?.() + useConfigState.getState().dispatch.defer.openAppSettings?.() get().dispatch.showPermissionsPrompt({persistSkip: true, show: false}) return } } try { - useConfigState.getState().dispatch.dynamic.openAppSettings?.() + useConfigState.getState().dispatch.defer.openAppSettings?.() const {increment} = useWaitingState.getState().dispatch increment(S.waitingKeyPushPermissionsRequesting) await requestPermissionsFromNative() @@ -307,7 +307,7 @@ export const usePushState = Z.createZustand((set, get) => { if ( p.show && useConfigState.getState().loggedIn && - get().dispatch.dynamic.onGetDaemonHandshakeState?.() === 'done' && + get().dispatch.defer.onGetDaemonHandshakeState?.() === 'done' && !get().justSignedUp && !get().hasPermissions ) { diff --git a/shared/stores/recover-password.tsx b/shared/stores/recover-password.tsx index 2888b3f79dcb..6136a01a06ec 100644 --- a/shared/stores/recover-password.tsx +++ b/shared/stores/recover-password.tsx @@ -34,10 +34,12 @@ const initialStore: Store = { export interface State extends Store { dispatch: { - dynamic: { - cancel?: () => void + defer: { onProvisionCancel?: (ignoreWarning?: boolean) => void onStartAccountReset?: (skipPassword: boolean, username: string) => void + } + dynamic: { + cancel?: () => void submitDeviceSelect?: (name: string) => void submitPaperKey?: (key: string) => void submitPassword?: (pw: string) => void @@ -50,14 +52,16 @@ export interface State extends Store { export const useState = Z.createZustand((set, get) => { const dispatch: State['dispatch'] = { - dynamic: { - cancel: undefined, + defer: { onProvisionCancel: () => { throw new Error('onProvisionCancel not implemented') }, onStartAccountReset: () => { throw new Error('onStartAccountReset not implemented') }, + }, + dynamic: { + cancel: undefined, submitDeviceSelect: undefined, submitPaperKey: undefined, submitPassword: undefined, @@ -82,7 +86,7 @@ export const useState = Z.createZustand((set, get) => { const f = async () => { if (p.abortProvisioning) { - get().dispatch.dynamic.onProvisionCancel?.() + get().dispatch.defer.onProvisionCancel?.() } let hadError = false try { @@ -146,7 +150,7 @@ export const useState = Z.createZustand((set, get) => { }) }) } else { - get().dispatch.dynamic.onStartAccountReset?.(true, '') + get().dispatch.defer.onStartAccountReset?.(true, '') response.result(T.RPCGen.ResetPromptResponse.nothing) } }, diff --git a/shared/stores/router2.tsx b/shared/stores/router2.tsx index b2dc1cbac7d6..0a1cf4cc0804 100644 --- a/shared/stores/router2.tsx +++ b/shared/stores/router2.tsx @@ -34,7 +34,7 @@ const initialStore: Store = { export interface State extends Store { dispatch: { clearModals: () => void - dynamic: { + defer: { tabLongPress?: (tab: string) => void } navigateAppend: (path: Util.PathParam, replace?: boolean) => void @@ -54,7 +54,7 @@ export interface State extends Store { export const useRouterState = Z.createZustand((set, get) => { const dispatch: State['dispatch'] = { clearModals: Util.clearModals, - dynamic: { + defer: { tabLongPress: undefined, }, navUpToScreen: Util.navUpToScreen, diff --git a/shared/stores/signup.tsx b/shared/stores/signup.tsx index f42110c7072d..3d35852a6978 100644 --- a/shared/stores/signup.tsx +++ b/shared/stores/signup.tsx @@ -45,7 +45,7 @@ const initialStore: Store = { export interface State extends Store { dispatch: { - dynamic: { + defer: { onEditEmail?: (p: {email: string; makeSearchable: boolean}) => void onShowPermissionsPrompt?: (p: {justSignedUp?: boolean}) => void } @@ -84,7 +84,7 @@ export const useSignupState = Z.createZustand((set, get) => { } try { - get().dispatch.dynamic.onShowPermissionsPrompt?.({justSignedUp: true}) + get().dispatch.defer.onShowPermissionsPrompt?.({justSignedUp: true}) await T.RPCGen.signupSignupRpcListener({ customResponseIncomingCallMap: { @@ -125,7 +125,7 @@ export const useSignupState = Z.createZustand((set, get) => { } // If the email was set to be visible during signup, we need to set that with a separate RPC. if (noErrors() && get().emailVisible) { - get().dispatch.dynamic.onEditEmail?.({email: get().email, makeSearchable: true}) + get().dispatch.defer.onEditEmail?.({email: get().email, makeSearchable: true}) } } catch (_error) { if (_error instanceof RPCError) { @@ -134,7 +134,7 @@ export const useSignupState = Z.createZustand((set, get) => { s.signupError = error }) navigateAppend('signupError') - get().dispatch.dynamic.onShowPermissionsPrompt?.({justSignedUp: false}) + get().dispatch.defer.onShowPermissionsPrompt?.({justSignedUp: false}) } } } @@ -232,7 +232,7 @@ export const useSignupState = Z.createZustand((set, get) => { s.justSignedUpEmail = '' }) }, - dynamic: { + defer: { onEditEmail: () => { throw new Error('onEditEmail not implemented') }, diff --git a/shared/stores/team-building.tsx b/shared/stores/team-building.tsx index d76b23e45847..549bedfb5e95 100644 --- a/shared/stores/team-building.tsx +++ b/shared/stores/team-building.tsx @@ -53,7 +53,7 @@ export interface State extends Store { cancelTeamBuilding: () => void changeSendNotification: (sendNotification: boolean) => void closeTeamBuilding: () => void - dynamic: { + defer: { onAddMembersWizardPushMembers: (members: Array) => void onFinishedTeamBuildingChat: (users: ReadonlySet) => void onFinishedTeamBuildingCrypto: (users: ReadonlySet) => void @@ -280,7 +280,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { // we want the first item for (const user of teamSoFar) { const username = user.serviceMap.keybase || user.id - get().dispatch.dynamic.onShowUserProfile(username) + get().dispatch.defer.onShowUserProfile(username) break } }, 100) @@ -307,7 +307,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { navigateUp() } }, - dynamic: { + defer: { onAddMembersWizardPushMembers: (_members: Array) => { throw new Error('onAddMembersWizardPushMembers not properly initialized') }, @@ -348,7 +348,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const contacts = contactRes.map(contactToUser) let suggestions = suggestionRes.map(interestingPersonToUser) const expectingContacts = - get().dispatch.dynamic.onGetSettingsContactsImportEnabled() && includeContacts + get().dispatch.defer.onGetSettingsContactsImportEnabled() && includeContacts if (expectingContacts) { suggestions = suggestions.slice(0, 10) } @@ -371,7 +371,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { get().dispatch.closeTeamBuilding() const {teamSoFar} = get() if (get().namespace === 'teams') { - get().dispatch.dynamic.onAddMembersWizardPushMembers( + get().dispatch.defer.onAddMembersWizardPushMembers( [...teamSoFar].map(user => ({assertion: user.id, role: 'writer'})) ) get().dispatch.finishedTeamBuilding() @@ -393,11 +393,11 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { const {finishedTeam, namespace} = get() switch (namespace) { case 'crypto': { - get().dispatch.dynamic.onFinishedTeamBuildingCrypto(finishedTeam) + get().dispatch.defer.onFinishedTeamBuildingCrypto(finishedTeam) break } case 'chat2': { - get().dispatch.dynamic.onFinishedTeamBuildingChat(finishedTeam) + get().dispatch.defer.onFinishedTeamBuildingChat(finishedTeam) break } default: @@ -448,7 +448,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { let users: typeof _users if (selectedService === 'keybase') { // If we are on Keybase tab, do additional search if query is phone/email. - const userRegion = get().dispatch.dynamic.onGetSettingsContactsUserCountryCode() + const userRegion = get().dispatch.defer.onGetSettingsContactsUserCountryCode() users = await specialContactSearch(_users, searchQuery, userRegion) } else { users = _users @@ -465,7 +465,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { } return arr }, new Array<{info: {fullname: string}; name: string}>()) - get().dispatch.dynamic.onUsersUpdates(updates) + get().dispatch.defer.onUsersUpdates(updates) const blocks = users.reduce((arr, {serviceMap}) => { const {keybase} = serviceMap if (keybase) { @@ -474,7 +474,7 @@ const createSlice: Z.ImmerStateCreator = (set, get) => { return arr }, new Array()) if (blocks.length) { - get().dispatch.dynamic.onUsersGetBlockState(blocks) + get().dispatch.defer.onUsersGetBlockState(blocks) } } ignorePromise(f()) diff --git a/shared/stores/teams.tsx b/shared/stores/teams.tsx index b240ef5a7dad..608429c44cdc 100644 --- a/shared/stores/teams.tsx +++ b/shared/stores/teams.tsx @@ -865,12 +865,14 @@ const initialStore: Store = { export interface State extends Store { dispatch: { - dynamic: { + defer: { onChatNavigateToInbox?: (allowSwitchTab?: boolean) => void onChatPreviewConversation?: ( p: Parameters['dispatch']['previewConversation']>[0] ) => void onUsersUpdates?: (updates: ReadonlyArray<{name: string; info: Partial}>) => void + } + dynamic: { respondToInviteLink?: (accept: boolean) => void } addMembersWizardPushMembers: (members: Array) => void @@ -1431,7 +1433,7 @@ export const useTeamsState = Z.createZustand((set, get) => { get().dispatch.loadTeamChannelList(teamID) // Select the new channel, and switch to the chat tab. if (navToChatOnSuccess) { - get().dispatch.dynamic.onChatPreviewConversation?.({ + get().dispatch.defer.onChatPreviewConversation?.({ channelname, conversationIDKey: newConversationIDKey, reason: 'newChannel', @@ -1501,8 +1503,8 @@ export const useTeamsState = Z.createZustand((set, get) => { if (fromChat) { clearModals() - get().dispatch.dynamic.onChatNavigateToInbox?.() - get().dispatch.dynamic.onChatPreviewConversation?.({ + get().dispatch.defer.onChatNavigateToInbox?.() + get().dispatch.defer.onChatPreviewConversation?.({ channelname: 'general', reason: 'convertAdHoc', teamname, @@ -1538,6 +1540,22 @@ export const useTeamsState = Z.createZustand((set, get) => { })) get().dispatch.createNewTeam(teamname, false, true, {sendChatNotification: true, users}) }, + defer: { + onChatNavigateToInbox: (_allowSwitchTab?: boolean) => { + throw new Error('onChatNavigateToInbox not implemented') + }, + onChatPreviewConversation: (_p: { + channelname?: string + conversationIDKey?: T.Chat.ConversationIDKey + reason?: string + teamname?: string + }) => { + throw new Error('onChatPreviewConversation not implemented') + }, + onUsersUpdates: (_updates: ReadonlyArray<{name: string; info: Partial}>) => { + throw new Error('onUsersUpdates not implemented') + }, + }, deleteChannelConfirmed: (teamID, conversationIDKey) => { const f = async () => { // channelName is only needed for confirmation, so since we handle @@ -1594,20 +1612,6 @@ export const useTeamsState = Z.createZustand((set, get) => { ignorePromise(f()) }, dynamic: { - onChatNavigateToInbox: (_allowSwitchTab?: boolean) => { - throw new Error('onChatNavigateToInbox not implemented') - }, - onChatPreviewConversation: (_p: { - channelname?: string - conversationIDKey?: T.Chat.ConversationIDKey - reason?: string - teamname?: string - }) => { - throw new Error('onChatPreviewConversation not implemented') - }, - onUsersUpdates: (_updates: ReadonlyArray<{name: string; info: Partial}>) => { - throw new Error('onUsersUpdates not implemented') - }, respondToInviteLink: undefined, }, eagerLoadTeams: () => { @@ -1748,7 +1752,7 @@ export const useTeamsState = Z.createZustand((set, get) => { set(s => { s.teamIDToMembers.set(teamID, members) }) - get().dispatch.dynamic.onUsersUpdates?.( + get().dispatch.defer.onUsersUpdates?.( [...members.values()].map(m => ({ info: {fullname: m.fullName}, name: m.username, diff --git a/shared/stores/tracker2.tsx b/shared/stores/tracker2.tsx index 506941d024ef..8b9475cb04a8 100644 --- a/shared/stores/tracker2.tsx +++ b/shared/stores/tracker2.tsx @@ -163,7 +163,7 @@ const initialStore: Store = { export interface State extends Store { dispatch: { - dynamic: { + defer: { onShowUserProfile?: (username: string) => void onUsersUpdates?: (updates: ReadonlyArray<{name: string; info: Partial}>) => void } @@ -231,7 +231,7 @@ export const useTrackerState = Z.createZustand((set, get) => { s.showTrackerSet.delete(username) }) }, - dynamic: { + defer: { onShowUserProfile: () => { throw new Error('onShowUserProfile not implemented') }, @@ -331,7 +331,7 @@ export const useTrackerState = Z.createZustand((set, get) => { d.followersCount = d.followers.size }) if (fs.users) { - get().dispatch.dynamic.onUsersUpdates?.( + get().dispatch.defer.onUsersUpdates?.( fs.users.map(u => ({info: {fullname: u.fullName}, name: u.username})) ) } @@ -357,7 +357,7 @@ export const useTrackerState = Z.createZustand((set, get) => { d.followingCount = d.following.size }) if (fs.users) { - get().dispatch.dynamic.onUsersUpdates?.( + get().dispatch.defer.onUsersUpdates?.( fs.users.map(u => ({info: {fullname: u.fullName}, name: u.username})) ) } @@ -447,7 +447,7 @@ export const useTrackerState = Z.createZustand((set, get) => { ) d.hidFromFollowers = hidFromFollowers }) - username && get().dispatch.dynamic.onUsersUpdates?.([{info: {fullname: card.fullName}, name: username}]) + username && get().dispatch.defer.onUsersUpdates?.([{info: {fullname: card.fullName}, name: username}]) }, notifyReset: guiID => { set(s => { @@ -606,7 +606,7 @@ export const useTrackerState = Z.createZustand((set, get) => { }) if (!skipNav) { // go to profile page - get().dispatch.dynamic.onShowUserProfile?.(username) + get().dispatch.defer.onShowUserProfile?.(username) } }, updateResult: (guiID, result, reason) => { diff --git a/shared/teams/common/enable-contacts.tsx b/shared/teams/common/enable-contacts.tsx index 829078c08933..477d3faf51dd 100644 --- a/shared/teams/common/enable-contacts.tsx +++ b/shared/teams/common/enable-contacts.tsx @@ -11,7 +11,7 @@ import {useConfigState} from '@/stores/config' * popup. */ const EnableContactsPopup = ({noAccess, onClose}: {noAccess: boolean; onClose: () => void}) => { - const onOpenSettings = useConfigState(s => s.dispatch.dynamic.openAppSettings) + const onOpenSettings = useConfigState(s => s.dispatch.defer.openAppSettings) const [showingPopup, setShowingPopup] = React.useState(noAccess) React.useEffect(() => { diff --git a/shared/tracker2/assertion.tsx b/shared/tracker2/assertion.tsx index 41a35459911b..1cf078bf5ece 100644 --- a/shared/tracker2/assertion.tsx +++ b/shared/tracker2/assertion.tsx @@ -424,7 +424,7 @@ const assertionColorToColor = (c: T.Tracker.AssertionColor) => { const StellarValue = (p: {value: string; color: T.Tracker.AssertionColor}) => { const {value, color} = p - const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard) + const copyToClipboard = useConfigState(s => s.dispatch.defer.copyToClipboard) const onCopyAddress = React.useCallback(() => { copyToClipboard(value) }, [copyToClipboard, value]) diff --git a/shared/util/zustand.tsx b/shared/util/zustand.tsx index 340308eb6d95..b3d223636d5b 100644 --- a/shared/util/zustand.tsx +++ b/shared/util/zustand.tsx @@ -9,7 +9,13 @@ import {wrapErrors} from '@/util/debug' // needed for tsc export type {WritableDraft} from 'immer' -type HasReset = {dispatch: {resetDeleteMe?: boolean; resetState: 'default' | (() => void)}} +type HasReset = { + dispatch: { + defer?: Record + resetDeleteMe?: boolean + resetState: 'default' | (() => void) + } +} const resetters: ((isDebug?: boolean) => void)[] = [] const resettersAndDelete: ((isDebug?: boolean) => void)[] = [] @@ -39,8 +45,9 @@ export const createZustand = ( let resetFunc: () => void if (reset === 'default') { resetFunc = () => { + const currentDefer = store.getState().dispatch.defer // eslint-disable-next-line - store.setState(initialState as any, true) + store.setState({...initialState, dispatch: {...initialState.dispatch, defer: currentDefer}} as any, true) } } else { resetFunc = reset diff --git a/shared/wallets/really-remove-account.tsx b/shared/wallets/really-remove-account.tsx index 88c7ad3c6408..aa7b88fb2143 100644 --- a/shared/wallets/really-remove-account.tsx +++ b/shared/wallets/really-remove-account.tsx @@ -17,7 +17,7 @@ const ReallyRemoveAccountPopup = (props: OwnProps) => { const attachmentRef = React.useRef(null) const setShowToastFalseLater = Kb.useTimeout(() => setShowToast(false), 2000) - const copyToClipboard = useConfigState(s => s.dispatch.dynamic.copyToClipboard) + const copyToClipboard = useConfigState(s => s.dispatch.defer.copyToClipboard) const [sk, setSK] = React.useState('') const loading = !sk From 9f5001e676aa880a0b752ebe37897b80f9a0aa0f Mon Sep 17 00:00:00 2001 From: chrisnojima-zoom <83838430+chrisnojima-zoom@users.noreply.github.com> Date: Tue, 10 Feb 2026 10:39:32 -0500 Subject: [PATCH 19/20] WIP: shift 21 (#28841) * WIP * WIP * WIP * WIP * WIP --------- Co-authored-by: chrisnojima --- shared/constants/init/shared.tsx | 61 +++++++++++-- shared/stores/chat2.tsx | 28 +++--- shared/stores/convostate.tsx | 146 ++++++++++++++++++++----------- shared/stores/settings-phone.tsx | 2 +- shared/stores/settings.tsx | 30 +++++-- shared/stores/store-registry.tsx | 7 -- shared/stores/team-building.tsx | 3 + shared/stores/teams.tsx | 9 +- 8 files changed, 195 insertions(+), 91 deletions(-) diff --git a/shared/constants/init/shared.tsx b/shared/constants/init/shared.tsx index 8f7c99df08b7..830d47dd9019 100644 --- a/shared/constants/init/shared.tsx +++ b/shared/constants/init/shared.tsx @@ -19,7 +19,7 @@ import type * as UseTeamsStateType from '@/stores/teams' import type * as UseTracker2StateType from '@/stores/tracker2' import type * as UseUnlockFoldersStateType from '@/stores/unlock-folders' import type * as UseUsersStateType from '@/stores/users' -import {createTBStore} from '@/stores/team-building' +import {createTBStore, getTBStore} from '@/stores/team-building' import {getSelectedConversation} from '@/constants/chat2/common' import {handleKeybaseLink} from '@/constants/deeplinks' import {ignorePromise} from '../utils' @@ -41,6 +41,8 @@ import {useProvisionState} from '@/stores/provision' import {usePushState} from '@/stores/push' import {useSettingsContactsState} from '@/stores/settings-contacts' import {useSettingsEmailState} from '@/stores/settings-email' +import {useSettingsPhoneState} from '@/stores/settings-phone' +import {useSettingsState} from '@/stores/settings' import {useSignupState} from '@/stores/signup' import {useState as useRecoverPasswordState} from '@/stores/recover-password' import {useTeamsState} from '@/stores/teams' @@ -49,7 +51,7 @@ import {useUsersState} from '@/stores/users' import {useWhatsNewState} from '@/stores/whats-new' import {useRouterState} from '@/stores/router2' import * as Util from '@/constants/router2' -import {setOtherStores} from '@/stores/convostate' +import {setConvoDefer} from '@/stores/convostate' let _emitStartupOnLoadDaemonConnectedOnce = false let _devicesLoaded = false @@ -373,12 +375,54 @@ export const initTracker2Callbacks = () => { }) } +export const initSettingsCallbacks = () => { + const currentState = useSettingsState.getState() + useSettingsState.setState({ + dispatch: { + ...currentState.dispatch, + defer: { + ...currentState.dispatch.defer, + getSettingsPhonePhones: () => { + return useSettingsPhoneState.getState().phones + }, + onSettingsEmailNotifyEmailsChanged: (emails: ReadonlyArray) => { + useSettingsEmailState.getState().dispatch.notifyEmailAddressEmailsChanged(emails) + }, + onSettingsPhoneSetNumbers: (phoneNumbers?: ReadonlyArray) => { + useSettingsPhoneState.getState().dispatch.setNumbers(phoneNumbers) + }, + }, + }, + }) +} + export const initSharedSubscriptions = () => { - setOtherStores( - storeRegistry.getStore('chat'), - storeRegistry.getStore('teams'), - storeRegistry.getStore('users') - ) + setConvoDefer({ + chatBlockButtonsMapHas: teamID => + storeRegistry.getState('chat').blockButtonsMap.has(teamID), + chatInboxLayoutSmallTeamsFirstConvID: () => + storeRegistry.getState('chat').inboxLayout?.smallTeams?.[0]?.convID, + chatInboxRefresh: reason => + storeRegistry.getState('chat').dispatch.inboxRefresh(reason), + chatMetasReceived: metas => + storeRegistry.getState('chat').dispatch.metasReceived(metas), + chatNavigateToInbox: () => + storeRegistry.getState('chat').dispatch.navigateToInbox(), + chatPaymentInfoReceived: (_messageID, paymentInfo) => + storeRegistry.getState('chat').dispatch.paymentInfoReceived(paymentInfo), + chatPreviewConversation: p => + storeRegistry.getState('chat').dispatch.previewConversation(p), + chatResetConversationErrored: () => + storeRegistry.getState('chat').dispatch.resetConversationErrored(), + chatUnboxRows: (convIDs, force) => + storeRegistry.getState('chat').dispatch.unboxRows(convIDs, force), + chatUpdateInfoPanel: (show, tab) => + storeRegistry.getState('chat').dispatch.updateInfoPanel(show, tab), + teamsGetMembers: teamID => + storeRegistry.getState('teams').dispatch.getMembers(teamID), + usersGetBio: username => + storeRegistry.getState('users').dispatch.getBio(username), + }) useConfigState.subscribe((s, old) => { if (s.loadOnStartPhase !== old.loadOnStartPhase) { if (s.loadOnStartPhase === 'startupOrReloginButNotInARush') { @@ -581,7 +625,7 @@ export const initSharedSubscriptions = () => { // team building or modal on top of that still const isTeamBuilding = namespaceToRoute.get(namespace) === Util.getVisibleScreen(next)?.name if (!isTeamBuilding) { - storeRegistry.getTBStore(namespace).dispatch.cancelTeamBuilding() + getTBStore(namespace).dispatch.cancelTeamBuilding() } } } @@ -651,6 +695,7 @@ export const initSharedSubscriptions = () => { initProfileCallbacks() initPushCallbacks() initRecoverPasswordCallbacks() + initSettingsCallbacks() initSignupCallbacks() initTracker2Callbacks() } diff --git a/shared/stores/chat2.tsx b/shared/stores/chat2.tsx index 24c548599ed0..693304814f4d 100644 --- a/shared/stores/chat2.tsx +++ b/shared/stores/chat2.tsx @@ -286,6 +286,19 @@ const initialStore: Store = { userReacjis: defaultUserReacjis, } +export type RefreshReason = + | 'bootstrap' + | 'componentNeverLoaded' + | 'inboxStale' + | 'inboxSyncedClear' + | 'inboxSyncedUnknown' + | 'joinedAConversation' + | 'leftAConversation' + | 'teamTypeChanged' + | 'maybeKickedFromTeam' + | 'widgetRefresh' + | 'shareConfigSearch' + export interface State extends Store { dispatch: { badgesUpdated: (badgeState?: T.RPCGen.BadgeState) => void @@ -310,20 +323,7 @@ export interface State extends Store { ensureWidgetMetas: () => void findGeneralConvIDFromTeamID: (teamID: T.Teams.TeamID) => void fetchUserEmoji: (conversationIDKey?: T.Chat.ConversationIDKey, onlyInTeam?: boolean) => void - inboxRefresh: ( - reason: - | 'bootstrap' - | 'componentNeverLoaded' - | 'inboxStale' - | 'inboxSyncedClear' - | 'inboxSyncedUnknown' - | 'joinedAConversation' - | 'leftAConversation' - | 'teamTypeChanged' - | 'maybeKickedFromTeam' - | 'widgetRefresh' - | 'shareConfigSearch' - ) => void + inboxRefresh: (reason: RefreshReason) => void inboxSearch: (query: string) => void inboxSearchMoveSelectedIndex: (increment: boolean) => void inboxSearchSelect: ( diff --git a/shared/stores/convostate.tsx b/shared/stores/convostate.tsx index a48c54a4cc79..824c7a78f748 100644 --- a/shared/stores/convostate.tsx +++ b/shared/stores/convostate.tsx @@ -48,9 +48,7 @@ import * as Strings from '@/constants/strings' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' -import type {useChatState} from '@/stores/chat2' -import type {useTeamsState} from '@/stores/teams' -import type {useUsersState} from '@/stores/users' +import type {useChatState, RefreshReason} from '@/stores/chat2' const {darwinCopyToChatTempUploadFile} = KB2.functions @@ -227,6 +225,25 @@ export interface ConvoState extends ConvoStore { botCommandsUpdateStatus: (b: T.RPCChat.UIBotCommandsUpdateStatus) => void channelSuggestionsTriggered: () => void clearAttachmentView: () => void + defer: { + chatBlockButtonsMapHas: (teamID: T.RPCGen.TeamID) => boolean + chatInboxLayoutSmallTeamsFirstConvID: () => T.Chat.ConversationIDKey | undefined + chatInboxRefresh: (reason: RefreshReason) => void + chatMetasReceived: (metas: ReadonlyArray) => void + chatNavigateToInbox: () => void + chatPaymentInfoReceived: (messageID: T.Chat.MessageID, paymentInfo: T.Chat.ChatPaymentInfo) => void + chatPreviewConversation: ( + p: Parameters['dispatch']['previewConversation']>[0] + ) => void + chatResetConversationErrored: () => void + chatUnboxRows: (convIDs: ReadonlyArray, force: boolean) => void + chatUpdateInfoPanel: ( + show: boolean, + tab: 'settings' | 'members' | 'attachments' | 'bots' | undefined + ) => void + teamsGetMembers: (teamID: T.RPCGen.TeamID) => void + usersGetBio: (username: string) => void + } dismissBottomBanner: () => void dismissBlockButtons: (teamID: T.RPCGen.TeamID) => void dismissJourneycard: (cardType: T.RPCChat.JourneycardType, ordinal: T.Chat.Ordinal) => void @@ -375,15 +392,68 @@ type ScrollDirection = 'none' | 'back' | 'forward' export const numMessagesOnInitialLoad = isMobile ? 20 : 100 export const numMessagesOnScrollback = isMobile ? 100 : 100 -const createSlice = ( - chatStateHook: typeof useChatState, - teamsStateHook: typeof useTeamsState, - usersStateHook: typeof useUsersState -): Z.ImmerStateCreator => (set, get) => { +const stubDefer: ConvoState['dispatch']['defer'] = { + chatBlockButtonsMapHas: () => { + throw new Error('convostate defer not initialized') + }, + chatInboxLayoutSmallTeamsFirstConvID: () => { + throw new Error('convostate defer not initialized') + }, + chatInboxRefresh: () => { + throw new Error('convostate defer not initialized') + }, + chatMetasReceived: () => { + throw new Error('convostate defer not initialized') + }, + chatNavigateToInbox: () => { + throw new Error('convostate defer not initialized') + }, + chatPaymentInfoReceived: () => { + throw new Error('convostate defer not initialized') + }, + chatPreviewConversation: () => { + throw new Error('convostate defer not initialized') + }, + chatResetConversationErrored: () => { + throw new Error('convostate defer not initialized') + }, + chatUnboxRows: () => { + throw new Error('convostate defer not initialized') + }, + chatUpdateInfoPanel: () => { + throw new Error('convostate defer not initialized') + }, + teamsGetMembers: () => { + throw new Error('convostate defer not initialized') + }, + usersGetBio: () => { + throw new Error('convostate defer not initialized') + }, +} + +let convoDeferImpl: ConvoState['dispatch']['defer'] | undefined + +export const setConvoDefer = (impl: ConvoState['dispatch']['defer']) => { + convoDeferImpl = impl + for (const store of chatStores.values()) { + const s = store.getState() + store.setState({ + ...s, + dispatch: { + ...s.dispatch, + defer: impl, + }, + }) + } +} + +const createSlice = (): Z.ImmerStateCreator => (set, get) => { + const defer = convoDeferImpl ?? stubDefer + const closeBotModal = () => { clearModals() if (get().meta.teamname) { - teamsStateHook.getState().dispatch.getMembers(get().meta.teamID) + get().dispatch.defer.teamsGetMembers(get().meta.teamID) } } @@ -501,7 +571,7 @@ const createSlice = ( const onClick = () => { useConfigState.getState().dispatch.showMain() - chatStateHook.getState().dispatch.navigateToInbox() + get().dispatch.defer.chatNavigateToInbox() get().dispatch.navigateToThread('desktopNotification') } const onClose = () => {} @@ -638,7 +708,7 @@ const createSlice = ( logger.error(errMsg) throw new Error(errMsg) } - chatStateHook.getState().dispatch.paymentInfoReceived(paymentInfo) + get().dispatch.defer.chatPaymentInfoReceived(T.Chat.numberToMessageID(msgID), paymentInfo) getConvoState(conversationIDKey).dispatch.paymentInfoReceived(msgID, paymentInfo) } @@ -1076,7 +1146,7 @@ const createSlice = ( } // If there are block buttons on this conversation, clear them. - if (chatStateHook.getState().blockButtonsMap.has(meta.teamID)) { + if (get().dispatch.defer.chatBlockButtonsMapHas(meta.teamID)) { get().dispatch.dismissBlockButtons(meta.teamID) } @@ -1244,7 +1314,7 @@ const createSlice = ( }, blockConversation: reportUser => { const f = async () => { - chatStateHook.getState().dispatch.navigateToInbox() + get().dispatch.defer.chatNavigateToInbox() useConfigState.getState().dispatch.defer.persistRoute?.() await T.RPCChat.localSetConversationStatusLocalRpcPromise({ conversationID: get().getConvID(), @@ -1277,6 +1347,7 @@ const createSlice = ( s.attachmentViewMap = new Map() }) }, + defer, dismissBlockButtons: teamID => { const f = async () => { try { @@ -1348,7 +1419,7 @@ const createSlice = ( // Nav to inbox but don't use findNewConversation since changeSelectedConversation // does that with better information. It knows the conversation is hidden even before // that state bounces back. - chatStateHook.getState().dispatch.navigateToInbox() + get().dispatch.defer.chatNavigateToInbox() get().dispatch.showInfoPanel(false, undefined) } @@ -1401,7 +1472,7 @@ const createSlice = ( const params = vs?.params as undefined | {conversationIDKey?: T.Chat.ConversationIDKey} if (params?.conversationIDKey === get().id) { // select a convo - const next = chatStateHook.getState().inboxLayout?.smallTeams?.[0]?.convID + const next = get().dispatch.defer.chatInboxLayoutSmallTeamsFirstConvID() if (next) { getConvoState(next).dispatch.navigateToThread('findNewestConversationFromLayout') } @@ -1666,8 +1737,8 @@ const createSlice = ( logger.warn(`loadMoreMessages: error: ${error.desc}`) // no longer in team if (error.code === T.RPCGen.StatusCode.scchatnotinteam) { - chatStateHook.getState().dispatch.inboxRefresh('maybeKickedFromTeam') - chatStateHook.getState().dispatch.navigateToInbox() + get().dispatch.defer.chatInboxRefresh('maybeKickedFromTeam') + get().dispatch.defer.chatNavigateToInbox() } if (error.code !== T.RPCGen.StatusCode.scteamreaderror) { // scteamreaderror = user is not in team. they'll see the rekey screen so don't throw for that @@ -1994,7 +2065,7 @@ const createSlice = ( const text = formatTextForQuoting(message.text.stringValue()) getConvoState(newThreadCID).dispatch.injectIntoInput(text) - chatStateHook.getState().dispatch.metasReceived([meta]) + get().dispatch.defer.chatMetasReceived([meta]) getConvoState(newThreadCID).dispatch.navigateToThread('createdMessagePrivately') } ignorePromise(f()) @@ -2139,7 +2210,7 @@ const createSlice = ( loadMessages() // load meta - chatStateHook.getState().dispatch.unboxRows([get().id], true) + get().dispatch.defer.chatUnboxRows([get().id], true) const updateNav = () => { const reason = _reason @@ -2465,7 +2536,7 @@ const createSlice = ( // remove all bad people const goodParticipants = new Set(participantInfo.all) meta.resetParticipants.forEach(r => goodParticipants.delete(r)) - chatStateHook.getState().dispatch.previewConversation({ + get().dispatch.defer.chatPreviewConversation({ participants: [...goodParticipants], reason: 'resetChatWithoutThem', }) @@ -2508,7 +2579,7 @@ const createSlice = ( return } - usersStateHook.getState().dispatch.getBio(username) + get().dispatch.defer.usersGetBio(username) } } @@ -2518,19 +2589,19 @@ const createSlice = ( if (isMetaGood()) { const {teamID, teamname} = meta if (teamname) { - teamsStateHook.getState().dispatch.getMembers(teamID) + get().dispatch.defer.teamsGetMembers(teamID) } } } ensureSelectedTeamLoaded() const participantInfo = get().participants const force = !get().isMetaGood() || participantInfo.all.length === 0 - chatStateHook.getState().dispatch.unboxRows([conversationIDKey], force) + get().dispatch.defer.chatUnboxRows([conversationIDKey], force) set(s => { s.threadLoadStatus = T.RPCChat.UIChatThreadStatusTyp.none }) fetchConversationBio() - chatStateHook.getState().dispatch.resetConversationErrored() + get().dispatch.defer.chatResetConversationErrored() }, sendAudioRecording: async (path, duration, amps) => { const outboxID = Common.generateOutboxID() @@ -2851,7 +2922,7 @@ const createSlice = ( }) }, 1000), showInfoPanel: (show, tab) => { - chatStateHook.getState().dispatch.updateInfoPanel(show, tab) + get().dispatch.defer.chatUpdateInfoPanel(show, tab) const conversationIDKey = get().id if (Platform.isPhone) { const visibleScreen = getVisibleScreen() @@ -3252,33 +3323,10 @@ registerDebugClear(() => { clearChatStores() }) -let chatStore: typeof useChatState | undefined -let teamsStore: typeof useTeamsState | undefined -let usersStore: typeof useUsersState | undefined - -export const setOtherStores = ( - chat: typeof useChatState, - teams: typeof useTeamsState, - users: typeof useUsersState -) => { - chatStore = chat - teamsStore = teams - usersStore = users -} - const createConvoStore = (id: T.Chat.ConversationIDKey) => { const existing = chatStores.get(id) if (existing) return existing - if (!chatStore || !teamsStore || !usersStore) { - throw new Error('Stores not initialized. Call setOtherStores before creating conversation stores.') - } - const next = Z.createZustand( - createSlice( - chatStore, - teamsStore, - usersStore - ) - ) + const next = Z.createZustand(createSlice()) next.setState({id}) chatStores.set(id, next) return next diff --git a/shared/stores/settings-phone.tsx b/shared/stores/settings-phone.tsx index a70f161aa1f0..eefe6932475d 100644 --- a/shared/stores/settings-phone.tsx +++ b/shared/stores/settings-phone.tsx @@ -43,7 +43,7 @@ export const makePhoneError = (e: RPCError) => { } } -type PhoneRow = { +export type PhoneRow = { displayNumber: string e164: string searchable: boolean diff --git a/shared/stores/settings.tsx b/shared/stores/settings.tsx index 477e3d29638e..6c9ed5b1a946 100644 --- a/shared/stores/settings.tsx +++ b/shared/stores/settings.tsx @@ -8,11 +8,11 @@ import {RPCError} from '@/util/errors' import * as Tabs from '@/constants/tabs' import logger from '@/logger' import {clearModals, navigateAppend, switchTab} from '@/constants/router2' -import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {useCurrentUserState} from '@/stores/current-user' import {useWaitingState} from '@/stores/waiting' import {processorProfileInProgressKey, traceInProgressKey} from '@/constants/settings' +import type {PhoneRow} from '@/stores/settings-phone' export * from '@/constants/settings' @@ -33,8 +33,13 @@ const initialStore: Store = { export interface State extends Store { dispatch: { checkPassword: (password: string) => void - dbNuke: () => void clearLogs: () => void + dbNuke: () => void + defer: { + getSettingsPhonePhones: () => undefined | ReadonlyMap + onSettingsEmailNotifyEmailsChanged: (list: ReadonlyArray) => void + onSettingsPhoneSetNumbers: (phoneNumbers?: ReadonlyArray) => void + } deleteAccountForever: (passphrase?: string) => void loadLockdownMode: () => void loadProxyData: () => void @@ -52,9 +57,9 @@ export interface State extends Store { } let maybeLoadAppLinkOnce = false -export const useSettingsState = Z.createZustand(set => { +export const useSettingsState = Z.createZustand((set, get) => { const maybeLoadAppLink = () => { - const phones = storeRegistry.getState('settings-phone').phones + const phones = get().dispatch.defer.getSettingsPhonePhones() if (!phones || phones.size > 0) { return } @@ -96,6 +101,17 @@ export const useSettingsState = Z.createZustand(set => { } ignorePromise(f()) }, + defer: { + getSettingsPhonePhones: () => { + throw new Error('getSettingsPhonePhones not implemented') + }, + onSettingsEmailNotifyEmailsChanged: () => { + throw new Error('onSettingsEmailNotifyEmailsChanged not implemented') + }, + onSettingsPhoneSetNumbers: () => { + throw new Error('onSettingsPhoneSetNumbers not implemented') + }, + }, deleteAccountForever: passphrase => { const f = async () => { const username = useCurrentUserState.getState().username @@ -157,10 +173,8 @@ export const useSettingsState = Z.createZustand(set => { undefined, S.waitingKeySettingsLoadSettings ) - storeRegistry - .getState('settings-email') - .dispatch.notifyEmailAddressEmailsChanged(settings.emails ?? []) - storeRegistry.getState('settings-phone').dispatch.setNumbers(settings.phoneNumbers ?? undefined) + get().dispatch.defer.onSettingsEmailNotifyEmailsChanged(settings.emails ?? []) + get().dispatch.defer.onSettingsPhoneSetNumbers(settings.phoneNumbers ?? undefined) maybeLoadAppLink() } catch (error) { if (!(error instanceof RPCError)) { diff --git a/shared/stores/store-registry.tsx b/shared/stores/store-registry.tsx index 8fe0eb68399a..dbae6e710f48 100644 --- a/shared/stores/store-registry.tsx +++ b/shared/stores/store-registry.tsx @@ -1,7 +1,6 @@ // used to allow non-circular cross-calls between stores // ONLY for zustand stores import type * as T from '@/constants/types' -import type * as TBType from '@/stores/team-building' import type * as ConvoStateType from '@/stores/convostate' import type {ConvoState} from '@/stores/convostate' import type {State as ChatState, useChatState} from '@/stores/chat2' @@ -149,12 +148,6 @@ class StoreRegistry { return this.getStore(storeName).getState() as StoreStates[T] } - getTBStore(name: T.TB.AllowedNamespace): TBType.State { - const {createTBStore} = require('@/stores/team-building') as typeof TBType - const store = createTBStore(name) - return store.getState() - } - getConvoState(id: T.Chat.ConversationIDKey): ConvoState { const {getConvoState} = require('@/stores/convostate') as typeof ConvoStateType return getConvoState(id) diff --git a/shared/stores/team-building.tsx b/shared/stores/team-building.tsx index 549bedfb5e95..fb68799d16c0 100644 --- a/shared/stores/team-building.tsx +++ b/shared/stores/team-building.tsx @@ -512,6 +512,9 @@ export const createTBStore = (namespace: T.TB.AllowedNamespace) => { return next } +export const getTBStore = (namespace: T.TB.AllowedNamespace): State => + createTBStore(namespace).getState() + const Context = React.createContext(null) type TBProviderProps = React.PropsWithChildren<{namespace: T.TB.AllowedNamespace}> diff --git a/shared/stores/teams.tsx b/shared/stores/teams.tsx index 608429c44cdc..ac4b61953748 100644 --- a/shared/stores/teams.tsx +++ b/shared/stores/teams.tsx @@ -19,6 +19,7 @@ import {isMobile, isPhone} from '@/constants/platform' import {mapGetEnsureValue} from '@/util/map' import {bodyToJSON} from '@/constants/rpc-utils' import {fixCrop} from '@/util/crop' +import {getTBStore} from '@/stores/team-building' import {storeRegistry} from '@/stores/store-registry' import {useConfigState} from '@/stores/config' import {type useChatState} from '@/stores/chat2' @@ -1230,7 +1231,7 @@ export const useTeamsState = Z.createZustand((set, get) => { ) if (res.notAdded && res.notAdded.length > 0) { const usernames = res.notAdded.map(elem => elem.username) - storeRegistry.getTBStore('teams').dispatch.finishedTeamBuilding() + getTBStore('teams').dispatch.finishedTeamBuilding() navigateAppend({ props: {source: 'teamAddSomeFailed', usernames}, selected: 'contactRestricted', @@ -1242,7 +1243,7 @@ export const useTeamsState = Z.createZustand((set, get) => { s.errorInAddToTeam = '' }) if (fromTeamBuilder) { - storeRegistry.getTBStore('teams').dispatch.finishedTeamBuilding() + getTBStore('teams').dispatch.finishedTeamBuilding() } } catch (error) { if (!(error instanceof RPCError)) { @@ -1254,7 +1255,7 @@ export const useTeamsState = Z.createZustand((set, get) => { ?.filter(elem => elem?.key === 'usernames') .map(elem => elem?.value) const usernames = users?.[0]?.split(',') ?? [] - storeRegistry.getTBStore('teams').dispatch.finishedTeamBuilding() + getTBStore('teams').dispatch.finishedTeamBuilding() navigateAppend({ props: {source: 'teamAddAllFailed', usernames}, selected: 'contactRestricted', @@ -1268,7 +1269,7 @@ export const useTeamsState = Z.createZustand((set, get) => { }) // TODO this should not error on member already in team if (fromTeamBuilder) { - storeRegistry.getTBStore('teams').dispatch.setError(msg) + getTBStore('teams').dispatch.setError(msg) } } } From 4ed0562bab36943b6e6e26f07ba3ce64b399ad18 Mon Sep 17 00:00:00 2001 From: chrisnojima Date: Thu, 12 Feb 2026 10:56:32 -0500 Subject: [PATCH 20/20] WIP --- go/libkb/version.go | 2 +- shared/android/app/build.gradle | 2 +- shared/ios/Keybase/Info.plist | 2 +- shared/ios/KeybaseShare/Info.plist | 2 +- shared/ios/Podfile.lock | 36 +- shared/package.json | 56 +- shared/todo.txt | 6 +- shared/yarn.lock | 1213 ++++++++++++++++++---------- 8 files changed, 824 insertions(+), 495 deletions(-) diff --git a/go/libkb/version.go b/go/libkb/version.go index d8b23ce1ad0e..e9c38269738b 100644 --- a/go/libkb/version.go +++ b/go/libkb/version.go @@ -4,4 +4,4 @@ package libkb // Version is the current version (should be MAJOR.MINOR.PATCH) -const Version = "6.6.0" +const Version = "6.7.0" diff --git a/shared/android/app/build.gradle b/shared/android/app/build.gradle index 43cfc1c7c8ad..29e9bfaf1434 100644 --- a/shared/android/app/build.gradle +++ b/shared/android/app/build.gradle @@ -4,7 +4,7 @@ apply plugin: "com.facebook.react" apply plugin: 'com.github.triplet.play' // KB: app version -def VERSION_NAME = "6.6.0" +def VERSION_NAME = "6.7.0" // KB: Number of commits, like ios Integer getVersionCode() { diff --git a/shared/ios/Keybase/Info.plist b/shared/ios/Keybase/Info.plist index fb65c31b600d..fc0bc7c9f8f2 100644 --- a/shared/ios/Keybase/Info.plist +++ b/shared/ios/Keybase/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 6.6.0 + 6.7.0 CFBundleSignature ???? CFBundleURLTypes diff --git a/shared/ios/KeybaseShare/Info.plist b/shared/ios/KeybaseShare/Info.plist index d7a771229ac6..b699e9a1d1b1 100644 --- a/shared/ios/KeybaseShare/Info.plist +++ b/shared/ios/KeybaseShare/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 6.6.0 + 6.7.0 CFBundleVersion 200 NSExtension diff --git a/shared/ios/Podfile.lock b/shared/ios/Podfile.lock index 6c16b2c5df90..34be5b28b06c 100644 --- a/shared/ios/Podfile.lock +++ b/shared/ios/Podfile.lock @@ -9,7 +9,7 @@ PODS: - EXImageLoader (6.0.0): - ExpoModulesCore - React-Core - - Expo (54.0.31): + - Expo (54.0.33): - boost - DoubleConversion - ExpoModulesCore @@ -52,7 +52,7 @@ PODS: - ExpoModulesCore - ExpoFileSystem (19.0.21): - ExpoModulesCore - - ExpoFont (14.0.10): + - ExpoFont (14.0.11): - ExpoModulesCore - ExpoHaptics (15.0.8): - ExpoModulesCore @@ -1932,7 +1932,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-keyboard-controller (1.20.6): + - react-native-keyboard-controller (1.20.7): - boost - DoubleConversion - fast_float @@ -1950,7 +1950,7 @@ PODS: - React-graphics - React-ImageManager - React-jsi - - react-native-keyboard-controller/common (= 1.20.6) + - react-native-keyboard-controller/common (= 1.20.7) - React-NativeModulesApple - React-RCTFabric - React-renderercss @@ -1961,7 +1961,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-keyboard-controller/common (1.20.6): + - react-native-keyboard-controller/common (1.20.7): - boost - DoubleConversion - fast_float @@ -2814,7 +2814,7 @@ PODS: - RNWorklets - SocketRocket - Yoga - - RNScreens (4.18.0): + - RNScreens (4.23.0): - boost - DoubleConversion - fast_float @@ -2841,10 +2841,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNScreens/common (= 4.18.0) + - RNScreens/common (= 4.23.0) - SocketRocket - Yoga - - RNScreens/common (4.18.0): + - RNScreens/common (4.23.0): - boost - DoubleConversion - fast_float @@ -2873,7 +2873,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - RNWorklets (0.7.1): + - RNWorklets (0.7.3): - boost - DoubleConversion - fast_float @@ -2900,10 +2900,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNWorklets/worklets (= 0.7.1) + - RNWorklets/worklets (= 0.7.3) - SocketRocket - Yoga - - RNWorklets/worklets (0.7.1): + - RNWorklets/worklets (0.7.3): - boost - DoubleConversion - fast_float @@ -2930,10 +2930,10 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNWorklets/worklets/apple (= 0.7.1) + - RNWorklets/worklets/apple (= 0.7.3) - SocketRocket - Yoga - - RNWorklets/worklets/apple (0.7.1): + - RNWorklets/worklets/apple (0.7.3): - boost - DoubleConversion - fast_float @@ -3323,13 +3323,13 @@ SPEC CHECKSUMS: EXAV: b60fcf142fae6684d295bc28cd7cfcb3335570ea EXConstants: fce59a631a06c4151602843667f7cfe35f81e271 EXImageLoader: 189e3476581efe3ad4d1d3fb4735b7179eb26f05 - Expo: 5fe0862b0c3de267afbba769891aa65f64c2800c + Expo: ec20d60a9ba93352323b8f773c0e59bc7aa1c492 ExpoAsset: f867e55ceb428aab99e1e8c082b5aee7c159ea18 ExpoCamera: 6a326deb45ba840749652e4c15198317aa78497e ExpoClipboard: b36b287d8356887844bb08ed5c84b5979bb4dd1e ExpoContacts: 1c976e6c0b9be9b256ea038eba5c86f5707a73ce ExpoFileSystem: 858a44267a3e6e9057e0888ad7c7cfbf55d52063 - ExpoFont: 35ac6191ed86bbf56b3ebd2d9154eda9fad5b509 + ExpoFont: f543ce20a228dd702813668b1a07b46f51878d47 ExpoHaptics: d3a6375d8dcc3a1083d003bc2298ff654fafb536 ExpoImage: 686f972bff29525733aa13357f6691dc90aa03d8 ExpoImagePicker: 1af3e4e31512d2f34c95c2a3018a3edc40aee748 @@ -3385,7 +3385,7 @@ SPEC CHECKSUMS: React-Mapbuffer: 017336879e2e0fb7537bbc08c24f34e2384c9260 React-microtasksnativemodule: 63ee6730cec233feab9cdcc0c100dc28a12e4165 react-native-kb: 078843e8c52d210aff0c50cbb4c4abe888c28ee2 - react-native-keyboard-controller: 40b005f1202d68566a2d058ddc148a3ea8d73288 + react-native-keyboard-controller: a9e423beaa20d00a4b9664b0fa37f1cdf3a59975 react-native-netinfo: 64f05e94821ee3f3adcd9b67b35c1480e5564915 react-native-safe-area-context: 0a3b034bb63a5b684dd2f5fffd3c90ef6ed41ee8 react-native-webview: cdce419e8022d0ef6f07db21890631258e7a9e6e @@ -3423,8 +3423,8 @@ SPEC CHECKSUMS: RNCPicker: 35fc66f352403cdfe99d53b541f5180482ca2bc5 RNGestureHandler: 043d32e7e7ae6bdcca06264682d5a078712903a1 RNReanimated: e79d7f42b76ba026e7dc5fb3e3f81991c590d3af - RNScreens: 98771ad898d1c0528fc8139606bbacf5a2e9d237 - RNWorklets: 416ef974c176d76634e34c0aeda83f6b67084a88 + RNScreens: 199799bdab32fa1e17ebf938b06fec52033e81e5 + RNWorklets: ff9b9ff38df9accccbbbad692b6e435fec64e24e SDWebImage: e9c98383c7572d713c1a0d7dd2783b10599b9838 SDWebImageAVIFCoder: afe194a084e851f70228e4be35ef651df0fc5c57 SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c diff --git a/shared/package.json b/shared/package.json index 837257dde1f4..a0bdb4e9c25e 100644 --- a/shared/package.json +++ b/shared/package.json @@ -72,20 +72,20 @@ "dependencies": { "@gorhom/bottom-sheet": "5.2.8", "@gorhom/portal": "1.0.14", - "@khanacademy/simple-markdown": "2.1.4", - "@msgpack/msgpack": "3.1.2", + "@khanacademy/simple-markdown": "2.2.1", + "@msgpack/msgpack": "3.1.3", "@react-native-community/netinfo": "11.5.2", "@react-native-masked-view/masked-view": "0.3.2", "@react-native-picker/picker": "2.11.4", - "@react-navigation/bottom-tabs": "7.9.1", - "@react-navigation/core": "7.13.7", - "@react-navigation/native": "7.1.27", - "@react-navigation/native-stack": "7.9.1", + "@react-navigation/bottom-tabs": "7.13.0", + "@react-navigation/core": "7.14.0", + "@react-navigation/native": "7.1.28", + "@react-navigation/native-stack": "7.12.0", "classnames": "2.5.1", "date-fns": "4.1.0", "emoji-datasource-apple": "16.0.0", "emoji-regex": "10.6.0", - "expo": "54.0.31", + "expo": "54.0.33", "expo-av": "16.0.8", "expo-camera": "17.0.10", "expo-clipboard": "8.0.8", @@ -99,10 +99,10 @@ "expo-media-library": "18.2.1", "expo-sms": "14.0.8", "expo-task-manager": "14.0.9", - "framed-msgpack-rpc": "keybase/node-framed-msgpack-rpc#nojima/HOTPOT-use-buffer", - "google-libphonenumber": "3.2.43", + "framed-msgpack-rpc": "keybase/node-framed-msgpack-rpc#nojima/HOTPOT-use-buffer-iserror2", + "google-libphonenumber": "3.2.44", "iced-runtime": "1.0.4", - "immer": "11.1.3", + "immer": "11.1.4", "lodash": "4.17.23", "lottie-react-native": "7.3.5", "lottie-web": "5.13.0", @@ -115,27 +115,27 @@ "react-list": "0.8.18", "react-native": "0.81.5", "react-native-gesture-handler": "2.30.0", - "react-native-keyboard-controller": "1.20.6", + "react-native-keyboard-controller": "1.20.7", "react-native-kb": "file:../rnmodules/react-native-kb", "react-native-reanimated": "4.2.1", - "react-native-worklets": "0.7.1", + "react-native-worklets": "0.7.3", "react-native-safe-area-context": "5.6.2", - "react-native-screens": "4.18.0", + "react-native-screens": "4.23.0", "react-native-web": "0.21.2", "react-native-webview": "13.16.0", "react-native-zoom-toolkit": "5.0.1", - "react-window": "2.2.5", + "react-window": "2.2.6", "shallowequal": "1.1.0", "uint8array-extras": "1.5.0", "url-parse": "1.5.10", "use-debounce": "10.1.0", "util": "0.12.5", - "zustand": "5.0.10" + "zustand": "5.0.11" }, "devDependencies": { - "@babel/core": "7.28.5", - "@babel/node": "7.28.0", - "@babel/preset-env": "7.28.5", + "@babel/core": "7.29.0", + "@babel/node": "7.29.0", + "@babel/preset-env": "7.29.0", "@babel/preset-react": "7.28.5", "@babel/preset-typescript": "7.28.5", "@electron/packager": "18.4.4", @@ -149,7 +149,7 @@ "@types/google-libphonenumber": "7.4.30", "@types/lodash": "4.17.23", "@types/lodash-es": "4.17.12", - "@types/react": "19.2.8", + "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@types/react-is": "19.2.0", "@types/react-list": "0.8.12", @@ -161,22 +161,22 @@ "babel-plugin-module-resolver": "5.0.2", "babel-plugin-react-compiler": "1.0.0", "babel-plugin-react-native-web": "0.21.2", - "babel-preset-expo": "54.0.9", + "babel-preset-expo": "54.0.10", "cross-env": "7.0.3", - "css-loader": "7.1.2", - "electron": "39.2.7", - "eslint": "9.39.2", + "css-loader": "7.1.3", + "electron": "40.4.0", + "eslint": "10.0.0", "eslint-plugin-deprecation": "3.0.0", "eslint-plugin-promise": "7.2.1", "eslint-plugin-react": "7.37.5", "eslint-plugin-react-compiler": "19.1.0-rc.2", "eslint-plugin-react-hooks": "7.0.1", "fs-extra": "11.3.3", - "html-webpack-plugin": "5.6.5", + "html-webpack-plugin": "5.6.6", "json5": "2.2.3", "null-loader": "4.0.1", "patch-package": "8.0.1", - "prettier": "3.8.0", + "prettier": "3.8.1", "react-refresh": "0.18.0", "react-scan": "0.4.3", "react-test-renderer": "19.1.0", @@ -184,15 +184,15 @@ "style-loader": "4.0.0", "terser-webpack-plugin": "5.3.16", "typescript": "5.9.3", - "typescript-eslint": "8.53.0", - "webpack": "5.104.1", + "typescript-eslint": "8.55.0", + "webpack": "5.105.2", "webpack-cli": "6.0.1", "webpack-dev-server": "5.2.3", "webpack-merge": "6.0.1" }, "resolutions": { "**/purepack": "keybase/nullModule", - "**/@types/react": "19.2.8" + "**/@types/react": "19.2.14" }, "typecoverage": { "detail": true, diff --git a/shared/todo.txt b/shared/todo.txt index ae8511c890cb..a13900cfbaa4 100644 --- a/shared/todo.txt +++ b/shared/todo.txt @@ -1,8 +1,8 @@ -android: +TOOD: +react-native-screens header doesn't handle dyanmic colors still https://github.com/software-mansion/react-native-screens/issues/3570 -ios: -input paste view removed <<<<<<<<<<<< +ios: ipad: expo-av to expo-video / expo-audio (not ready yet can't get video size...), missing stuff we need like on full screen change diff --git a/shared/yarn.lock b/shared/yarn.lock index 369c399aa434..5667c8ecec8e 100644 --- a/shared/yarn.lock +++ b/shared/yarn.lock @@ -23,12 +23,47 @@ js-tokens "^4.0.0" picocolors "^1.1.1" -"@babel/compat-data@^7.27.2", "@babel/compat-data@^7.27.7", "@babel/compat-data@^7.28.5": +"@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" + integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== + dependencies: + "@babel/helper-validator-identifier" "^7.28.5" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2", "@babel/compat-data@^7.27.7": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.5.tgz#a8a4962e1567121ac0b3b487f52107443b455c7f" integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA== -"@babel/core@7.28.5", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.20.0", "@babel/core@^7.24.4", "@babel/core@^7.25.2", "@babel/core@^7.26.0": +"@babel/compat-data@^7.28.6", "@babel/compat-data@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.0.tgz#00d03e8c0ac24dd9be942c5370990cbe1f17d88d" + integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg== + +"@babel/core@7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.0.tgz#5286ad785df7f79d656e88ce86e650d16ca5f322" + integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helpers" "^7.28.6" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.20.0", "@babel/core@^7.24.4", "@babel/core@^7.25.2", "@babel/core@^7.26.0": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.5.tgz#4c81b35e51e1b734f510c99b07dfbc7bbbb48f7e" integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw== @@ -69,6 +104,17 @@ "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" +"@babel/generator@^7.29.0": + version "7.29.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" + integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw== + dependencies: + "@babel/parser" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + "@babel/helper-annotate-as-pure@^7.27.1", "@babel/helper-annotate-as-pure@^7.27.3": version "7.27.3" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5" @@ -87,6 +133,17 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-compilation-targets@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" + integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== + dependencies: + "@babel/compat-data" "^7.28.6" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.27.1", "@babel/helper-create-class-features-plugin@^7.28.3", "@babel/helper-create-class-features-plugin@^7.28.5": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz#472d0c28028850968979ad89f173594a6995da46" @@ -100,7 +157,20 @@ "@babel/traverse" "^7.28.5" semver "^6.3.1" -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.27.1": +"@babel/helper-create-class-features-plugin@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz#611ff5482da9ef0db6291bcd24303400bca170fb" + integrity sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-member-expression-to-functions" "^7.28.5" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/helper-replace-supers" "^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/traverse" "^7.28.6" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.27.1", "@babel/helper-create-regexp-features-plugin@^7.28.5": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz#7c1ddd64b2065c7f78034b25b43346a7e19ed997" integrity sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw== @@ -120,6 +190,17 @@ lodash.debounce "^4.0.8" resolve "^1.22.10" +"@babel/helper-define-polyfill-provider@^0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz#714dfe33d8bd710f556df59953720f6eeb6c1a14" + integrity sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA== + dependencies: + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + debug "^4.4.3" + lodash.debounce "^4.0.8" + resolve "^1.22.11" + "@babel/helper-globals@^7.28.0": version "7.28.0" resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" @@ -141,6 +222,14 @@ "@babel/traverse" "^7.27.1" "@babel/types" "^7.27.1" +"@babel/helper-module-imports@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" + integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw== + dependencies: + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" + "@babel/helper-module-transforms@^7.27.1", "@babel/helper-module-transforms@^7.28.3": version "7.28.3" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz#a2b37d3da3b2344fe085dab234426f2b9a2fa5f6" @@ -150,6 +239,15 @@ "@babel/helper-validator-identifier" "^7.27.1" "@babel/traverse" "^7.28.3" +"@babel/helper-module-transforms@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" + integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== + dependencies: + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.6" + "@babel/helper-optimise-call-expression@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200" @@ -162,6 +260,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== +"@babel/helper-plugin-utils@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" + integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== + "@babel/helper-remap-async-to-generator@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz#4601d5c7ce2eb2aea58328d43725523fcd362ce6" @@ -180,6 +283,15 @@ "@babel/helper-optimise-call-expression" "^7.27.1" "@babel/traverse" "^7.27.1" +"@babel/helper-replace-supers@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz#94aa9a1d7423a00aead3f204f78834ce7d53fe44" + integrity sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.28.5" + "@babel/helper-optimise-call-expression" "^7.27.1" + "@babel/traverse" "^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56" @@ -220,6 +332,14 @@ "@babel/template" "^7.27.2" "@babel/types" "^7.28.4" +"@babel/helpers@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" + integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw== + dependencies: + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.6" + "@babel/highlight@^7.10.4": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.9.tgz#8141ce68fc73757946f983b343f1231f4691acc6" @@ -230,14 +350,14 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/node@7.28.0": - version "7.28.0" - resolved "https://registry.yarnpkg.com/@babel/node/-/node-7.28.0.tgz#fe52d05121ca064e6919215ffe54fea480a8746f" - integrity sha512-6u1Mmn3SIMUH8uwTq543L062X3JDgms9HPf06o/pIGdDjeD/zNQ+dfZPQD27sCyvtP0ZOlJtwnl2RIdPe9bHeQ== +"@babel/node@7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/node/-/node-7.29.0.tgz#278d903d17bf80d361ed6ac9552125eebd5eab5f" + integrity sha512-9UeU8F3rx2lOZXneEW2HTnTYdA8+fXP0kr54tk7d0fPomWNlZ6WJ2H9lunr5dSvr8FNY0CDnop3Km6jZ5NAUsQ== dependencies: - "@babel/register" "^7.27.1" + "@babel/register" "^7.28.6" commander "^6.2.0" - core-js "^3.30.2" + core-js "^3.48.0" node-environment-flags "^1.0.5" regenerator-runtime "^0.14.0" v8flags "^3.1.1" @@ -249,6 +369,13 @@ dependencies: "@babel/types" "^7.28.5" +"@babel/parser@^7.28.6", "@babel/parser@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.0.tgz#669ef345add7d057e92b7ed15f0bac07611831b6" + integrity sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww== + dependencies: + "@babel/types" "^7.29.0" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.28.5": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz#fbde57974707bbfa0376d34d425ff4fa6c732421" @@ -280,13 +407,13 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" "@babel/plugin-transform-optional-chaining" "^7.27.1" -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.28.3": - version "7.28.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz#373f6e2de0016f73caf8f27004f61d167743742a" - integrity sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw== +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz#0e8289cec28baaf05d54fd08d81ae3676065f69f" + integrity sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - "@babel/traverse" "^7.28.3" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/traverse" "^7.28.6" "@babel/plugin-proposal-decorators@^7.12.9": version "7.28.0" @@ -373,20 +500,27 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-syntax-import-assertions@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz#88894aefd2b03b5ee6ad1562a7c8e1587496aecd" - integrity sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg== +"@babel/plugin-syntax-import-assertions@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz#ae9bc1923a6ba527b70104dd2191b0cd872c8507" + integrity sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-plugin-utils" "^7.28.6" -"@babel/plugin-syntax-import-attributes@^7.24.7", "@babel/plugin-syntax-import-attributes@^7.27.1": +"@babel/plugin-syntax-import-attributes@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz#34c017d54496f9b11b61474e7ea3dfd5563ffe07" integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== dependencies: "@babel/helper-plugin-utils" "^7.27.1" +"@babel/plugin-syntax-import-attributes@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" + integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" @@ -486,7 +620,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-async-generator-functions@^7.25.4", "@babel/plugin-transform-async-generator-functions@^7.28.0": +"@babel/plugin-transform-async-generator-functions@^7.25.4": version "7.28.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz#1276e6c7285ab2cd1eccb0bc7356b7a69ff842c2" integrity sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q== @@ -495,7 +629,16 @@ "@babel/helper-remap-async-to-generator" "^7.27.1" "@babel/traverse" "^7.28.0" -"@babel/plugin-transform-async-to-generator@^7.24.7", "@babel/plugin-transform-async-to-generator@^7.27.1": +"@babel/plugin-transform-async-generator-functions@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz#63ed829820298f0bf143d5a4a68fb8c06ffd742f" + integrity sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-remap-async-to-generator" "^7.27.1" + "@babel/traverse" "^7.29.0" + +"@babel/plugin-transform-async-to-generator@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz#9a93893b9379b39466c74474f55af03de78c66e7" integrity sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA== @@ -504,6 +647,15 @@ "@babel/helper-plugin-utils" "^7.27.1" "@babel/helper-remap-async-to-generator" "^7.27.1" +"@babel/plugin-transform-async-to-generator@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz#bd97b42237b2d1bc90d74bcb486c39be5b4d7e77" + integrity sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g== + dependencies: + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-remap-async-to-generator" "^7.27.1" + "@babel/plugin-transform-block-scoped-functions@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz#558a9d6e24cf72802dd3b62a4b51e0d62c0f57f9" @@ -511,14 +663,21 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-block-scoping@^7.25.0", "@babel/plugin-transform-block-scoping@^7.28.5": +"@babel/plugin-transform-block-scoping@^7.25.0": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz#e0d3af63bd8c80de2e567e690a54e84d85eb16f6" integrity sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g== dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-class-properties@7.27.1", "@babel/plugin-transform-class-properties@^7.25.4", "@babel/plugin-transform-class-properties@^7.27.1": +"@babel/plugin-transform-block-scoping@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz#e1ef5633448c24e76346125c2534eeb359699a99" + integrity sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-class-properties@7.27.1", "@babel/plugin-transform-class-properties@^7.25.4": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz#dd40a6a370dfd49d32362ae206ddaf2bb082a925" integrity sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA== @@ -526,7 +685,15 @@ "@babel/helper-create-class-features-plugin" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-class-static-block@^7.27.1", "@babel/plugin-transform-class-static-block@^7.28.3": +"@babel/plugin-transform-class-properties@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz#d274a4478b6e782d9ea987fda09bdb6d28d66b72" + integrity sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-class-static-block@^7.27.1": version "7.28.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz#d1b8e69b54c9993bc558203e1f49bfc979bfd852" integrity sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg== @@ -534,7 +701,15 @@ "@babel/helper-create-class-features-plugin" "^7.28.3" "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-classes@7.28.4", "@babel/plugin-transform-classes@^7.25.4", "@babel/plugin-transform-classes@^7.28.4": +"@babel/plugin-transform-class-static-block@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz#1257491e8259c6d125ac4d9a6f39f9d2bf3dba70" + integrity sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-classes@7.28.4", "@babel/plugin-transform-classes@^7.25.4": version "7.28.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz#75d66175486788c56728a73424d67cbc7473495c" integrity sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA== @@ -546,7 +721,19 @@ "@babel/helper-replace-supers" "^7.27.1" "@babel/traverse" "^7.28.4" -"@babel/plugin-transform-computed-properties@^7.24.7", "@babel/plugin-transform-computed-properties@^7.27.1": +"@babel/plugin-transform-classes@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz#8f6fb79ba3703978e701ce2a97e373aae7dda4b7" + integrity sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-globals" "^7.28.0" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-replace-supers" "^7.28.6" + "@babel/traverse" "^7.28.6" + +"@babel/plugin-transform-computed-properties@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz#81662e78bf5e734a97982c2b7f0a793288ef3caa" integrity sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw== @@ -554,6 +741,14 @@ "@babel/helper-plugin-utils" "^7.27.1" "@babel/template" "^7.27.1" +"@babel/plugin-transform-computed-properties@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz#936824fc71c26cb5c433485776d79c8e7b0202d2" + integrity sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/template" "^7.28.6" + "@babel/plugin-transform-destructuring@^7.24.8", "@babel/plugin-transform-destructuring@^7.28.0", "@babel/plugin-transform-destructuring@^7.28.5": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz#b8402764df96179a2070bb7b501a1586cf8ad7a7" @@ -562,13 +757,13 @@ "@babel/helper-plugin-utils" "^7.27.1" "@babel/traverse" "^7.28.5" -"@babel/plugin-transform-dotall-regex@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz#aa6821de864c528b1fecf286f0a174e38e826f4d" - integrity sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw== +"@babel/plugin-transform-dotall-regex@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz#def31ed84e0fb6e25c71e53c124e7b76a4ab8e61" + integrity sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-transform-duplicate-keys@^7.27.1": version "7.27.1" @@ -577,13 +772,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz#5043854ca620a94149372e69030ff8cb6a9eb0ec" - integrity sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ== +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz#8014b8a6cfd0e7b92762724443bf0d2400f26df1" + integrity sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-transform-dynamic-import@^7.27.1": version "7.27.1" @@ -592,20 +787,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-explicit-resource-management@^7.28.0": - version "7.28.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz#45be6211b778dbf4b9d54c4e8a2b42fa72e09a1a" - integrity sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ== +"@babel/plugin-transform-explicit-resource-management@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz#dd6788f982c8b77e86779d1d029591e39d9d8be7" + integrity sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" - "@babel/plugin-transform-destructuring" "^7.28.0" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-transform-destructuring" "^7.28.5" -"@babel/plugin-transform-exponentiation-operator@^7.28.5": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz#7cc90a8170e83532676cfa505278e147056e94fe" - integrity sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw== +"@babel/plugin-transform-exponentiation-operator@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz#5e477eb7eafaf2ab5537a04aaafcf37e2d7f1091" + integrity sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-transform-export-namespace-from@^7.25.9", "@babel/plugin-transform-export-namespace-from@^7.27.1": version "7.27.1" @@ -639,12 +834,12 @@ "@babel/helper-plugin-utils" "^7.27.1" "@babel/traverse" "^7.27.1" -"@babel/plugin-transform-json-strings@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz#a2e0ce6ef256376bd527f290da023983527a4f4c" - integrity sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q== +"@babel/plugin-transform-json-strings@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz#4c8c15b2dc49e285d110a4cf3dac52fd2dfc3038" + integrity sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-transform-literals@^7.25.2", "@babel/plugin-transform-literals@^7.27.1": version "7.27.1" @@ -653,13 +848,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-logical-assignment-operators@^7.24.7", "@babel/plugin-transform-logical-assignment-operators@^7.28.5": +"@babel/plugin-transform-logical-assignment-operators@^7.24.7": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz#d028fd6db8c081dee4abebc812c2325e24a85b0e" integrity sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA== dependencies: "@babel/helper-plugin-utils" "^7.27.1" +"@babel/plugin-transform-logical-assignment-operators@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz#53028a3d77e33c50ef30a8fce5ca17065936e605" + integrity sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-transform-member-expression-literals@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz#37b88ba594d852418e99536f5612f795f23aeaf9" @@ -683,15 +885,23 @@ "@babel/helper-module-transforms" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-modules-systemjs@^7.28.5": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz#7439e592a92d7670dfcb95d0cbc04bd3e64801d2" - integrity sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew== +"@babel/plugin-transform-modules-commonjs@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz#c0232e0dfe66a734cc4ad0d5e75fc3321b6fdef1" + integrity sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA== dependencies: - "@babel/helper-module-transforms" "^7.28.3" - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-modules-systemjs@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz#e458a95a17807c415924106a3ff188a3b8dee964" + integrity sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ== + dependencies: + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/helper-validator-identifier" "^7.28.5" - "@babel/traverse" "^7.28.5" + "@babel/traverse" "^7.29.0" "@babel/plugin-transform-modules-umd@^7.27.1": version "7.27.1" @@ -701,7 +911,7 @@ "@babel/helper-module-transforms" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-named-capturing-groups-regex@^7.24.7", "@babel/plugin-transform-named-capturing-groups-regex@^7.27.1": +"@babel/plugin-transform-named-capturing-groups-regex@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz#f32b8f7818d8fc0cc46ee20a8ef75f071af976e1" integrity sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng== @@ -709,6 +919,14 @@ "@babel/helper-create-regexp-features-plugin" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" +"@babel/plugin-transform-named-capturing-groups-regex@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz#a26cd51e09c4718588fc4cce1c5d1c0152102d6a" + integrity sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-transform-new-target@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz#259c43939728cad1706ac17351b7e6a7bea1abeb" @@ -716,21 +934,35 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "@babel/plugin-transform-nullish-coalescing-operator@^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator@^7.27.1": +"@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "@babel/plugin-transform-nullish-coalescing-operator@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz#4f9d3153bf6782d73dd42785a9d22d03197bc91d" integrity sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA== dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-numeric-separator@^7.24.7", "@babel/plugin-transform-numeric-separator@^7.27.1": +"@babel/plugin-transform-nullish-coalescing-operator@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz#9bc62096e90ab7a887f3ca9c469f6adec5679757" + integrity sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-numeric-separator@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz#614e0b15cc800e5997dadd9bd6ea524ed6c819c6" integrity sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw== dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-object-rest-spread@^7.24.7", "@babel/plugin-transform-object-rest-spread@^7.28.4": +"@babel/plugin-transform-numeric-separator@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz#1310b0292762e7a4a335df5f580c3320ee7d9e9f" + integrity sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-object-rest-spread@^7.24.7": version "7.28.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz#9ee1ceca80b3e6c4bac9247b2149e36958f7f98d" integrity sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew== @@ -741,6 +973,17 @@ "@babel/plugin-transform-parameters" "^7.27.7" "@babel/traverse" "^7.28.4" +"@babel/plugin-transform-object-rest-spread@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz#fdd4bc2d72480db6ca42aed5c051f148d7b067f7" + integrity sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA== + dependencies: + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-transform-destructuring" "^7.28.5" + "@babel/plugin-transform-parameters" "^7.27.7" + "@babel/traverse" "^7.28.6" + "@babel/plugin-transform-object-super@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz#1c932cd27bf3874c43a5cac4f43ebf970c9871b5" @@ -749,13 +992,20 @@ "@babel/helper-plugin-utils" "^7.27.1" "@babel/helper-replace-supers" "^7.27.1" -"@babel/plugin-transform-optional-catch-binding@^7.24.7", "@babel/plugin-transform-optional-catch-binding@^7.27.1": +"@babel/plugin-transform-optional-catch-binding@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz#84c7341ebde35ccd36b137e9e45866825072a30c" integrity sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q== dependencies: "@babel/helper-plugin-utils" "^7.27.1" +"@babel/plugin-transform-optional-catch-binding@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz#75107be14c78385978201a49c86414a150a20b4c" + integrity sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-transform-optional-chaining@7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz#874ce3c4f06b7780592e946026eb76a32830454f" @@ -764,7 +1014,7 @@ "@babel/helper-plugin-utils" "^7.27.1" "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" -"@babel/plugin-transform-optional-chaining@^7.24.8", "@babel/plugin-transform-optional-chaining@^7.27.1", "@babel/plugin-transform-optional-chaining@^7.28.5": +"@babel/plugin-transform-optional-chaining@^7.24.8", "@babel/plugin-transform-optional-chaining@^7.27.1": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz#8238c785f9d5c1c515a90bf196efb50d075a4b26" integrity sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ== @@ -772,6 +1022,14 @@ "@babel/helper-plugin-utils" "^7.27.1" "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" +"@babel/plugin-transform-optional-chaining@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz#926cf150bd421fc8362753e911b4a1b1ce4356cd" + integrity sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-transform-parameters@^7.24.7", "@babel/plugin-transform-parameters@^7.27.7": version "7.27.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz#1fd2febb7c74e7d21cf3b05f7aebc907940af53a" @@ -779,7 +1037,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-private-methods@^7.24.7", "@babel/plugin-transform-private-methods@^7.27.1": +"@babel/plugin-transform-private-methods@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz#fdacbab1c5ed81ec70dfdbb8b213d65da148b6af" integrity sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA== @@ -787,7 +1045,15 @@ "@babel/helper-create-class-features-plugin" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-private-property-in-object@^7.24.7", "@babel/plugin-transform-private-property-in-object@^7.27.1": +"@babel/plugin-transform-private-methods@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz#c76fbfef3b86c775db7f7c106fff544610bdb411" + integrity sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-private-property-in-object@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz#4dbbef283b5b2f01a21e81e299f76e35f900fb11" integrity sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ== @@ -796,6 +1062,15 @@ "@babel/helper-create-class-features-plugin" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" +"@babel/plugin-transform-private-property-in-object@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz#4fafef1e13129d79f1d75ac180c52aafefdb2811" + integrity sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.27.3" + "@babel/helper-create-class-features-plugin" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/plugin-transform-property-literals@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz#07eafd618800591e88073a0af1b940d9a42c6424" @@ -850,20 +1125,27 @@ "@babel/helper-annotate-as-pure" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-regenerator@^7.24.7", "@babel/plugin-transform-regenerator@^7.28.4": +"@babel/plugin-transform-regenerator@^7.24.7": version "7.28.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz#9d3fa3bebb48ddd0091ce5729139cd99c67cea51" integrity sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA== dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-regexp-modifiers@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz#df9ba5577c974e3f1449888b70b76169998a6d09" - integrity sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA== +"@babel/plugin-transform-regenerator@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz#dec237cec1b93330876d6da9992c4abd42c9d18b" + integrity sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-transform-regexp-modifiers@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz#7ef0163bd8b4a610481b2509c58cf217f065290b" + integrity sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-transform-reserved-words@^7.27.1": version "7.27.1" @@ -891,7 +1173,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-spread@^7.24.7", "@babel/plugin-transform-spread@^7.27.1": +"@babel/plugin-transform-spread@^7.24.7": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz#1a264d5fc12750918f50e3fe3e24e437178abb08" integrity sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q== @@ -899,6 +1181,14 @@ "@babel/helper-plugin-utils" "^7.27.1" "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" +"@babel/plugin-transform-spread@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz#40a2b423f6db7b70f043ad027a58bcb44a9757b6" + integrity sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers" "^7.27.1" + "@babel/plugin-transform-sticky-regex@^7.24.7", "@babel/plugin-transform-sticky-regex@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz#18984935d9d2296843a491d78a014939f7dcd280" @@ -938,13 +1228,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-unicode-property-regex@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz#bdfe2d3170c78c5691a3c3be934c8c0087525956" - integrity sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q== +"@babel/plugin-transform-unicode-property-regex@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz#63a7a6c21a0e75dae9b1861454111ea5caa22821" + integrity sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-transform-unicode-regex@7.27.1", "@babel/plugin-transform-unicode-regex@^7.24.7", "@babel/plugin-transform-unicode-regex@^7.27.1": version "7.27.1" @@ -954,88 +1244,88 @@ "@babel/helper-create-regexp-features-plugin" "^7.27.1" "@babel/helper-plugin-utils" "^7.27.1" -"@babel/plugin-transform-unicode-sets-regex@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz#6ab706d10f801b5c72da8bb2548561fa04193cd1" - integrity sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw== +"@babel/plugin-transform-unicode-sets-regex@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz#924912914e5df9fe615ec472f88ff4788ce04d4e" + integrity sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.27.1" - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-create-regexp-features-plugin" "^7.28.5" + "@babel/helper-plugin-utils" "^7.28.6" -"@babel/preset-env@7.28.5": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.28.5.tgz#82dd159d1563f219a1ce94324b3071eb89e280b0" - integrity sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg== +"@babel/preset-env@7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.29.0.tgz#c55db400c515a303662faaefd2d87e796efa08d0" + integrity sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w== dependencies: - "@babel/compat-data" "^7.28.5" - "@babel/helper-compilation-targets" "^7.27.2" - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/compat-data" "^7.29.0" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/helper-validator-option" "^7.27.1" "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.28.5" "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.27.1" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.27.1" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.27.1" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.28.3" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.28.6" "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" - "@babel/plugin-syntax-import-assertions" "^7.27.1" - "@babel/plugin-syntax-import-attributes" "^7.27.1" + "@babel/plugin-syntax-import-assertions" "^7.28.6" + "@babel/plugin-syntax-import-attributes" "^7.28.6" "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" "@babel/plugin-transform-arrow-functions" "^7.27.1" - "@babel/plugin-transform-async-generator-functions" "^7.28.0" - "@babel/plugin-transform-async-to-generator" "^7.27.1" + "@babel/plugin-transform-async-generator-functions" "^7.29.0" + "@babel/plugin-transform-async-to-generator" "^7.28.6" "@babel/plugin-transform-block-scoped-functions" "^7.27.1" - "@babel/plugin-transform-block-scoping" "^7.28.5" - "@babel/plugin-transform-class-properties" "^7.27.1" - "@babel/plugin-transform-class-static-block" "^7.28.3" - "@babel/plugin-transform-classes" "^7.28.4" - "@babel/plugin-transform-computed-properties" "^7.27.1" + "@babel/plugin-transform-block-scoping" "^7.28.6" + "@babel/plugin-transform-class-properties" "^7.28.6" + "@babel/plugin-transform-class-static-block" "^7.28.6" + "@babel/plugin-transform-classes" "^7.28.6" + "@babel/plugin-transform-computed-properties" "^7.28.6" "@babel/plugin-transform-destructuring" "^7.28.5" - "@babel/plugin-transform-dotall-regex" "^7.27.1" + "@babel/plugin-transform-dotall-regex" "^7.28.6" "@babel/plugin-transform-duplicate-keys" "^7.27.1" - "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.27.1" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.29.0" "@babel/plugin-transform-dynamic-import" "^7.27.1" - "@babel/plugin-transform-explicit-resource-management" "^7.28.0" - "@babel/plugin-transform-exponentiation-operator" "^7.28.5" + "@babel/plugin-transform-explicit-resource-management" "^7.28.6" + "@babel/plugin-transform-exponentiation-operator" "^7.28.6" "@babel/plugin-transform-export-namespace-from" "^7.27.1" "@babel/plugin-transform-for-of" "^7.27.1" "@babel/plugin-transform-function-name" "^7.27.1" - "@babel/plugin-transform-json-strings" "^7.27.1" + "@babel/plugin-transform-json-strings" "^7.28.6" "@babel/plugin-transform-literals" "^7.27.1" - "@babel/plugin-transform-logical-assignment-operators" "^7.28.5" + "@babel/plugin-transform-logical-assignment-operators" "^7.28.6" "@babel/plugin-transform-member-expression-literals" "^7.27.1" "@babel/plugin-transform-modules-amd" "^7.27.1" - "@babel/plugin-transform-modules-commonjs" "^7.27.1" - "@babel/plugin-transform-modules-systemjs" "^7.28.5" + "@babel/plugin-transform-modules-commonjs" "^7.28.6" + "@babel/plugin-transform-modules-systemjs" "^7.29.0" "@babel/plugin-transform-modules-umd" "^7.27.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.27.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.29.0" "@babel/plugin-transform-new-target" "^7.27.1" - "@babel/plugin-transform-nullish-coalescing-operator" "^7.27.1" - "@babel/plugin-transform-numeric-separator" "^7.27.1" - "@babel/plugin-transform-object-rest-spread" "^7.28.4" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.28.6" + "@babel/plugin-transform-numeric-separator" "^7.28.6" + "@babel/plugin-transform-object-rest-spread" "^7.28.6" "@babel/plugin-transform-object-super" "^7.27.1" - "@babel/plugin-transform-optional-catch-binding" "^7.27.1" - "@babel/plugin-transform-optional-chaining" "^7.28.5" + "@babel/plugin-transform-optional-catch-binding" "^7.28.6" + "@babel/plugin-transform-optional-chaining" "^7.28.6" "@babel/plugin-transform-parameters" "^7.27.7" - "@babel/plugin-transform-private-methods" "^7.27.1" - "@babel/plugin-transform-private-property-in-object" "^7.27.1" + "@babel/plugin-transform-private-methods" "^7.28.6" + "@babel/plugin-transform-private-property-in-object" "^7.28.6" "@babel/plugin-transform-property-literals" "^7.27.1" - "@babel/plugin-transform-regenerator" "^7.28.4" - "@babel/plugin-transform-regexp-modifiers" "^7.27.1" + "@babel/plugin-transform-regenerator" "^7.29.0" + "@babel/plugin-transform-regexp-modifiers" "^7.28.6" "@babel/plugin-transform-reserved-words" "^7.27.1" "@babel/plugin-transform-shorthand-properties" "^7.27.1" - "@babel/plugin-transform-spread" "^7.27.1" + "@babel/plugin-transform-spread" "^7.28.6" "@babel/plugin-transform-sticky-regex" "^7.27.1" "@babel/plugin-transform-template-literals" "^7.27.1" "@babel/plugin-transform-typeof-symbol" "^7.27.1" "@babel/plugin-transform-unicode-escapes" "^7.27.1" - "@babel/plugin-transform-unicode-property-regex" "^7.27.1" + "@babel/plugin-transform-unicode-property-regex" "^7.28.6" "@babel/plugin-transform-unicode-regex" "^7.27.1" - "@babel/plugin-transform-unicode-sets-regex" "^7.27.1" + "@babel/plugin-transform-unicode-sets-regex" "^7.28.6" "@babel/preset-modules" "0.1.6-no-external-plugins" - babel-plugin-polyfill-corejs2 "^0.4.14" - babel-plugin-polyfill-corejs3 "^0.13.0" - babel-plugin-polyfill-regenerator "^0.6.5" - core-js-compat "^3.43.0" + babel-plugin-polyfill-corejs2 "^0.4.15" + babel-plugin-polyfill-corejs3 "^0.14.0" + babel-plugin-polyfill-regenerator "^0.6.6" + core-js-compat "^3.48.0" semver "^6.3.1" "@babel/preset-modules@0.1.6-no-external-plugins": @@ -1081,10 +1371,10 @@ "@babel/plugin-transform-modules-commonjs" "^7.27.1" "@babel/plugin-transform-typescript" "^7.28.5" -"@babel/register@^7.27.1": - version "7.28.3" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.28.3.tgz#abd8a3753480c799bdaf9c9092d6745d16e052c2" - integrity sha512-CieDOtd8u208eI49bYl4z1J22ySFw87IGwE+IswFEExH7e3rLgKb0WNQeumnacQ1+VoDJLYI5QFA3AJZuyZQfA== +"@babel/register@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.28.6.tgz#f54461dd32f6a418c1eb1f583c95ed0b7266ea4c" + integrity sha512-pgcbbEl/dWQYb6L6Yew6F94rdwygfuv+vJ/tXfwIOYAfPB6TNWpXUMEtEq3YuTeHRdvMIhvz13bkT9CNaS+wqA== dependencies: clone-deep "^4.0.1" find-cache-dir "^2.0.0" @@ -1106,6 +1396,15 @@ "@babel/parser" "^7.27.2" "@babel/types" "^7.27.1" +"@babel/template@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" + integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + "@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.5.tgz#450cab9135d21a7a2ca9d2d35aa05c20e68c360b" @@ -1132,6 +1431,19 @@ "@babel/types" "^7.28.5" debug "^4.3.1" +"@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" + integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/types" "^7.29.0" + debug "^4.3.1" + "@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.2", "@babel/types@^7.26.0", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.2", "@babel/types@^7.28.4", "@babel/types@^7.28.5", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b" @@ -1140,6 +1452,14 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" +"@babel/types@^7.28.6", "@babel/types@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" + integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + "@clack/core@0.3.5", "@clack/core@^0.3.5": version "0.3.5" resolved "https://registry.yarnpkg.com/@clack/core/-/core-0.3.5.tgz#3e1454c83a329353cc3a6ff8491e4284d49565bb" @@ -1424,71 +1744,51 @@ dependencies: eslint-visitor-keys "^3.4.3" -"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.12.2": +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.2": version "4.12.2" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== -"@eslint/config-array@^0.21.1": - version "0.21.1" - resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.1.tgz#7d1b0060fea407f8301e932492ba8c18aff29713" - integrity sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA== +"@eslint/config-array@^0.23.0": + version "0.23.1" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.23.1.tgz#908223da7b9148f1af5bfb3144b77a9387a89446" + integrity sha512-uVSdg/V4dfQmTjJzR0szNczjOH/J+FyUMMjYtr07xFRXR7EDf9i1qdxrD0VusZH9knj1/ecxzCQQxyic5NzAiA== dependencies: - "@eslint/object-schema" "^2.1.7" + "@eslint/object-schema" "^3.0.1" debug "^4.3.1" - minimatch "^3.1.2" + minimatch "^10.1.1" -"@eslint/config-helpers@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz#1bd006ceeb7e2e55b2b773ab318d300e1a66aeda" - integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== +"@eslint/config-helpers@^0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.5.2.tgz#314c7b03d02a371ad8c0a7f6821d5a8a8437ba9d" + integrity sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ== dependencies: - "@eslint/core" "^0.17.0" + "@eslint/core" "^1.1.0" -"@eslint/core@^0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.17.0.tgz#77225820413d9617509da9342190a2019e78761c" - integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== +"@eslint/core@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-1.1.0.tgz#51f5cd970e216fbdae6721ac84491f57f965836d" + integrity sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw== dependencies: "@types/json-schema" "^7.0.15" -"@eslint/eslintrc@^3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964" - integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^10.0.1" - globals "^14.0.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/js@9.39.2": - version "9.39.2" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.39.2.tgz#2d4b8ec4c3ea13c1b3748e0c97ecd766bdd80599" - integrity sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA== - -"@eslint/object-schema@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.7.tgz#6e2126a1347e86a4dedf8706ec67ff8e107ebbad" - integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== +"@eslint/object-schema@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-3.0.1.tgz#9a1dc9af00d790dc79a9bf57a756e3cb2740ddb9" + integrity sha512-P9cq2dpr+LU8j3qbLygLcSZrl2/ds/pUpfnHNNuk5HW7mnngHs+6WSq5C9mO3rqRX8A1poxqLTC9cu0KOyJlBg== -"@eslint/plugin-kit@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz#9779e3fd9b7ee33571a57435cf4335a1794a6cb2" - integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== +"@eslint/plugin-kit@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz#e0cb12ec66719cb2211ad36499fb516f2a63899d" + integrity sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ== dependencies: - "@eslint/core" "^0.17.0" + "@eslint/core" "^1.1.0" levn "^0.4.1" -"@expo/cli@54.0.21": - version "54.0.21" - resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-54.0.21.tgz#196ea08f539535b26717e09661937b24b38f25e7" - integrity sha512-L/FdpyZDsg/Nq6xW6kfiyF9DUzKfLZCKFXEVZcDqCNar6bXxQVotQyvgexRvtUF5nLinuT/UafLOdC3FUALUmA== +"@expo/cli@54.0.23": + version "54.0.23" + resolved "https://registry.yarnpkg.com/@expo/cli/-/cli-54.0.23.tgz#e8a7dc4e1f2a8a5361afd80bcc352014b57a87ac" + integrity sha512-km0h72SFfQCmVycH/JtPFTVy69w6Lx1cHNDmfLfQqgKFYeeHTjx7LVDP4POHCtNxFP2UeRazrygJhlh4zz498g== dependencies: "@0no-co/graphql.web" "^1.0.8" "@expo/code-signing-certificates" "^0.0.6" @@ -1499,9 +1799,9 @@ "@expo/image-utils" "^0.8.8" "@expo/json-file" "^10.0.8" "@expo/metro" "~54.2.0" - "@expo/metro-config" "~54.0.13" + "@expo/metro-config" "~54.0.14" "@expo/osascript" "^2.3.8" - "@expo/package-manager" "^1.9.9" + "@expo/package-manager" "^1.9.10" "@expo/plist" "^0.4.8" "@expo/prebuild-config" "^54.0.8" "@expo/schema-utils" "^0.1.8" @@ -1724,10 +2024,10 @@ "@babel/code-frame" "~7.10.4" json5 "^2.2.3" -"@expo/metro-config@54.0.13", "@expo/metro-config@~54.0.13": - version "54.0.13" - resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-54.0.13.tgz#a78f0da6ba7eca4d3b1fa0fa2487be4d947e4fd6" - integrity sha512-RRufMCgLR2Za1WGsh02OatIJo5qZFt31yCnIOSfoubNc3Qqe92Z41pVsbrFnmw5CIaisv1NgdBy05DHe7pEyuw== +"@expo/metro-config@54.0.14", "@expo/metro-config@~54.0.14": + version "54.0.14" + resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-54.0.14.tgz#e455dfb2bae9473ec665bc830d651baa709c1e8a" + integrity sha512-hxpLyDfOR4L23tJ9W1IbJJsG7k4lv2sotohBm/kTYyiG+pe1SYCAWsRmgk+H42o/wWf/HQjE5k45S5TomGLxNA== dependencies: "@babel/code-frame" "^7.20.0" "@babel/core" "^7.20.0" @@ -1779,10 +2079,10 @@ "@expo/spawn-async" "^1.7.2" exec-async "^2.2.0" -"@expo/package-manager@^1.9.9": - version "1.9.9" - resolved "https://registry.yarnpkg.com/@expo/package-manager/-/package-manager-1.9.9.tgz#dd030d2bccebd095e02bfb6976852afaddcd122a" - integrity sha512-Nv5THOwXzPprMJwbnXU01iXSrCp3vJqly9M4EJ2GkKko9Ifer2ucpg7x6OUsE09/lw+npaoUnHMXwkw7gcKxlg== +"@expo/package-manager@^1.9.10": + version "1.9.10" + resolved "https://registry.yarnpkg.com/@expo/package-manager/-/package-manager-1.9.10.tgz#5da3f4943f6fa44ddd7f0efe32a360040edd734a" + integrity sha512-axJm+NOj3jVxep49va/+L3KkF3YW/dkV+RwzqUJedZrv4LeTqOG4rhrCaCPXHTvLqCTDKu6j0Xyd28N7mnxsGA== dependencies: "@expo/json-file" "^10.0.8" "@expo/spawn-async" "^1.7.2" @@ -2118,10 +2418,10 @@ resolved "https://registry.yarnpkg.com/@khanacademy/perseus-utils/-/perseus-utils-2.1.4.tgz#f87462f16781c7a40311ac0932e13a1f67ab9418" integrity sha512-TQLLUZQWc0K0gCLejNTd7G2y1qMhF3BtM9rBGvSObo10EVL4LwA2nCgm0FaPLowCp0ujweZACh9ty+xlekkGXA== -"@khanacademy/simple-markdown@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@khanacademy/simple-markdown/-/simple-markdown-2.1.4.tgz#1673e79fd1d4a2f4c3f697c5421b0a1289ed6f0e" - integrity sha512-2WBPGtnaCuMS2b6DewdXPbgy14QFo6V22FuMf2PxREQaAHakIOhjQ7sgeswN7ZdAZ1uyGi4TnDbN1qSgIbaC3Q== +"@khanacademy/simple-markdown@2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@khanacademy/simple-markdown/-/simple-markdown-2.2.1.tgz#3a477c2bcb026fbf25c0aa0272fbb9b3b0f7058c" + integrity sha512-9xmLOLIh//ZiWwQFtJETnV8Ha24J3KgHpcwrROjqjuXD3tNiNZrVMBBZU93Aw1/jeocA7p5jiYBrErZiqGlLag== dependencies: "@khanacademy/perseus-utils" "2.1.4" @@ -2142,10 +2442,10 @@ resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-2.8.0.tgz#4210deb771ee3912964f14a15ddfb5ff877e70b9" integrity sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ== -"@msgpack/msgpack@3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-3.1.2.tgz#fdd25cc2202297519798bbaf4689152ad9609e19" - integrity sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ== +"@msgpack/msgpack@3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-3.1.3.tgz#c4bff2b9539faf0882f3ee03537a7e9a4b3a7864" + integrity sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA== "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" @@ -2760,19 +3060,19 @@ invariant "^2.2.4" nullthrows "^1.1.1" -"@react-navigation/bottom-tabs@7.9.1": - version "7.9.1" - resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-7.9.1.tgz#1a228e68c85f27bb3f0d2b814bdddb25eeb60360" - integrity sha512-1MHn1b5tWFa8t8LXUvaNtlg5WGVXcNTsiV00ygQDBFDusMcu0ZPOU1exqELZwHf6kDntmTQE96/NRM+Cd2QR+A== +"@react-navigation/bottom-tabs@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-7.13.0.tgz#cef50768633cdbd272809aec7751ac37ce36dab0" + integrity sha512-qxxjRDpjhZ4vIZqG4rBU1Vx2jgOAO/ciUKc9sJqVlTM005E2E+aK1EaE3lGaBDyZxTpjonollAucZcqL7OTscQ== dependencies: - "@react-navigation/elements" "^2.9.4" + "@react-navigation/elements" "^2.9.5" color "^4.2.3" sf-symbols-typescript "^2.1.0" -"@react-navigation/core@7.13.7", "@react-navigation/core@^7.13.7": - version "7.13.7" - resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-7.13.7.tgz#1263903a703b5f183a08c22dfc5c3735ac4ef91c" - integrity sha512-k2ABo3250vq1ovOh/iVwXS6Hwr5PVRGXoPh/ewVFOOuEKTvOx9i//OBzt8EF+HokBxS2HBRlR2b+aCOmscRqBw== +"@react-navigation/core@7.14.0", "@react-navigation/core@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-7.14.0.tgz#d24f93d424ab33f645262dc4775e4708aa3d9a8b" + integrity sha512-tMpzskBzVp0E7CRNdNtJIdXjk54Kwe/TF9ViXAef+YFM1kSfGv4e/B2ozfXE+YyYgmh4WavTv8fkdJz1CNyu+g== dependencies: "@react-navigation/routers" "^7.5.3" escape-string-regexp "^4.0.0" @@ -2783,31 +3083,31 @@ use-latest-callback "^0.2.4" use-sync-external-store "^1.5.0" -"@react-navigation/elements@^2.9.4": - version "2.9.4" - resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-2.9.4.tgz#72101e7cf74e6952a303ffd3a69aab5e9ba178a8" - integrity sha512-TMFh+QzwesEuSaKpvZk4BFC5105t5gJs9eq+jG7jtfdlMKyrcFwheu2/dy1zfrW4WYbVcoMxhzFqCU4mKwI4fw== +"@react-navigation/elements@^2.9.5": + version "2.9.5" + resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-2.9.5.tgz#29f68c4975351724dcfe1d3bdc76c4d6dc65fc33" + integrity sha512-iHZU8rRN1014Upz73AqNVXDvSMZDh5/ktQ1CMe21rdgnOY79RWtHHBp9qOS3VtqlUVYGkuX5GEw5mDt4tKdl0g== dependencies: color "^4.2.3" use-latest-callback "^0.2.4" use-sync-external-store "^1.5.0" -"@react-navigation/native-stack@7.9.1": - version "7.9.1" - resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-7.9.1.tgz#0d8f576a9c2ca34344b114ae1e380ad0933dc7b1" - integrity sha512-DIRv72UliHvCWkBO1xwvik0maRka4aebn10huL9u4lPRXZZjumlMFHhA9z8vOaj02ri54m8pQUybRdbVzNeqgQ== +"@react-navigation/native-stack@7.12.0": + version "7.12.0" + resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-7.12.0.tgz#0511234ac6030ed6d716561a380cb2225541373c" + integrity sha512-XmNJsPshjkNsahgbxNgGWQUq4s1l6HqH/Fei4QsjBNn/0mTvVrRVZwJ1XrY9YhWYvyiYkAN6/OmarWQaQJ0otQ== dependencies: - "@react-navigation/elements" "^2.9.4" + "@react-navigation/elements" "^2.9.5" color "^4.2.3" sf-symbols-typescript "^2.1.0" warn-once "^0.1.1" -"@react-navigation/native@7.1.27": - version "7.1.27" - resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-7.1.27.tgz#5be53e9fac9f6173d229b334fe41c2208684bac2" - integrity sha512-kW7LGP/RrisktpGyizTKw6HwSeQJdXnAN9L8GyQJcJAlgL9YtfEg6yEyD5n9RWH90CL8G0cRyUhphKIAFf4lVw== +"@react-navigation/native@7.1.28": + version "7.1.28" + resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-7.1.28.tgz#1ee75cf3a8b3e4365f94c5d657bb3c015e387720" + integrity sha512-d1QDn+KNHfHGt3UIwOZvupvdsDdiHYZBEj7+wL2yDVo3tMezamYy60H9s3EnNVE1Ae1ty0trc7F2OKqo/RmsdQ== dependencies: - "@react-navigation/core" "^7.13.7" + "@react-navigation/core" "^7.14.0" escape-string-regexp "^4.0.0" fast-deep-equal "^3.1.3" nanoid "^3.3.11" @@ -2966,6 +3266,11 @@ "@types/estree" "*" "@types/json-schema" "*" +"@types/esrecurse@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@types/esrecurse/-/esrecurse-4.3.1.tgz#6f636af962fbe6191b830bd676ba5986926bccec" + integrity sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw== + "@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.6", "@types/estree@^1.0.8": version "1.0.8" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" @@ -3116,12 +3421,12 @@ dependencies: undici-types "~6.21.0" -"@types/node@^22.7.7": - version "22.19.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.1.tgz#1188f1ddc9f46b4cc3aec76749050b4e1f459b7b" - integrity sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ== +"@types/node@^24.9.0": + version "24.10.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.10.13.tgz#2fac25c0e30f3848e19912c3b8791a28370e9e07" + integrity sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg== dependencies: - undici-types "~6.21.0" + undici-types "~7.16.0" "@types/qs@*": version "6.14.0" @@ -3164,10 +3469,10 @@ resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.28.9.tgz#d24b4864c384e770c83275b3fe73fba00269c83b" integrity sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg== -"@types/react@*", "@types/react@19.2.8": - version "19.2.8" - resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.8.tgz#307011c9f5973a6abab8e17d0293f48843627994" - integrity sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg== +"@types/react@*", "@types/react@19.2.14": + version "19.2.14" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.14.tgz#39604929b5e3957e3a6fa0001dafb17c7af70bad" + integrity sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w== dependencies: csstype "^3.2.2" @@ -3267,16 +3572,16 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz#afb966c66a2fdc6158cf81118204a971a36d0fc5" - integrity sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg== +"@typescript-eslint/eslint-plugin@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.55.0.tgz#086d2ef661507b561f7b17f62d3179d692a0765f" + integrity sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ== dependencies: "@eslint-community/regexpp" "^4.12.2" - "@typescript-eslint/scope-manager" "8.53.0" - "@typescript-eslint/type-utils" "8.53.0" - "@typescript-eslint/utils" "8.53.0" - "@typescript-eslint/visitor-keys" "8.53.0" + "@typescript-eslint/scope-manager" "8.55.0" + "@typescript-eslint/type-utils" "8.55.0" + "@typescript-eslint/utils" "8.55.0" + "@typescript-eslint/visitor-keys" "8.55.0" ignore "^7.0.5" natural-compare "^1.4.0" ts-api-utils "^2.4.0" @@ -3296,15 +3601,15 @@ natural-compare "^1.4.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.53.0.tgz#d8bed6f12dc74e03751e5f947510ff2b165990c6" - integrity sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg== +"@typescript-eslint/parser@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.55.0.tgz#6eace4e9e95f178d3447ed1f17f3d6a5dfdb345c" + integrity sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw== dependencies: - "@typescript-eslint/scope-manager" "8.53.0" - "@typescript-eslint/types" "8.53.0" - "@typescript-eslint/typescript-estree" "8.53.0" - "@typescript-eslint/visitor-keys" "8.53.0" + "@typescript-eslint/scope-manager" "8.55.0" + "@typescript-eslint/types" "8.55.0" + "@typescript-eslint/typescript-estree" "8.55.0" + "@typescript-eslint/visitor-keys" "8.55.0" debug "^4.4.3" "@typescript-eslint/parser@^7.1.1": @@ -3318,13 +3623,13 @@ "@typescript-eslint/visitor-keys" "7.18.0" debug "^4.3.4" -"@typescript-eslint/project-service@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.53.0.tgz#327c67c61c16a1c8b12a440b0779b41eb77cc7df" - integrity sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg== +"@typescript-eslint/project-service@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.55.0.tgz#b8a71c06a625bdad481c24d5614b68e252f3ae9b" + integrity sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ== dependencies: - "@typescript-eslint/tsconfig-utils" "^8.53.0" - "@typescript-eslint/types" "^8.53.0" + "@typescript-eslint/tsconfig-utils" "^8.55.0" + "@typescript-eslint/types" "^8.55.0" debug "^4.4.3" "@typescript-eslint/scope-manager@5.62.0": @@ -3343,18 +3648,18 @@ "@typescript-eslint/types" "7.18.0" "@typescript-eslint/visitor-keys" "7.18.0" -"@typescript-eslint/scope-manager@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.53.0.tgz#f922fcbf0d42e72f065297af31779ccf19de9a97" - integrity sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g== +"@typescript-eslint/scope-manager@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.55.0.tgz#8a0752c31c788651840dc98f840b0c2ebe143b8c" + integrity sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q== dependencies: - "@typescript-eslint/types" "8.53.0" - "@typescript-eslint/visitor-keys" "8.53.0" + "@typescript-eslint/types" "8.55.0" + "@typescript-eslint/visitor-keys" "8.55.0" -"@typescript-eslint/tsconfig-utils@8.53.0", "@typescript-eslint/tsconfig-utils@^8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.0.tgz#105279d7969a7abdc8345cc9c57cff83cf910f8f" - integrity sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA== +"@typescript-eslint/tsconfig-utils@8.55.0", "@typescript-eslint/tsconfig-utils@^8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.55.0.tgz#62f1d005419985e09d37a040b2f1450e4e805afa" + integrity sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q== "@typescript-eslint/type-utils@7.18.0": version "7.18.0" @@ -3366,14 +3671,14 @@ debug "^4.3.4" ts-api-utils "^1.3.0" -"@typescript-eslint/type-utils@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.53.0.tgz#81a0de5c01fc68f6df0591d03cd8226bda01c91f" - integrity sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw== +"@typescript-eslint/type-utils@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.55.0.tgz#195d854b3e56308ce475fdea2165313bb1190200" + integrity sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g== dependencies: - "@typescript-eslint/types" "8.53.0" - "@typescript-eslint/typescript-estree" "8.53.0" - "@typescript-eslint/utils" "8.53.0" + "@typescript-eslint/types" "8.55.0" + "@typescript-eslint/typescript-estree" "8.55.0" + "@typescript-eslint/utils" "8.55.0" debug "^4.4.3" ts-api-utils "^2.4.0" @@ -3387,10 +3692,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== -"@typescript-eslint/types@8.53.0", "@typescript-eslint/types@^8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.53.0.tgz#1adcad3fa32bc2c4cbf3785ba07a5e3151819efb" - integrity sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ== +"@typescript-eslint/types@8.55.0", "@typescript-eslint/types@^8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.55.0.tgz#8449c5a7adac61184cac92dbf6315733569708c2" + integrity sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w== "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" @@ -3419,15 +3724,15 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/typescript-estree@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.0.tgz#7805b46b7a8ce97e91b7bb56fc8b1ba26ca8ef52" - integrity sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw== +"@typescript-eslint/typescript-estree@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.55.0.tgz#c83ac92c11ce79bedd984937c7780a65e7f7b2e3" + integrity sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw== dependencies: - "@typescript-eslint/project-service" "8.53.0" - "@typescript-eslint/tsconfig-utils" "8.53.0" - "@typescript-eslint/types" "8.53.0" - "@typescript-eslint/visitor-keys" "8.53.0" + "@typescript-eslint/project-service" "8.55.0" + "@typescript-eslint/tsconfig-utils" "8.55.0" + "@typescript-eslint/types" "8.55.0" + "@typescript-eslint/visitor-keys" "8.55.0" debug "^4.4.3" minimatch "^9.0.5" semver "^7.7.3" @@ -3444,15 +3749,15 @@ "@typescript-eslint/types" "7.18.0" "@typescript-eslint/typescript-estree" "7.18.0" -"@typescript-eslint/utils@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.53.0.tgz#bf0a4e2edaf1afc9abce209fc02f8cab0b74af13" - integrity sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA== +"@typescript-eslint/utils@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.55.0.tgz#c1744d94a3901deb01f58b09d3478d811f96d619" + integrity sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow== dependencies: "@eslint-community/eslint-utils" "^4.9.1" - "@typescript-eslint/scope-manager" "8.53.0" - "@typescript-eslint/types" "8.53.0" - "@typescript-eslint/typescript-estree" "8.53.0" + "@typescript-eslint/scope-manager" "8.55.0" + "@typescript-eslint/types" "8.55.0" + "@typescript-eslint/typescript-estree" "8.55.0" "@typescript-eslint/utils@^5.10.0": version "5.62.0" @@ -3484,12 +3789,12 @@ "@typescript-eslint/types" "7.18.0" eslint-visitor-keys "^3.4.3" -"@typescript-eslint/visitor-keys@8.53.0": - version "8.53.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.0.tgz#9a785664ddae7e3f7e570ad8166e48dbc9c6cf02" - integrity sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw== +"@typescript-eslint/visitor-keys@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.55.0.tgz#3d9a40fd4e3705c63d8fae3af58988add3ed464d" + integrity sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA== dependencies: - "@typescript-eslint/types" "8.53.0" + "@typescript-eslint/types" "8.55.0" eslint-visitor-keys "^4.2.1" "@ungap/structured-clone@^1.3.0": @@ -4059,6 +4364,15 @@ babel-plugin-polyfill-corejs2@^0.4.14: "@babel/helper-define-polyfill-provider" "^0.6.5" semver "^6.3.1" +babel-plugin-polyfill-corejs2@^0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz#808fa349686eea4741807cfaaa2aa3aa57ce120a" + integrity sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw== + dependencies: + "@babel/compat-data" "^7.28.6" + "@babel/helper-define-polyfill-provider" "^0.6.6" + semver "^6.3.1" + babel-plugin-polyfill-corejs3@^0.13.0: version "0.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz#bb7f6aeef7addff17f7602a08a6d19a128c30164" @@ -4067,6 +4381,14 @@ babel-plugin-polyfill-corejs3@^0.13.0: "@babel/helper-define-polyfill-provider" "^0.6.5" core-js-compat "^3.43.0" +babel-plugin-polyfill-corejs3@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz#65b06cda48d6e447e1e926681f5a247c6ae2b9cf" + integrity sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.6" + core-js-compat "^3.48.0" + babel-plugin-polyfill-regenerator@^0.6.5: version "0.6.5" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz#32752e38ab6f6767b92650347bf26a31b16ae8c5" @@ -4074,6 +4396,13 @@ babel-plugin-polyfill-regenerator@^0.6.5: dependencies: "@babel/helper-define-polyfill-provider" "^0.6.5" +babel-plugin-polyfill-regenerator@^0.6.6: + version "0.6.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz#69f5dd263cab933c42fe5ea05e83443b374bd4bf" + integrity sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.6.6" + babel-plugin-react-compiler@1.0.0, babel-plugin-react-compiler@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz#bdf7360a23a4d5ebfca090255da3893efd07425f" @@ -4121,10 +4450,10 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" -babel-preset-expo@54.0.9, babel-preset-expo@~54.0.9: - version "54.0.9" - resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-54.0.9.tgz#88af355f08dc49b4b54ac559c02ce8890ab08930" - integrity sha512-8J6hRdgEC2eJobjoft6mKJ294cLxmi3khCUy2JJQp4htOYYkllSLUq6vudWJkTJiIuGdVR4bR6xuz2EvJLWHNg== +babel-preset-expo@54.0.10, babel-preset-expo@~54.0.10: + version "54.0.10" + resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-54.0.10.tgz#3b70f4af3a5f65f945d7957ef511ee016e8f2fd6" + integrity sha512-wTt7POavLFypLcPW/uC5v8y+mtQKDJiyGLzYCjqr9tx0Qc3vCXcDKk1iCFIj/++Iy5CWhhTflEa7VvVPNWeCfw== dependencies: "@babel/helper-module-imports" "^7.25.9" "@babel/plugin-proposal-decorators" "^7.12.9" @@ -4781,15 +5110,22 @@ core-js-compat@^3.43.0: dependencies: browserslist "^4.28.0" +core-js-compat@^3.48.0: + version "3.48.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.48.0.tgz#7efbe1fc1cbad44008190462217cc5558adaeaa6" + integrity sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q== + dependencies: + browserslist "^4.28.1" + core-js-pure@^3.23.3: version "3.47.0" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.47.0.tgz#1104df8a3b6eb9189fcc559b5a65b90f66e7e887" integrity sha512-BcxeDbzUrRnXGYIVAGFtcGQVNpFcUhVjr6W7F8XktvQW2iJP9e66GP6xdKotCRFlrxBvNIBrhwKteRXqMV86Nw== -core-js@^3.30.2: - version "3.47.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.47.0.tgz#436ef07650e191afeb84c24481b298bd60eb4a17" - integrity sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg== +core-js@^3.48.0: + version "3.48.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.48.0.tgz#1f813220a47bbf0e667e3885c36cd6f0593bf14d" + integrity sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ== core-util-is@~1.0.0: version "1.0.3" @@ -4846,19 +5182,19 @@ css-in-js-utils@^3.1.0: dependencies: hyphenate-style-name "^1.0.3" -css-loader@7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-7.1.2.tgz#64671541c6efe06b0e22e750503106bdd86880f8" - integrity sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA== +css-loader@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-7.1.3.tgz#c0de715ceabe39b8531a85fcaf6734a430c4d99a" + integrity sha512-frbERmjT0UC5lMheWpJmMilnt9GEhbZJN/heUb7/zaJYeIzj5St9HvDcfshzzOqbsS+rYpMk++2SD3vGETDSyA== dependencies: icss-utils "^5.1.0" - postcss "^8.4.33" + postcss "^8.4.40" postcss-modules-extract-imports "^3.1.0" postcss-modules-local-by-default "^4.0.5" postcss-modules-scope "^3.2.0" postcss-modules-values "^4.0.0" postcss-value-parser "^4.2.0" - semver "^7.5.4" + semver "^7.6.3" css-select@^4.1.3: version "4.3.0" @@ -5174,13 +5510,13 @@ electron-to-chromium@^1.5.263: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz#5d84f2df8cdb6bfe7e873706bb21bd4bfb574dc7" integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw== -electron@39.2.7: - version "39.2.7" - resolved "https://registry.yarnpkg.com/electron/-/electron-39.2.7.tgz#1cf2371304994fe26c564764bd50878fe405fb4b" - integrity sha512-KU0uFS6LSTh4aOIC3miolcbizOFP7N1M46VTYVfqIgFiuA2ilfNaOHLDS9tCMvwwHRowAsvqBrh9NgMXcTOHCQ== +electron@40.4.0: + version "40.4.0" + resolved "https://registry.yarnpkg.com/electron/-/electron-40.4.0.tgz#e2e73d837df141216dcd91fb6c3f754e771387c2" + integrity sha512-31l4V7Ys4oUuXyaN/cCNnyBdDXN9RwOVOG+JhiHCf4zx5tZkHd43PKGY6KLEWpeYCxaphsuGSEjagJLfPqKj8g== dependencies: "@electron/get" "^2.0.0" - "@types/node" "^22.7.7" + "@types/node" "^24.9.0" extract-zip "^2.0.1" emoji-datasource-apple@16.0.0: @@ -5220,13 +5556,13 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@^5.17.4: - version "5.18.4" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz#c22d33055f3952035ce6a144ce092447c525f828" - integrity sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q== +enhanced-resolve@^5.19.0: + version "5.19.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz#6687446a15e969eaa63c2fa2694510e17ae6d97c" + integrity sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg== dependencies: graceful-fs "^4.2.4" - tapable "^2.2.0" + tapable "^2.3.0" entities@^2.0.0: version "2.2.0" @@ -5588,11 +5924,13 @@ eslint-scope@5.1.1, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" - integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== +eslint-scope@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-9.1.0.tgz#dfcb41d6c0d73df6b977a50cf3e91c41ddb4154e" + integrity sha512-CkWE42hOJsNj9FJRaoMX9waUFYhqY4jmyLFdAdzZr6VaCg3ynLYx4WnOdkaIifGfH4gsUcBTn4OZbHXkpLD0FQ== dependencies: + "@types/esrecurse" "^4.3.1" + "@types/estree" "^1.0.8" esrecurse "^4.3.0" estraverse "^5.2.0" @@ -5611,32 +5949,34 @@ eslint-visitor-keys@^4.2.1: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== -eslint@9.39.2: - version "9.39.2" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.39.2.tgz#cb60e6d16ab234c0f8369a3fe7cc87967faf4b6c" - integrity sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw== +eslint-visitor-keys@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz#b9aa1a74aa48c44b3ae46c1597ce7171246a94a9" + integrity sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q== + +eslint@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.0.0.tgz#c93c36a96d91621d0fbb680db848ea11af56ab1e" + integrity sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg== dependencies: "@eslint-community/eslint-utils" "^4.8.0" - "@eslint-community/regexpp" "^4.12.1" - "@eslint/config-array" "^0.21.1" - "@eslint/config-helpers" "^0.4.2" - "@eslint/core" "^0.17.0" - "@eslint/eslintrc" "^3.3.1" - "@eslint/js" "9.39.2" - "@eslint/plugin-kit" "^0.4.1" + "@eslint-community/regexpp" "^4.12.2" + "@eslint/config-array" "^0.23.0" + "@eslint/config-helpers" "^0.5.2" + "@eslint/core" "^1.1.0" + "@eslint/plugin-kit" "^0.6.0" "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" "@humanwhocodes/retry" "^0.4.2" "@types/estree" "^1.0.6" ajv "^6.12.4" - chalk "^4.0.0" cross-spawn "^7.0.6" debug "^4.3.2" escape-string-regexp "^4.0.0" - eslint-scope "^8.4.0" - eslint-visitor-keys "^4.2.1" - espree "^10.4.0" - esquery "^1.5.0" + eslint-scope "^9.1.0" + eslint-visitor-keys "^5.0.0" + espree "^11.1.0" + esquery "^1.7.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^8.0.0" @@ -5646,29 +5986,28 @@ eslint@9.39.2: imurmurhash "^0.1.4" is-glob "^4.0.0" json-stable-stringify-without-jsonify "^1.0.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" + minimatch "^10.1.1" natural-compare "^1.4.0" optionator "^0.9.3" -espree@^10.0.1, espree@^10.4.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" - integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== +espree@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-11.1.0.tgz#7d0c82a69f8df670728dba256264b383fbf73e8f" + integrity sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw== dependencies: acorn "^8.15.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^4.2.1" + eslint-visitor-keys "^5.0.0" esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" - integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== +esquery@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== dependencies: estraverse "^5.1.0" @@ -5797,10 +6136,10 @@ expo-file-system@19.0.21, expo-file-system@~19.0.21: resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-19.0.21.tgz#e96a68107fb629cf0dd1906fe7b46b566ff13e10" integrity sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg== -expo-font@~14.0.10: - version "14.0.10" - resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-14.0.10.tgz#33fb9f6dc5661729192a6bc8cd6f08bd1a9097cc" - integrity sha512-UqyNaaLKRpj4pKAP4HZSLnuDQqueaO5tB1c/NWu5vh1/LF9ulItyyg2kF/IpeOp0DeOLk0GY0HrIXaKUMrwB+Q== +expo-font@~14.0.11: + version "14.0.11" + resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-14.0.11.tgz#198743d17332520545107df026d8a261e6b2732f" + integrity sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg== dependencies: fontfaceobserver "^2.1.0" @@ -5881,26 +6220,26 @@ expo-task-manager@14.0.9: dependencies: unimodules-app-loader "~6.0.8" -expo@54.0.31: - version "54.0.31" - resolved "https://registry.yarnpkg.com/expo/-/expo-54.0.31.tgz#c9b88d7154039bb7165abc21d73aec5e5fde6d71" - integrity sha512-kQ3RDqA/a59I7y+oqQGyrPbbYlgPMUdKBOgvFLpoHbD2bCM+F75i4N0mUijy7dG5F/CUCu2qHmGGUCXBbMDkCg== +expo@54.0.33: + version "54.0.33" + resolved "https://registry.yarnpkg.com/expo/-/expo-54.0.33.tgz#f7d572857323f5a8250a9afe245a487d2ee2735f" + integrity sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw== dependencies: "@babel/runtime" "^7.20.0" - "@expo/cli" "54.0.21" + "@expo/cli" "54.0.23" "@expo/config" "~12.0.13" "@expo/config-plugins" "~54.0.4" "@expo/devtools" "0.1.8" "@expo/fingerprint" "0.15.4" "@expo/metro" "~54.2.0" - "@expo/metro-config" "54.0.13" + "@expo/metro-config" "54.0.14" "@expo/vector-icons" "^15.0.3" "@ungap/structured-clone" "^1.3.0" - babel-preset-expo "~54.0.9" + babel-preset-expo "~54.0.10" expo-asset "~12.0.12" expo-constants "~18.0.13" expo-file-system "~19.0.21" - expo-font "~14.0.10" + expo-font "~14.0.11" expo-keep-awake "~15.0.8" expo-modules-autolinking "3.0.24" expo-modules-core "3.0.29" @@ -6220,9 +6559,9 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -framed-msgpack-rpc@keybase/node-framed-msgpack-rpc#nojima/HOTPOT-use-buffer: +framed-msgpack-rpc@keybase/node-framed-msgpack-rpc#nojima/HOTPOT-use-buffer-iserror2: version "1.1.24" - resolved "https://codeload.github.com/keybase/node-framed-msgpack-rpc/tar.gz/be19aba75ae0b67e301953efe87933aaaae7dfd8" + resolved "https://codeload.github.com/keybase/node-framed-msgpack-rpc/tar.gz/e3bd0029435879bdb6f5bfde5e05b097d3812886" dependencies: iced-error "0.0.13" iced-lock "2.0.1" @@ -6497,11 +6836,6 @@ global-dirs@^0.1.1: dependencies: ini "^1.3.4" -globals@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" - integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== - globalthis@^1.0.1, globalthis@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" @@ -6522,10 +6856,10 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -google-libphonenumber@3.2.43: - version "3.2.43" - resolved "https://registry.yarnpkg.com/google-libphonenumber/-/google-libphonenumber-3.2.43.tgz#c1e5107ab9c6e3848dc2108e380bde08da80931c" - integrity sha512-TbIX/UC3BFRJwCxbBeCPwuRC4Qws9Jz/CECmfTM1t9RFoI3X6eRThurv6AYr9wSrt640IA9KFIHuAD/vlyjqRw== +google-libphonenumber@3.2.44: + version "3.2.44" + resolved "https://registry.yarnpkg.com/google-libphonenumber/-/google-libphonenumber-3.2.44.tgz#694ec9d5581f013b881c4c2937791e973a45f420" + integrity sha512-9p2TghluF2LTChFMLWsDRD5N78SZDsILdUk4gyqYxBXluCyxoPiOq+Fqt7DKM+LUd33+OgRkdrc+cPR93AypCQ== gopd@^1.0.1, gopd@^1.2.0: version "1.2.0" @@ -6707,10 +7041,10 @@ html-minifier-terser@^6.0.2: relateurl "^0.2.7" terser "^5.10.0" -html-webpack-plugin@5.6.5: - version "5.6.5" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.5.tgz#d57defb83cabbf29bf56b2d4bf10b67b650066be" - integrity sha512-4xynFbKNNk+WlzXeQQ+6YYsH2g7mpfPszQZUi3ovKlj+pDmngQ7vRXjrrmGROabmKwyQkcgcX5hqfOwHbFmK5g== +html-webpack-plugin@5.6.6: + version "5.6.6" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.6.tgz#5321b9579f4a1949318550ced99c2a4a4e60cbaf" + integrity sha512-bLjW01UTrvoWTJQL5LsMRo1SypHW80FTm12OJRSnr3v6YHNhfe+1r0MYUZJMACxnCHURVnBWRwAsWs2yPU9Ezw== dependencies: "@types/html-minifier-terser" "^6.0.0" html-minifier-terser "^6.0.2" @@ -6877,12 +7211,12 @@ image-size@^1.0.2: dependencies: queue "6.0.2" -immer@11.1.3: - version "11.1.3" - resolved "https://registry.yarnpkg.com/immer/-/immer-11.1.3.tgz#78681e1deb6cec39753acf04eb16d7576c04f4d6" - integrity sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q== +immer@11.1.4: + version "11.1.4" + resolved "https://registry.yarnpkg.com/immer/-/immer-11.1.4.tgz#37aee86890b134a8f1a2fadd44361fb86c6ae67e" + integrity sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw== -import-fresh@^3.2.1, import-fresh@^3.3.0: +import-fresh@^3.3.0: version "3.3.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== @@ -7745,11 +8079,6 @@ lodash.get@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" @@ -8984,7 +9313,7 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.33: +postcss@^8.4.40: version "8.5.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== @@ -9019,10 +9348,10 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.0.tgz#f72cf71505133f40cfa2ef77a2668cdc558fcd69" - integrity sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA== +prettier@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.1.tgz#edf48977cf991558f4fcbd8a3ba6015ba2a3a173" + integrity sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg== prettier@^3.4.2: version "3.6.2" @@ -9309,10 +9638,10 @@ react-native-is-edge-to-edge@1.2.1, react-native-is-edge-to-edge@^1.2.1: "react-native-kb@file:../rnmodules/react-native-kb": version "0.1.1" -react-native-keyboard-controller@1.20.6: - version "1.20.6" - resolved "https://registry.yarnpkg.com/react-native-keyboard-controller/-/react-native-keyboard-controller-1.20.6.tgz#139a66f36734a69648822bf2e7ec3c90e7b3dc8e" - integrity sha512-RS6FjIjTFtAMQGdcXp3m6jUs1XgDa8qkpO5c4ix1S5HS0z3L2E1LUOY5rD73YUADOO3MfQN1z3JkHdBtzKucbg== +react-native-keyboard-controller@1.20.7: + version "1.20.7" + resolved "https://registry.yarnpkg.com/react-native-keyboard-controller/-/react-native-keyboard-controller-1.20.7.tgz#e1be1c15a5eb10b96a40a0812d8472e6e4bd8f29" + integrity sha512-G8S5jz1FufPrcL1vPtReATx+jJhT/j+sTqxMIb30b1z7cYEfMlkIzOCyaHgf6IMB2KA9uBmnA5M6ve2A9Ou4kw== dependencies: react-native-is-edge-to-edge "^1.2.1" @@ -9329,10 +9658,10 @@ react-native-safe-area-context@5.6.2: resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz#283e006f5b434fb247fcb4be0971ad7473d5c560" integrity sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg== -react-native-screens@4.18.0: - version "4.18.0" - resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-4.18.0.tgz#ba5a951b3f145e3b773d201143c19e1b1c1337ff" - integrity sha512-mRTLWL7Uc1p/RFNveEIIrhP22oxHduC2ZnLr/2iHwBeYpGXR0rJZ7Bgc0ktxQSHRjWTPT70qc/7yd4r9960PBQ== +react-native-screens@4.23.0: + version "4.23.0" + resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-4.23.0.tgz#81574b1b0cc4ac6c9ed63e46eca7126f37affe86" + integrity sha512-XhO3aK0UeLpBn4kLecd+J+EDeRRJlI/Ro9Fze06vo1q163VeYtzfU9QS09/VyDFMWR1qxDC1iazCArTPSFFiPw== dependencies: react-freeze "^1.0.0" warn-once "^0.1.0" @@ -9359,10 +9688,10 @@ react-native-webview@13.16.0: escape-string-regexp "^4.0.0" invariant "2.2.4" -react-native-worklets@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/react-native-worklets/-/react-native-worklets-0.7.1.tgz#263da5216b0b5342b9f1b36e0ab897c5ca5c863b" - integrity sha512-KNsvR48ULg73QhTlmwPbdJLPsWcyBotrGPsrDRDswb5FYpQaJEThUKc2ncXE4UM5dn/ewLoQHjSjLaKUVPxPhA== +react-native-worklets@0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/react-native-worklets/-/react-native-worklets-0.7.3.tgz#e561c006b576019feb21888c4acf60261b55ca24" + integrity sha512-m/CIUCHvLQulboBn0BtgpsesXjOTeubU7t+V0lCPpBj0t2ExigwqDHoKj3ck7OeErnjgkD27wdAtQCubYATe3g== dependencies: "@babel/plugin-transform-arrow-functions" "7.27.1" "@babel/plugin-transform-class-properties" "7.27.1" @@ -9464,10 +9793,10 @@ react-test-renderer@19.1.0: react-is "^19.1.0" scheduler "^0.26.0" -react-window@2.2.5: - version "2.2.5" - resolved "https://registry.yarnpkg.com/react-window/-/react-window-2.2.5.tgz#425a29609980083aafd5a48a1711a2af9319c1d2" - integrity sha512-6viWvPSZvVuMIe9hrl4IIZoVfO/npiqOb03m4Z9w+VihmVzBbiudUrtUqDpsWdKvd/Ai31TCR25CBcFFAUm28w== +react-window@2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/react-window/-/react-window-2.2.6.tgz#00ca174346b5146d3c33a752d888181250c71d9f" + integrity sha512-v89O08xRdpCaEuf380B39D1C/0KgUDZA59xft6SVAjzjz/xQxSyXrgDWHymIsYI6TMrqE8WO+G0/PB9AGE8VNA== react@19.1.0: version "19.1.0" @@ -9705,7 +10034,7 @@ resolve.exports@^2.0.3: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.10, resolve@^1.22.2, resolve@^1.22.8: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.10, resolve@^1.22.11, resolve@^1.22.2, resolve@^1.22.8: version "1.22.11" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== @@ -9912,6 +10241,11 @@ semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^7.6.3: + version "7.7.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + send@0.19.0: version "0.19.0" resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" @@ -10465,11 +10799,6 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -10556,7 +10885,7 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -tapable@^2.0.0, tapable@^2.2.0, tapable@^2.3.0: +tapable@^2.0.0, tapable@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.3.0.tgz#7e3ea6d5ca31ba8e078b560f0d83ce9a14aa8be6" integrity sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg== @@ -10825,15 +11154,15 @@ typedarray-to-buffer@4.0.0: resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz#cdd2933c61dd3f5f02eda5d012d441f95bfeb50a" integrity sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ== -typescript-eslint@8.53.0: - version "8.53.0" - resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.53.0.tgz#c35ca6403cd381753aee325f67e10d6101d55f04" - integrity sha512-xHURCQNxZ1dsWn0sdOaOfCSQG0HKeqSj9OexIxrz6ypU6wHYOdX2I3D2b8s8wFSsSOYJb+6q283cLiLlkEsBYw== +typescript-eslint@8.55.0: + version "8.55.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.55.0.tgz#abae8295c5f0f82f816218113a46e89bc30c3de2" + integrity sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw== dependencies: - "@typescript-eslint/eslint-plugin" "8.53.0" - "@typescript-eslint/parser" "8.53.0" - "@typescript-eslint/typescript-estree" "8.53.0" - "@typescript-eslint/utils" "8.53.0" + "@typescript-eslint/eslint-plugin" "8.55.0" + "@typescript-eslint/parser" "8.55.0" + "@typescript-eslint/typescript-estree" "8.55.0" + "@typescript-eslint/utils" "8.55.0" typescript@5.9.3: version "5.9.3" @@ -11057,10 +11386,10 @@ warn-once@^0.1.0, warn-once@^0.1.1: resolved "https://registry.yarnpkg.com/warn-once/-/warn-once-0.1.1.tgz#952088f4fb56896e73fd4e6a3767272a3fccce43" integrity sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q== -watchpack@^2.4.4: - version "2.4.4" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.4.tgz#473bda72f0850453da6425081ea46fc0d7602947" - integrity sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA== +watchpack@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.5.1.tgz#dd38b601f669e0cbf567cb802e75cead82cde102" + integrity sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -11173,10 +11502,10 @@ webpack-virtual-modules@^0.6.2: resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8" integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ== -webpack@5.104.1: - version "5.104.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.104.1.tgz#94bd41eb5dbf06e93be165ba8be41b8260d4fb1a" - integrity sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA== +webpack@5.105.2: + version "5.105.2" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.105.2.tgz#f3b76f9fc36f1152e156e63ffda3bbb82e6739ea" + integrity sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw== dependencies: "@types/eslint-scope" "^3.7.7" "@types/estree" "^1.0.8" @@ -11188,7 +11517,7 @@ webpack@5.104.1: acorn-import-phases "^1.0.3" browserslist "^4.28.1" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.17.4" + enhanced-resolve "^5.19.0" es-module-lexer "^2.0.0" eslint-scope "5.1.1" events "^3.2.0" @@ -11201,7 +11530,7 @@ webpack@5.104.1: schema-utils "^4.3.3" tapable "^2.3.0" terser-webpack-plugin "^5.3.16" - watchpack "^2.4.4" + watchpack "^2.5.1" webpack-sources "^3.3.3" websocket-driver@>=0.5.1, websocket-driver@^0.7.4: @@ -11502,7 +11831,7 @@ zod@^3.22.4: resolved "https://registry.yarnpkg.com/zod/-/zod-4.1.12.tgz#64f1ea53d00eab91853195653b5af9eee68970f0" integrity sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ== -zustand@5.0.10: - version "5.0.10" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.10.tgz#4db510c0c4c25a5f1ae43227b307ddf1641a3210" - integrity sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg== +zustand@5.0.11: + version "5.0.11" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.11.tgz#99f912e590de1ca9ce6c6d1cab6cdb1f034ab494" + integrity sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==