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 )