Assorted clipclop fixes (#3853)

* empty state for new chat dialog

* use terniary

* dark mode pending state

* copy message text option

* fix service url input (scrollview ftw)

* whoops, fix equality

* slightly reduce horizontal message padding
zio/stable
Samuel Newman 2024-05-04 01:49:49 +01:00 committed by GitHub
parent feff55a14a
commit c223bcdaf7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 67 additions and 23 deletions

View File

@ -62,19 +62,23 @@ export let MessageItem = ({
lastInGroupRef.current = isLastInGroup lastInGroupRef.current = isLastInGroup
} }
const pendingColor =
t.name === 'light' ? t.palette.primary_200 : t.palette.primary_800
return ( return (
<View> <View>
<ActionsWrapper isFromSelf={isFromSelf} message={item}> <ActionsWrapper isFromSelf={isFromSelf} message={item}>
<View <View
style={[ style={[
a.py_sm, a.py_sm,
a.px_lg,
a.my_2xs, a.my_2xs,
a.rounded_md, a.rounded_md,
{ {
paddingLeft: 14,
paddingRight: 14,
backgroundColor: isFromSelf backgroundColor: isFromSelf
? pending ? pending
? t.palette.primary_200 ? pendingColor
: t.palette.primary_500 : t.palette.primary_500
: t.palette.contrast_50, : t.palette.contrast_50,
borderRadius: 17, borderRadius: 17,
@ -88,6 +92,7 @@ export let MessageItem = ({
a.text_md, a.text_md,
a.leading_snug, a.leading_snug,
isFromSelf && {color: t.palette.white}, isFromSelf && {color: t.palette.white},
pending && t.name !== 'light' && {color: t.palette.primary_300},
]}> ]}>
{item.text} {item.text}
</Text> </Text>

View File

@ -1,10 +1,12 @@
import React from 'react' import React from 'react'
import {Pressable, View} from 'react-native' import {Pressable, View} from 'react-native'
import * as Clipboard from 'expo-clipboard'
import {ChatBskyConvoDefs} from '@atproto-labs/api' import {ChatBskyConvoDefs} from '@atproto-labs/api'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useSession} from 'state/session' import {useSession} from 'state/session'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid' import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
@ -12,6 +14,7 @@ import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/War
import * as Menu from '#/components/Menu' import * as Menu from '#/components/Menu'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
import {usePromptControl} from '#/components/Prompt' import {usePromptControl} from '#/components/Prompt'
import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '../icons/Clipboard'
export let MessageMenu = ({ export let MessageMenu = ({
message, message,
@ -32,6 +35,14 @@ export let MessageMenu = ({
const isFromSelf = message.sender?.did === currentAccount?.did const isFromSelf = message.sender?.did === currentAccount?.did
const onCopyPostText = React.useCallback(() => {
// use when we have rich text
// const str = richTextToString(richText, true)
Clipboard.setStringAsync(message.text)
Toast.show(_(msg`Copied to clipboard`))
}, [_, message.text])
const onDelete = React.useCallback(() => { const onDelete = React.useCallback(() => {
// TODO delete the message // TODO delete the message
}, []) }, [])
@ -62,12 +73,22 @@ export let MessageMenu = ({
)} )}
<Menu.Outer> <Menu.Outer>
<Menu.Group>
<Menu.Item
testID="messageDropdownCopyBtn"
label={_(msg`Copy message text`)}
onPress={onCopyPostText}>
<Menu.ItemText>{_(msg`Copy message text`)}</Menu.ItemText>
<Menu.ItemIcon icon={ClipboardIcon} position="right" />
</Menu.Item>
</Menu.Group>
<Menu.Divider />
<Menu.Group> <Menu.Group>
<Menu.Item <Menu.Item
testID="messageDropdownDeleteBtn" testID="messageDropdownDeleteBtn"
label={_(msg`Delete message`)} label={_(msg`Delete message for me`)}
onPress={deleteControl.open}> onPress={deleteControl.open}>
<Menu.ItemText>{_(msg`Delete`)}</Menu.ItemText> <Menu.ItemText>{_(msg`Delete for me`)}</Menu.ItemText>
<Menu.ItemIcon icon={Trash} position="right" /> <Menu.ItemIcon icon={Trash} position="right" />
</Menu.Item> </Menu.Item>
{!isFromSelf && ( {!isFromSelf && (

View File

@ -20,6 +20,7 @@ import * as TextField from '#/components/forms/TextField'
import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {Button} from '../Button' import {Button} from '../Button'
import {Envelope_Stroke2_Corner0_Rounded as Envelope} from '../icons/Envelope'
import {ListMaybePlaceholder} from '../Lists' import {ListMaybePlaceholder} from '../Lists'
import {Text} from '../Typography' import {Text} from '../Typography'
@ -178,7 +179,7 @@ function SearchablePeopleList({
</Text> </Text>
<TextField.Root> <TextField.Root>
<TextField.Icon icon={Search} /> <TextField.Icon icon={Search} />
<TextField.Input <Dialog.Input
label={_(msg`Search profiles`)} label={_(msg`Search profiles`)}
placeholder={_(msg`Search`)} placeholder={_(msg`Search`)}
value={searchText} value={searchText}
@ -197,6 +198,7 @@ function SearchablePeopleList({
autoCorrect={false} autoCorrect={false}
autoComplete="off" autoComplete="off"
autoCapitalize="none" autoCapitalize="none"
autoFocus
/> />
</TextField.Root> </TextField.Root>
</View> </View>
@ -211,20 +213,35 @@ function SearchablePeopleList({
ListHeaderComponent={ ListHeaderComponent={
<> <>
{listHeader} {listHeader}
{searchText.length > 0 && !actorAutocompleteData?.length && ( {searchText.length === 0 ? (
<ListMaybePlaceholder <View style={[a.pt_4xl, a.align_center, a.px_lg]}>
isLoading={isFetching} <Envelope width={64} fill={t.palette.contrast_200} />
isError={isError} <Text
onRetry={refetch} style={[
hideBackButton={true} a.text_lg,
emptyType="results" a.text_center,
sideBorders={false} a.mt_md,
emptyMessage={ t.atoms.text_contrast_low,
isError ]}>
? _(msg`No search results found for "${searchText}".`) <Trans>Search for someone to start a conversation with.</Trans>
: _(msg`Could not load profiles. Please try again later.`) </Text>
} </View>
/> ) : (
!actorAutocompleteData?.length && (
<ListMaybePlaceholder
isLoading={isFetching}
isError={isError}
onRetry={refetch}
hideBackButton={true}
emptyType="results"
sideBorders={false}
emptyMessage={
isError
? _(msg`No search results found for "${searchText}".`)
: _(msg`Could not load profiles. Please try again later.`)
}
/>
)
)} )}
</> </>
} }

View File

@ -21,6 +21,7 @@ import {TimeElapsed} from '#/view/com/util/TimeElapsed'
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
import {ViewHeader} from '#/view/com/util/ViewHeader' import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from '#/view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {ScrollView} from '#/view/com/util/Views'
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {DialogControlProps, useDialogControl} from '#/components/Dialog' import {DialogControlProps, useDialogControl} from '#/components/Dialog'
@ -130,7 +131,7 @@ export function MessagesScreen({navigation}: Props) {
if (!hasValidServiceUrl) { if (!hasValidServiceUrl) {
return ( return (
<CenteredView sideBorders style={[a.flex_1, a.p_md]}> <ScrollView contentContainerStyle={a.p_lg}>
<View> <View>
<TextField.LabelText>Service URL</TextField.LabelText> <TextField.LabelText>Service URL</TextField.LabelText>
<TextField.Root> <TextField.Root>
@ -143,7 +144,7 @@ export function MessagesScreen({navigation}: Props) {
/> />
</TextField.Root> </TextField.Root>
</View> </View>
</CenteredView> </ScrollView>
) )
} }

View File

@ -1,6 +1,6 @@
import React, {memo} from 'react' import React, {memo} from 'react'
import {Pressable, PressableProps, StyleProp, ViewStyle} from 'react-native' import {Pressable, PressableProps, StyleProp, ViewStyle} from 'react-native'
import {setStringAsync} from 'expo-clipboard' import * as Clipboard from 'expo-clipboard'
import { import {
AppBskyActorDefs, AppBskyActorDefs,
AppBskyFeedPost, AppBskyFeedPost,
@ -160,7 +160,7 @@ let PostDropdownBtn = ({
const onCopyPostText = React.useCallback(() => { const onCopyPostText = React.useCallback(() => {
const str = richTextToString(richText, true) const str = richTextToString(richText, true)
setStringAsync(str) Clipboard.setStringAsync(str)
Toast.show(_(msg`Copied to clipboard`)) Toast.show(_(msg`Copied to clipboard`))
}, [_, richText]) }, [_, richText])