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 paddingzio/stable
parent
feff55a14a
commit
c223bcdaf7
|
@ -62,19 +62,23 @@ export let MessageItem = ({
|
|||
lastInGroupRef.current = isLastInGroup
|
||||
}
|
||||
|
||||
const pendingColor =
|
||||
t.name === 'light' ? t.palette.primary_200 : t.palette.primary_800
|
||||
|
||||
return (
|
||||
<View>
|
||||
<ActionsWrapper isFromSelf={isFromSelf} message={item}>
|
||||
<View
|
||||
style={[
|
||||
a.py_sm,
|
||||
a.px_lg,
|
||||
a.my_2xs,
|
||||
a.rounded_md,
|
||||
{
|
||||
paddingLeft: 14,
|
||||
paddingRight: 14,
|
||||
backgroundColor: isFromSelf
|
||||
? pending
|
||||
? t.palette.primary_200
|
||||
? pendingColor
|
||||
: t.palette.primary_500
|
||||
: t.palette.contrast_50,
|
||||
borderRadius: 17,
|
||||
|
@ -88,6 +92,7 @@ export let MessageItem = ({
|
|||
a.text_md,
|
||||
a.leading_snug,
|
||||
isFromSelf && {color: t.palette.white},
|
||||
pending && t.name !== 'light' && {color: t.palette.primary_300},
|
||||
]}>
|
||||
{item.text}
|
||||
</Text>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import React from 'react'
|
||||
import {Pressable, View} from 'react-native'
|
||||
import * as Clipboard from 'expo-clipboard'
|
||||
import {ChatBskyConvoDefs} from '@atproto-labs/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useSession} from 'state/session'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
|
||||
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 Prompt from '#/components/Prompt'
|
||||
import {usePromptControl} from '#/components/Prompt'
|
||||
import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '../icons/Clipboard'
|
||||
|
||||
export let MessageMenu = ({
|
||||
message,
|
||||
|
@ -32,6 +35,14 @@ export let MessageMenu = ({
|
|||
|
||||
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(() => {
|
||||
// TODO delete the message
|
||||
}, [])
|
||||
|
@ -62,12 +73,22 @@ export let MessageMenu = ({
|
|||
)}
|
||||
|
||||
<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.Item
|
||||
testID="messageDropdownDeleteBtn"
|
||||
label={_(msg`Delete message`)}
|
||||
label={_(msg`Delete message for me`)}
|
||||
onPress={deleteControl.open}>
|
||||
<Menu.ItemText>{_(msg`Delete`)}</Menu.ItemText>
|
||||
<Menu.ItemText>{_(msg`Delete for me`)}</Menu.ItemText>
|
||||
<Menu.ItemIcon icon={Trash} position="right" />
|
||||
</Menu.Item>
|
||||
{!isFromSelf && (
|
||||
|
|
|
@ -20,6 +20,7 @@ import * as TextField from '#/components/forms/TextField'
|
|||
import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2'
|
||||
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
|
||||
import {Button} from '../Button'
|
||||
import {Envelope_Stroke2_Corner0_Rounded as Envelope} from '../icons/Envelope'
|
||||
import {ListMaybePlaceholder} from '../Lists'
|
||||
import {Text} from '../Typography'
|
||||
|
||||
|
@ -178,7 +179,7 @@ function SearchablePeopleList({
|
|||
</Text>
|
||||
<TextField.Root>
|
||||
<TextField.Icon icon={Search} />
|
||||
<TextField.Input
|
||||
<Dialog.Input
|
||||
label={_(msg`Search profiles`)}
|
||||
placeholder={_(msg`Search`)}
|
||||
value={searchText}
|
||||
|
@ -197,6 +198,7 @@ function SearchablePeopleList({
|
|||
autoCorrect={false}
|
||||
autoComplete="off"
|
||||
autoCapitalize="none"
|
||||
autoFocus
|
||||
/>
|
||||
</TextField.Root>
|
||||
</View>
|
||||
|
@ -211,20 +213,35 @@ function SearchablePeopleList({
|
|||
ListHeaderComponent={
|
||||
<>
|
||||
{listHeader}
|
||||
{searchText.length > 0 && !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.`)
|
||||
}
|
||||
/>
|
||||
{searchText.length === 0 ? (
|
||||
<View style={[a.pt_4xl, a.align_center, a.px_lg]}>
|
||||
<Envelope width={64} fill={t.palette.contrast_200} />
|
||||
<Text
|
||||
style={[
|
||||
a.text_lg,
|
||||
a.text_center,
|
||||
a.mt_md,
|
||||
t.atoms.text_contrast_low,
|
||||
]}>
|
||||
<Trans>Search for someone to start a conversation with.</Trans>
|
||||
</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.`)
|
||||
}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</>
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import {TimeElapsed} from '#/view/com/util/TimeElapsed'
|
|||
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {ViewHeader} from '#/view/com/util/ViewHeader'
|
||||
import {CenteredView} from '#/view/com/util/Views'
|
||||
import {ScrollView} from '#/view/com/util/Views'
|
||||
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {DialogControlProps, useDialogControl} from '#/components/Dialog'
|
||||
|
@ -130,7 +131,7 @@ export function MessagesScreen({navigation}: Props) {
|
|||
|
||||
if (!hasValidServiceUrl) {
|
||||
return (
|
||||
<CenteredView sideBorders style={[a.flex_1, a.p_md]}>
|
||||
<ScrollView contentContainerStyle={a.p_lg}>
|
||||
<View>
|
||||
<TextField.LabelText>Service URL</TextField.LabelText>
|
||||
<TextField.Root>
|
||||
|
@ -143,7 +144,7 @@ export function MessagesScreen({navigation}: Props) {
|
|||
/>
|
||||
</TextField.Root>
|
||||
</View>
|
||||
</CenteredView>
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, {memo} from 'react'
|
||||
import {Pressable, PressableProps, StyleProp, ViewStyle} from 'react-native'
|
||||
import {setStringAsync} from 'expo-clipboard'
|
||||
import * as Clipboard from 'expo-clipboard'
|
||||
import {
|
||||
AppBskyActorDefs,
|
||||
AppBskyFeedPost,
|
||||
|
@ -160,7 +160,7 @@ let PostDropdownBtn = ({
|
|||
const onCopyPostText = React.useCallback(() => {
|
||||
const str = richTextToString(richText, true)
|
||||
|
||||
setStringAsync(str)
|
||||
Clipboard.setStringAsync(str)
|
||||
Toast.show(_(msg`Copied to clipboard`))
|
||||
}, [_, richText])
|
||||
|
||||
|
|
Loading…
Reference in New Issue