diff --git a/src/App.native.tsx b/src/App.native.tsx
index ccc7de32..5955504e 100644
--- a/src/App.native.tsx
+++ b/src/App.native.tsx
@@ -22,6 +22,7 @@ import * as Toast from 'view/com/util/Toast'
import {queryClient} from 'lib/react-query'
import {TestCtrls} from 'view/com/testing/TestCtrls'
import {Provider as ShellStateProvider} from 'state/shell'
+import {Provider as ModalStateProvider} from 'state/modals'
import {Provider as MutedThreadsProvider} from 'state/muted-threads'
import {Provider as InvitesStateProvider} from 'state/invites'
import {Provider as PrefsStateProvider} from 'state/preferences'
@@ -84,7 +85,9 @@ function App() {
-
+
+
+
diff --git a/src/App.web.tsx b/src/App.web.tsx
index 363161bf..9e5b99a9 100644
--- a/src/App.web.tsx
+++ b/src/App.web.tsx
@@ -17,6 +17,7 @@ import {ToastContainer} from 'view/com/util/Toast.web'
import {ThemeProvider} from 'lib/ThemeContext'
import {queryClient} from 'lib/react-query'
import {Provider as ShellStateProvider} from 'state/shell'
+import {Provider as ModalStateProvider} from 'state/modals'
import {Provider as MutedThreadsProvider} from 'state/muted-threads'
import {Provider as InvitesStateProvider} from 'state/invites'
import {Provider as PrefsStateProvider} from 'state/preferences'
@@ -74,7 +75,9 @@ function App() {
-
+
+
+
diff --git a/src/lib/hooks/useAccountSwitcher.ts b/src/lib/hooks/useAccountSwitcher.ts
index 1ddb181a..b165fddb 100644
--- a/src/lib/hooks/useAccountSwitcher.ts
+++ b/src/lib/hooks/useAccountSwitcher.ts
@@ -7,6 +7,7 @@ import {AccountData} from 'state/models/session'
import {reset as resetNavigation} from '../../Navigation'
import * as Toast from 'view/com/util/Toast'
import {useSetDrawerOpen} from '#/state/shell/drawer-open'
+import {useModalControls} from '#/state/modals'
export function useAccountSwitcher(): [
boolean,
@@ -16,6 +17,7 @@ export function useAccountSwitcher(): [
const {track} = useAnalytics()
const store = useStores()
const setDrawerOpen = useSetDrawerOpen()
+ const {closeModal} = useModalControls()
const [isSwitching, setIsSwitching] = useState(false)
const navigation = useNavigation()
@@ -25,6 +27,7 @@ export function useAccountSwitcher(): [
setIsSwitching(true)
const success = await store.session.resumeSession(acct)
setDrawerOpen(false)
+ closeModal()
store.shell.closeAllActiveElements()
if (success) {
resetNavigation()
@@ -36,7 +39,7 @@ export function useAccountSwitcher(): [
store.session.clear()
}
},
- [track, setIsSwitching, navigation, store, setDrawerOpen],
+ [track, setIsSwitching, navigation, store, setDrawerOpen, closeModal],
)
return [isSwitching, setIsSwitching, onPressSwitchAccount]
diff --git a/src/lib/hooks/useOTAUpdate.ts b/src/lib/hooks/useOTAUpdate.ts
index 0ce97a4c..a3584fc9 100644
--- a/src/lib/hooks/useOTAUpdate.ts
+++ b/src/lib/hooks/useOTAUpdate.ts
@@ -1,15 +1,15 @@
import * as Updates from 'expo-updates'
import {useCallback, useEffect} from 'react'
import {AppState} from 'react-native'
-import {useStores} from 'state/index'
import {logger} from '#/logger'
+import {useModalControls} from '#/state/modals'
export function useOTAUpdate() {
- const store = useStores()
+ const {openModal} = useModalControls()
// HELPER FUNCTIONS
const showUpdatePopup = useCallback(() => {
- store.shell.openModal({
+ openModal({
name: 'confirm',
title: 'Update Available',
message:
@@ -20,7 +20,7 @@ export function useOTAUpdate() {
})
},
})
- }, [store.shell])
+ }, [openModal])
const checkForUpdate = useCallback(async () => {
logger.debug('useOTAUpdate: Checking for update...')
try {
diff --git a/src/lib/media/alt-text.ts b/src/lib/media/alt-text.ts
deleted file mode 100644
index 4109f667..00000000
--- a/src/lib/media/alt-text.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import {RootStoreModel} from 'state/index'
-import {ImageModel} from 'state/models/media/image'
-
-export async function openAltTextModal(
- store: RootStoreModel,
- image: ImageModel,
-) {
- store.shell.openModal({
- name: 'alt-text-image',
- image,
- })
-}
diff --git a/src/lib/media/picker.web.tsx b/src/lib/media/picker.web.tsx
index d12685b0..50b9c73e 100644
--- a/src/lib/media/picker.web.tsx
+++ b/src/lib/media/picker.web.tsx
@@ -4,6 +4,7 @@ import {CameraOpts, CropperOptions} from './types'
import {RootStoreModel} from 'state/index'
import {Image as RNImage} from 'react-native-image-crop-picker'
export {openPicker} from './picker.shared'
+import {unstable__openModal} from '#/state/modals'
export async function openCamera(
_store: RootStoreModel,
@@ -14,12 +15,12 @@ export async function openCamera(
}
export async function openCropper(
- store: RootStoreModel,
+ _store: RootStoreModel,
opts: CropperOptions,
): Promise {
// TODO handle more opts
return new Promise((resolve, reject) => {
- store.shell.openModal({
+ unstable__openModal({
name: 'crop-image',
uri: opts.path,
onSelect: (img?: RNImage) => {
diff --git a/src/state/modals/index.tsx b/src/state/modals/index.tsx
new file mode 100644
index 00000000..f9bd1e3c
--- /dev/null
+++ b/src/state/modals/index.tsx
@@ -0,0 +1,284 @@
+import React from 'react'
+import {AppBskyActorDefs, ModerationUI} from '@atproto/api'
+import {StyleProp, ViewStyle, DeviceEventEmitter} from 'react-native'
+import {Image as RNImage} from 'react-native-image-crop-picker'
+
+import {ProfileModel} from '#/state/models/content/profile'
+import {ImageModel} from '#/state/models/media/image'
+import {ListModel} from '#/state/models/content/list'
+import {GalleryModel} from '#/state/models/media/gallery'
+
+export interface ConfirmModal {
+ name: 'confirm'
+ title: string
+ message: string | (() => JSX.Element)
+ onPressConfirm: () => void | Promise
+ onPressCancel?: () => void | Promise
+ confirmBtnText?: string
+ confirmBtnStyle?: StyleProp
+ cancelBtnText?: string
+}
+
+export interface EditProfileModal {
+ name: 'edit-profile'
+ profileView: ProfileModel
+ onUpdate?: () => void
+}
+
+export interface ProfilePreviewModal {
+ name: 'profile-preview'
+ did: string
+}
+
+export interface ServerInputModal {
+ name: 'server-input'
+ initialService: string
+ onSelect: (url: string) => void
+}
+
+export interface ModerationDetailsModal {
+ name: 'moderation-details'
+ context: 'account' | 'content'
+ moderation: ModerationUI
+}
+
+export type ReportModal = {
+ name: 'report'
+} & (
+ | {
+ uri: string
+ cid: string
+ }
+ | {did: string}
+)
+
+export interface CreateOrEditListModal {
+ name: 'create-or-edit-list'
+ purpose?: string
+ list?: ListModel
+ onSave?: (uri: string) => void
+}
+
+export interface UserAddRemoveListsModal {
+ name: 'user-add-remove-lists'
+ subject: string
+ displayName: string
+ onAdd?: (listUri: string) => void
+ onRemove?: (listUri: string) => void
+}
+
+export interface ListAddUserModal {
+ name: 'list-add-user'
+ list: ListModel
+ onAdd?: (profile: AppBskyActorDefs.ProfileViewBasic) => void
+}
+
+export interface EditImageModal {
+ name: 'edit-image'
+ image: ImageModel
+ gallery: GalleryModel
+}
+
+export interface CropImageModal {
+ name: 'crop-image'
+ uri: string
+ onSelect: (img?: RNImage) => void
+}
+
+export interface AltTextImageModal {
+ name: 'alt-text-image'
+ image: ImageModel
+}
+
+export interface DeleteAccountModal {
+ name: 'delete-account'
+}
+
+export interface RepostModal {
+ name: 'repost'
+ onRepost: () => void
+ onQuote: () => void
+ isReposted: boolean
+}
+
+export interface SelfLabelModal {
+ name: 'self-label'
+ labels: string[]
+ hasMedia: boolean
+ onChange: (labels: string[]) => void
+}
+
+export interface ChangeHandleModal {
+ name: 'change-handle'
+ onChanged: () => void
+}
+
+export interface WaitlistModal {
+ name: 'waitlist'
+}
+
+export interface InviteCodesModal {
+ name: 'invite-codes'
+}
+
+export interface AddAppPasswordModal {
+ name: 'add-app-password'
+}
+
+export interface ContentFilteringSettingsModal {
+ name: 'content-filtering-settings'
+}
+
+export interface ContentLanguagesSettingsModal {
+ name: 'content-languages-settings'
+}
+
+export interface PostLanguagesSettingsModal {
+ name: 'post-languages-settings'
+}
+
+export interface BirthDateSettingsModal {
+ name: 'birth-date-settings'
+}
+
+export interface VerifyEmailModal {
+ name: 'verify-email'
+ showReminder?: boolean
+}
+
+export interface ChangeEmailModal {
+ name: 'change-email'
+}
+
+export interface SwitchAccountModal {
+ name: 'switch-account'
+}
+
+export interface LinkWarningModal {
+ name: 'link-warning'
+ text: string
+ href: string
+}
+
+export type Modal =
+ // Account
+ | AddAppPasswordModal
+ | ChangeHandleModal
+ | DeleteAccountModal
+ | EditProfileModal
+ | ProfilePreviewModal
+ | BirthDateSettingsModal
+ | VerifyEmailModal
+ | ChangeEmailModal
+ | SwitchAccountModal
+
+ // Curation
+ | ContentFilteringSettingsModal
+ | ContentLanguagesSettingsModal
+ | PostLanguagesSettingsModal
+
+ // Moderation
+ | ModerationDetailsModal
+ | ReportModal
+
+ // Lists
+ | CreateOrEditListModal
+ | UserAddRemoveListsModal
+ | ListAddUserModal
+
+ // Posts
+ | AltTextImageModal
+ | CropImageModal
+ | EditImageModal
+ | ServerInputModal
+ | RepostModal
+ | SelfLabelModal
+
+ // Bluesky access
+ | WaitlistModal
+ | InviteCodesModal
+
+ // Generic
+ | ConfirmModal
+ | LinkWarningModal
+
+const ModalContext = React.createContext<{
+ isModalActive: boolean
+ activeModals: Modal[]
+}>({
+ isModalActive: false,
+ activeModals: [],
+})
+
+const ModalControlContext = React.createContext<{
+ openModal: (modal: Modal) => void
+ closeModal: () => void
+}>({
+ openModal: () => {},
+ closeModal: () => {},
+})
+
+/**
+ * @deprecated DO NOT USE THIS unless you have no other choice.
+ */
+export let unstable__openModal: (modal: Modal) => void = () => {
+ throw new Error(`ModalContext is not initialized`)
+}
+
+export function Provider({children}: React.PropsWithChildren<{}>) {
+ const [isModalActive, setIsModalActive] = React.useState(false)
+ const [activeModals, setActiveModals] = React.useState([])
+
+ const openModal = React.useCallback(
+ (modal: Modal) => {
+ DeviceEventEmitter.emit('navigation')
+ setActiveModals(activeModals => [...activeModals, modal])
+ setIsModalActive(true)
+ },
+ [setIsModalActive, setActiveModals],
+ )
+
+ unstable__openModal = openModal
+
+ const closeModal = React.useCallback(() => {
+ let totalActiveModals = 0
+ setActiveModals(activeModals => {
+ activeModals.pop()
+ totalActiveModals = activeModals.length
+ return activeModals
+ })
+ setIsModalActive(totalActiveModals > 0)
+ }, [setIsModalActive, setActiveModals])
+
+ const state = React.useMemo(
+ () => ({
+ isModalActive,
+ activeModals,
+ }),
+ [isModalActive, activeModals],
+ )
+
+ const methods = React.useMemo(
+ () => ({
+ openModal,
+ closeModal,
+ }),
+ [openModal, closeModal],
+ )
+
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+export function useModals() {
+ return React.useContext(ModalContext)
+}
+
+export function useModalControls() {
+ return React.useContext(ModalControlContext)
+}
diff --git a/src/state/models/media/gallery.ts b/src/state/models/media/gallery.ts
index 1b22fadb..f9c3efca 100644
--- a/src/state/models/media/gallery.ts
+++ b/src/state/models/media/gallery.ts
@@ -4,7 +4,6 @@ import {ImageModel} from './image'
import {Image as RNImage} from 'react-native-image-crop-picker'
import {openPicker} from 'lib/media/picker'
import {getImageDim} from 'lib/media/manip'
-import {isNative} from 'platform/detection'
export class GalleryModel {
images: ImageModel[] = []
@@ -42,18 +41,6 @@ export class GalleryModel {
}
}
- async edit(image: ImageModel) {
- if (isNative) {
- this.crop(image)
- } else {
- this.rootStore.shell.openModal({
- name: 'edit-image',
- image,
- gallery: this,
- })
- }
- }
-
async paste(uri: string) {
if (this.size >= 4) {
return
diff --git a/src/state/models/ui/shell.ts b/src/state/models/ui/shell.ts
index b5fa4e59..8ef322db 100644
--- a/src/state/models/ui/shell.ts
+++ b/src/state/models/ui/shell.ts
@@ -1,16 +1,12 @@
-import {AppBskyEmbedRecord, AppBskyActorDefs, ModerationUI} from '@atproto/api'
+import {AppBskyEmbedRecord} from '@atproto/api'
import {RootStoreModel} from '../root-store'
import {makeAutoObservable, runInAction} from 'mobx'
import {ProfileModel} from '../content/profile'
-import {Image as RNImage} from 'react-native-image-crop-picker'
-import {ImageModel} from '../media/image'
-import {ListModel} from '../content/list'
-import {GalleryModel} from '../media/gallery'
-import {StyleProp, ViewStyle} from 'react-native'
import {
shouldRequestEmailConfirmation,
setEmailConfirmationRequested,
} from '#/state/shell/reminders'
+import {unstable__openModal} from '#/state/modals'
export type ColorMode = 'system' | 'light' | 'dark'
@@ -18,200 +14,6 @@ export function isColorMode(v: unknown): v is ColorMode {
return v === 'system' || v === 'light' || v === 'dark'
}
-export interface ConfirmModal {
- name: 'confirm'
- title: string
- message: string | (() => JSX.Element)
- onPressConfirm: () => void | Promise
- onPressCancel?: () => void | Promise
- confirmBtnText?: string
- confirmBtnStyle?: StyleProp
- cancelBtnText?: string
-}
-
-export interface EditProfileModal {
- name: 'edit-profile'
- profileView: ProfileModel
- onUpdate?: () => void
-}
-
-export interface ProfilePreviewModal {
- name: 'profile-preview'
- did: string
-}
-
-export interface ServerInputModal {
- name: 'server-input'
- initialService: string
- onSelect: (url: string) => void
-}
-
-export interface ModerationDetailsModal {
- name: 'moderation-details'
- context: 'account' | 'content'
- moderation: ModerationUI
-}
-
-export type ReportModal = {
- name: 'report'
-} & (
- | {
- uri: string
- cid: string
- }
- | {did: string}
-)
-
-export interface CreateOrEditListModal {
- name: 'create-or-edit-list'
- purpose?: string
- list?: ListModel
- onSave?: (uri: string) => void
-}
-
-export interface UserAddRemoveListsModal {
- name: 'user-add-remove-lists'
- subject: string
- displayName: string
- onAdd?: (listUri: string) => void
- onRemove?: (listUri: string) => void
-}
-
-export interface ListAddUserModal {
- name: 'list-add-user'
- list: ListModel
- onAdd?: (profile: AppBskyActorDefs.ProfileViewBasic) => void
-}
-
-export interface EditImageModal {
- name: 'edit-image'
- image: ImageModel
- gallery: GalleryModel
-}
-
-export interface CropImageModal {
- name: 'crop-image'
- uri: string
- onSelect: (img?: RNImage) => void
-}
-
-export interface AltTextImageModal {
- name: 'alt-text-image'
- image: ImageModel
-}
-
-export interface DeleteAccountModal {
- name: 'delete-account'
-}
-
-export interface RepostModal {
- name: 'repost'
- onRepost: () => void
- onQuote: () => void
- isReposted: boolean
-}
-
-export interface SelfLabelModal {
- name: 'self-label'
- labels: string[]
- hasMedia: boolean
- onChange: (labels: string[]) => void
-}
-
-export interface ChangeHandleModal {
- name: 'change-handle'
- onChanged: () => void
-}
-
-export interface WaitlistModal {
- name: 'waitlist'
-}
-
-export interface InviteCodesModal {
- name: 'invite-codes'
-}
-
-export interface AddAppPasswordModal {
- name: 'add-app-password'
-}
-
-export interface ContentFilteringSettingsModal {
- name: 'content-filtering-settings'
-}
-
-export interface ContentLanguagesSettingsModal {
- name: 'content-languages-settings'
-}
-
-export interface PostLanguagesSettingsModal {
- name: 'post-languages-settings'
-}
-
-export interface BirthDateSettingsModal {
- name: 'birth-date-settings'
-}
-
-export interface VerifyEmailModal {
- name: 'verify-email'
- showReminder?: boolean
-}
-
-export interface ChangeEmailModal {
- name: 'change-email'
-}
-
-export interface SwitchAccountModal {
- name: 'switch-account'
-}
-
-export interface LinkWarningModal {
- name: 'link-warning'
- text: string
- href: string
-}
-
-export type Modal =
- // Account
- | AddAppPasswordModal
- | ChangeHandleModal
- | DeleteAccountModal
- | EditProfileModal
- | ProfilePreviewModal
- | BirthDateSettingsModal
- | VerifyEmailModal
- | ChangeEmailModal
- | SwitchAccountModal
-
- // Curation
- | ContentFilteringSettingsModal
- | ContentLanguagesSettingsModal
- | PostLanguagesSettingsModal
-
- // Moderation
- | ModerationDetailsModal
- | ReportModal
-
- // Lists
- | CreateOrEditListModal
- | UserAddRemoveListsModal
- | ListAddUserModal
-
- // Posts
- | AltTextImageModal
- | CropImageModal
- | EditImageModal
- | ServerInputModal
- | RepostModal
- | SelfLabelModal
-
- // Bluesky access
- | WaitlistModal
- | InviteCodesModal
-
- // Generic
- | ConfirmModal
- | LinkWarningModal
-
interface LightboxModel {}
export class ProfileImageLightbox implements LightboxModel {
@@ -267,8 +69,6 @@ export interface ComposerOpts {
}
export class ShellUiModel {
- isModalActive = false
- activeModals: Modal[] = []
isLightboxActive = false
activeLightbox: ProfileImageLightbox | ImagesLightbox | null = null
isComposerActive = false
@@ -293,10 +93,6 @@ export class ShellUiModel {
this.closeLightbox()
return true
}
- if (this.isModalActive) {
- this.closeModal()
- return true
- }
if (this.isComposerActive) {
this.closeComposer()
return true
@@ -311,25 +107,11 @@ export class ShellUiModel {
if (this.isLightboxActive) {
this.closeLightbox()
}
- while (this.isModalActive) {
- this.closeModal()
- }
if (this.isComposerActive) {
this.closeComposer()
}
}
- openModal(modal: Modal) {
- this.rootStore.emitNavigation()
- this.isModalActive = true
- this.activeModals.push(modal)
- }
-
- closeModal() {
- this.activeModals.pop()
- this.isModalActive = this.activeModals.length > 0
- }
-
openLightbox(lightbox: ProfileImageLightbox | ImagesLightbox) {
this.rootStore.emitNavigation()
this.isLightboxActive = true
@@ -363,7 +145,7 @@ export class ShellUiModel {
setupLoginModals() {
this.rootStore.onSessionReady(() => {
if (shouldRequestEmailConfirmation(this.rootStore.session)) {
- this.openModal({name: 'verify-email', showReminder: true})
+ unstable__openModal({name: 'verify-email', showReminder: true})
setEmailConfirmationRequested()
}
})
diff --git a/src/view/com/auth/create/Step2.tsx b/src/view/com/auth/create/Step2.tsx
index 60e19756..b2054150 100644
--- a/src/view/com/auth/create/Step2.tsx
+++ b/src/view/com/auth/create/Step2.tsx
@@ -10,8 +10,8 @@ import {usePalette} from 'lib/hooks/usePalette'
import {TextInput} from '../util/TextInput'
import {Policies} from './Policies'
import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
-import {useStores} from 'state/index'
import {isWeb} from 'platform/detection'
+import {useModalControls} from '#/state/modals'
/** STEP 2: Your account
* @field Invite code or waitlist
@@ -28,11 +28,11 @@ export const Step2 = observer(function Step2Impl({
model: CreateAccountModel
}) {
const pal = usePalette('default')
- const store = useStores()
+ const {openModal} = useModalControls()
const onPressWaitlist = React.useCallback(() => {
- store.shell.openModal({name: 'waitlist'})
- }, [store])
+ openModal({name: 'waitlist'})
+ }, [openModal])
return (
diff --git a/src/view/com/auth/login/Login.tsx b/src/view/com/auth/login/Login.tsx
index acc05b6c..24a657c6 100644
--- a/src/view/com/auth/login/Login.tsx
+++ b/src/view/com/auth/login/Login.tsx
@@ -31,6 +31,7 @@ import {useTheme} from 'lib/ThemeContext'
import {cleanError} from 'lib/strings/errors'
import {isWeb} from 'platform/detection'
import {logger} from '#/logger'
+import {useModalControls} from '#/state/modals'
enum Forms {
Login,
@@ -303,9 +304,10 @@ const LoginForm = ({
const [identifier, setIdentifier] = useState(initialHandle)
const [password, setPassword] = useState('')
const passwordInputRef = useRef(null)
+ const {openModal} = useModalControls()
const onPressSelectService = () => {
- store.shell.openModal({
+ openModal({
name: 'server-input',
initialService: serviceUrl,
onSelect: setServiceUrl,
@@ -528,7 +530,6 @@ const LoginForm = ({
}
const ForgotPasswordForm = ({
- store,
error,
serviceUrl,
serviceDescription,
@@ -551,13 +552,14 @@ const ForgotPasswordForm = ({
const [isProcessing, setIsProcessing] = useState(false)
const [email, setEmail] = useState('')
const {screen} = useAnalytics()
+ const {openModal} = useModalControls()
useEffect(() => {
screen('Signin:ForgotPassword')
}, [screen])
const onPressSelectService = () => {
- store.shell.openModal({
+ openModal({
name: 'server-input',
initialService: serviceUrl,
onSelect: setServiceUrl,
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index 632e72fd..68f70682 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -49,6 +49,7 @@ import {LabelsBtn} from './labels/LabelsBtn'
import {SelectLangBtn} from './select-language/SelectLangBtn'
import {EmojiPickerButton} from './text-input/web/EmojiPicker.web'
import {insertMentionAt} from 'lib/strings/mention-manip'
+import {useModals, useModalControls} from '#/state/modals'
import {useRequireAltTextEnabled} from '#/state/preferences'
import {
useLanguagePrefs,
@@ -64,6 +65,8 @@ export const ComposePost = observer(function ComposePost({
quote: initQuote,
mention: initMention,
}: Props) {
+ const {activeModals} = useModals()
+ const {openModal, closeModal} = useModalControls()
const {track} = useAnalytics()
const pal = usePalette('default')
const {isDesktop, isMobile} = useWebMediaQueries()
@@ -118,18 +121,18 @@ export const ComposePost = observer(function ComposePost({
const onPressCancel = useCallback(() => {
if (graphemeLength > 0 || !gallery.isEmpty) {
- if (store.shell.activeModals.some(modal => modal.name === 'confirm')) {
- store.shell.closeModal()
+ if (activeModals.some(modal => modal.name === 'confirm')) {
+ closeModal()
}
if (Keyboard) {
Keyboard.dismiss()
}
- store.shell.openModal({
+ openModal({
name: 'confirm',
title: 'Discard draft',
onPressConfirm: onClose,
onPressCancel: () => {
- store.shell.closeModal()
+ closeModal()
},
message: "Are you sure you'd like to discard this draft?",
confirmBtnText: 'Discard',
@@ -138,7 +141,7 @@ export const ComposePost = observer(function ComposePost({
} else {
onClose()
}
- }, [store, onClose, graphemeLength, gallery])
+ }, [openModal, closeModal, activeModals, onClose, graphemeLength, gallery])
// android back button
useEffect(() => {
if (!isAndroid) {
diff --git a/src/view/com/composer/labels/LabelsBtn.tsx b/src/view/com/composer/labels/LabelsBtn.tsx
index 96908d47..4b6ad81c 100644
--- a/src/view/com/composer/labels/LabelsBtn.tsx
+++ b/src/view/com/composer/labels/LabelsBtn.tsx
@@ -3,11 +3,11 @@ import {Keyboard, StyleSheet} from 'react-native'
import {observer} from 'mobx-react-lite'
import {Button} from 'view/com/util/forms/Button'
import {usePalette} from 'lib/hooks/usePalette'
-import {useStores} from 'state/index'
import {ShieldExclamation} from 'lib/icons'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
import {isNative} from 'platform/detection'
+import {useModalControls} from '#/state/modals'
export const LabelsBtn = observer(function LabelsBtn({
labels,
@@ -19,7 +19,7 @@ export const LabelsBtn = observer(function LabelsBtn({
onChange: (v: string[]) => void
}) {
const pal = usePalette('default')
- const store = useStores()
+ const {openModal} = useModalControls()
return (