ALF confirmation dialogs (Dialogs Pt. 3) (#3143)

* Improve a11y on ios

* Format

* Remove android

* Fix android

* ALF confirmation dialog

* Use ALF for Delete Post confirmation

organize

diff

fix text

minimize

change copy

alternative confirm prompt

revert type changes

add ButtonColor param

* small adjustment to buttons in prompt

* full width below gtmobile

* update hide post dialog

* space out dialogs

* update dialogs for lists

* add example

* add to app passwords

* Revert some changes

* use sharedvalue for `importantForAccessibility`

* add back `isOpen`

* fix some more types

* small adjustment to buttons in prompt

* full width below gtmobile

* update the rest of the prompts

rm old confirm modal

rm update prompt

feed error prompt

feed source card and profile block/unblock

composer discard

* Update src/view/screens/AppPasswords.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* lint

* How about a default

* Reverse reverse

* Port over confirm dialogs

* Add some comments

* Remove unused file

* complete merge

* add testID where needed

---------

Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
This commit is contained in:
Hailey 2024-03-12 16:56:14 -07:00 committed by GitHub
parent 090b35e52e
commit 9f2f7f221c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 540 additions and 605 deletions

View file

@ -29,6 +29,8 @@ import {
} from '#/state/queries/app-passwords'
import {ErrorScreen} from '../com/util/error/ErrorScreen'
import {cleanError} from '#/lib/strings/errors'
import * as Prompt from '#/components/Prompt'
import {useDialogControl} from '#/components/Dialog'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'>
export function AppPasswords({}: Props) {
@ -212,23 +214,18 @@ function AppPassword({
}) {
const pal = usePalette('default')
const {_} = useLingui()
const {openModal} = useModalControls()
const control = useDialogControl()
const {contentLanguages} = useLanguagePrefs()
const deleteMutation = useAppPasswordDeleteMutation()
const onDelete = React.useCallback(async () => {
openModal({
name: 'confirm',
title: _(msg`Delete app password`),
message: _(
msg`Are you sure you want to delete the app password "${name}"?`,
),
async onPressConfirm() {
await deleteMutation.mutateAsync({name})
Toast.show(_(msg`App password deleted`))
},
})
}, [deleteMutation, openModal, name, _])
await deleteMutation.mutateAsync({name})
Toast.show(_(msg`App password deleted`))
}, [deleteMutation, name, _])
const onPress = React.useCallback(() => {
control.open()
}, [control])
const primaryLocale =
contentLanguages.length > 0 ? contentLanguages[0] : 'en-US'
@ -237,7 +234,7 @@ function AppPassword({
<TouchableOpacity
testID={testID}
style={[styles.item, pal.border]}
onPress={onDelete}
onPress={onPress}
accessibilityRole="button"
accessibilityLabel={_(msg`Delete app password`)}
accessibilityHint="">
@ -260,6 +257,17 @@ function AppPassword({
</Text>
</View>
<FontAwesomeIcon icon={['far', 'trash-can']} style={styles.trashIcon} />
<Prompt.Basic
control={control}
title={_(msg`Delete app password?`)}
description={_(
msg`Are you sure you want to delete the app password "${name}"?`,
)}
onConfirm={onDelete}
confirmButtonCta={_(msg`Delete`)}
confirmButtonColor="negative"
/>
</TouchableOpacity>
)
}

View file

@ -61,6 +61,8 @@ import {logger} from '#/logger'
import {useAnalytics} from '#/lib/analytics/analytics'
import {listenSoftReset} from '#/state/events'
import {atoms as a, useTheme} from '#/alf'
import * as Prompt from '#/components/Prompt'
import {useDialogControl} from '#/components/Dialog'
const SECTION_TITLES_CURATE = ['Posts', 'About']
const SECTION_TITLES_MOD = ['About']
@ -234,7 +236,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
const {_} = useLingui()
const navigation = useNavigation<NavigationProp>()
const {currentAccount} = useSession()
const {openModal, closeModal} = useModalControls()
const {openModal} = useModalControls()
const listMuteMutation = useListMuteMutation()
const listBlockMutation = useListBlockMutation()
const listDeleteMutation = useListDeleteMutation()
@ -251,6 +253,10 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
const {mutate: setSavedFeeds} = useSetSaveFeedsMutation()
const {track} = useAnalytics()
const deleteListPromptControl = useDialogControl()
const subscribeMutePromptControl = useDialogControl()
const subscribeBlockPromptControl = useDialogControl()
const isPinned = preferences?.feeds?.pinned?.includes(list.uri)
const isSaved = preferences?.feeds?.saved?.includes(list.uri)
@ -269,32 +275,19 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
}
}, [list.uri, isPinned, pinFeed, unpinFeed, _])
const onSubscribeMute = useCallback(() => {
openModal({
name: 'confirm',
title: _(msg`Mute these accounts?`),
message: _(
msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`,
),
confirmBtnText: _(msg`Mute this List`),
async onPressConfirm() {
try {
await listMuteMutation.mutateAsync({uri: list.uri, mute: true})
Toast.show(_(msg`List muted`))
track('Lists:Mute')
} catch {
Toast.show(
_(
msg`There was an issue. Please check your internet connection and try again.`,
),
)
}
},
onPressCancel() {
closeModal()
},
})
}, [openModal, closeModal, list, listMuteMutation, track, _])
const onSubscribeMute = useCallback(async () => {
try {
await listMuteMutation.mutateAsync({uri: list.uri, mute: true})
Toast.show(_(msg`List muted`))
track('Lists:Mute')
} catch {
Toast.show(
_(
msg`There was an issue. Please check your internet connection and try again.`,
),
)
}
}, [list, listMuteMutation, track, _])
const onUnsubscribeMute = useCallback(async () => {
try {
@ -310,32 +303,19 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
}
}, [list, listMuteMutation, track, _])
const onSubscribeBlock = useCallback(() => {
openModal({
name: 'confirm',
title: _(msg`Block these accounts?`),
message: _(
msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`,
),
confirmBtnText: _(msg`Block this List`),
async onPressConfirm() {
try {
await listBlockMutation.mutateAsync({uri: list.uri, block: true})
Toast.show(_(msg`List blocked`))
track('Lists:Block')
} catch {
Toast.show(
_(
msg`There was an issue. Please check your internet connection and try again.`,
),
)
}
},
onPressCancel() {
closeModal()
},
})
}, [openModal, closeModal, list, listBlockMutation, track, _])
const onSubscribeBlock = useCallback(async () => {
try {
await listBlockMutation.mutateAsync({uri: list.uri, block: true})
Toast.show(_(msg`List blocked`))
track('Lists:Block')
} catch {
Toast.show(
_(
msg`There was an issue. Please check your internet connection and try again.`,
),
)
}
}, [list, listBlockMutation, track, _])
const onUnsubscribeBlock = useCallback(async () => {
try {
@ -358,34 +338,26 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
})
}, [openModal, list])
const onPressDelete = useCallback(() => {
openModal({
name: 'confirm',
title: _(msg`Delete List`),
message: _(msg`Are you sure?`),
async onPressConfirm() {
await listDeleteMutation.mutateAsync({uri: list.uri})
const onPressDelete = useCallback(async () => {
await listDeleteMutation.mutateAsync({uri: list.uri})
if (isSaved || isPinned) {
const {saved, pinned} = preferences!.feeds
if (isSaved || isPinned) {
const {saved, pinned} = preferences!.feeds
setSavedFeeds({
saved: isSaved ? saved.filter(uri => uri !== list.uri) : saved,
pinned: isPinned ? pinned.filter(uri => uri !== list.uri) : pinned,
})
}
setSavedFeeds({
saved: isSaved ? saved.filter(uri => uri !== list.uri) : saved,
pinned: isPinned ? pinned.filter(uri => uri !== list.uri) : pinned,
})
}
Toast.show(_(msg`List deleted`))
track('Lists:Delete')
if (navigation.canGoBack()) {
navigation.goBack()
} else {
navigation.navigate('Home')
}
},
})
Toast.show(_(msg`List deleted`))
track('Lists:Delete')
if (navigation.canGoBack()) {
navigation.goBack()
} else {
navigation.navigate('Home')
}
}, [
openModal,
list,
listDeleteMutation,
navigation,
@ -443,7 +415,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
items.push({
testID: 'listHeaderDropdownDeleteBtn',
label: _(msg`Delete List`),
onPress: onPressDelete,
onPress: deleteListPromptControl.open,
icon: {
ios: {
name: 'trash',
@ -489,7 +461,9 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
items.push({
testID: 'listHeaderDropdownMuteBtn',
label: isMuting ? _(msg`Un-mute list`) : _(msg`Mute list`),
onPress: isMuting ? onUnsubscribeMute : onSubscribeMute,
onPress: isMuting
? onUnsubscribeMute
: subscribeMutePromptControl.open,
icon: {
ios: {
name: isMuting ? 'eye' : 'eye.slash',
@ -504,7 +478,9 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
items.push({
testID: 'listHeaderDropdownBlockBtn',
label: isBlocking ? _(msg`Un-block list`) : _(msg`Block list`),
onPress: isBlocking ? onUnsubscribeBlock : onSubscribeBlock,
onPress: isBlocking
? onUnsubscribeBlock
: subscribeBlockPromptControl.open,
icon: {
ios: {
name: 'person.fill.xmark',
@ -517,24 +493,24 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
}
return items
}, [
isOwner,
onPressShare,
onPressEdit,
onPressDelete,
onPressReport,
_,
onPressShare,
isOwner,
isModList,
isPinned,
unpinFeed,
isPending,
list.uri,
isCurateList,
isMuting,
onPressEdit,
deleteListPromptControl.open,
onPressReport,
isPending,
unpinFeed,
list.uri,
isBlocking,
isMuting,
onUnsubscribeMute,
onSubscribeMute,
subscribeMutePromptControl.open,
onUnsubscribeBlock,
onSubscribeBlock,
subscribeBlockPromptControl.open,
])
const subscribeDropdownItems: DropdownItem[] = useMemo(() => {
@ -542,7 +518,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
{
testID: 'subscribeDropdownMuteBtn',
label: _(msg`Mute accounts`),
onPress: onSubscribeMute,
onPress: subscribeMutePromptControl.open,
icon: {
ios: {
name: 'speaker.slash',
@ -554,7 +530,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
{
testID: 'subscribeDropdownBlockBtn',
label: _(msg`Block accounts`),
onPress: onSubscribeBlock,
onPress: subscribeBlockPromptControl.open,
icon: {
ios: {
name: 'person.fill.xmark',
@ -564,7 +540,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
},
},
]
}, [onSubscribeMute, onSubscribeBlock, _])
}, [_, subscribeMutePromptControl.open, subscribeBlockPromptControl.open])
return (
<ProfileSubpageHeader
@ -620,6 +596,38 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
<FontAwesomeIcon icon="ellipsis" size={20} color={pal.colors.text} />
</View>
</NativeDropdown>
<Prompt.Basic
control={deleteListPromptControl}
title={_(msg`Delete this list?`)}
description={_(
msg`If you delete this list, you won't be able to recover it.`,
)}
onConfirm={onPressDelete}
confirmButtonCta={_(msg`Delete`)}
confirmButtonColor="negative"
/>
<Prompt.Basic
control={subscribeMutePromptControl}
title={_(msg`Mute these accounts?`)}
description={_(
msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`,
)}
onConfirm={onSubscribeMute}
confirmButtonCta={_(msg`Mute list`)}
/>
<Prompt.Basic
control={subscribeBlockPromptControl}
title={_(msg`Block these accounts?`)}
description={_(
msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`,
)}
onConfirm={onSubscribeBlock}
confirmButtonCta={_(msg`Block list`)}
confirmButtonColor="negative"
/>
</ProfileSubpageHeader>
)
}

View file

@ -68,7 +68,7 @@ export function Dialogs() {
</Prompt.Description>
<Prompt.Actions>
<Prompt.Cancel>Cancel</Prompt.Cancel>
<Prompt.Action>Confirm</Prompt.Action>
<Prompt.Action onPress={() => {}}>Confirm</Prompt.Action>
</Prompt.Actions>
</Prompt.Outer>