Big batch of UI updates (#276)
* Replace react-native-root-toast with a custom toast that fits the visual style * Tune dark mode colors * Tune colors a bit more * Move the reply prompt to a fixed position in the footer * Fully hide muted posts but give a control to show anyway (close #270) * Improve thread rendering (better clarity on reply lines) * Add follower/following counts to side menu * Fix issues with display name overflows
This commit is contained in:
parent
2f3fc4fe4e
commit
e74f94bc72
19 changed files with 381 additions and 249 deletions
|
@ -1,91 +1,45 @@
|
|||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {StyleSheet, TouchableOpacity} from 'react-native'
|
||||
import {UserAvatar} from '../util/UserAvatar'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useStores} from 'state/index'
|
||||
|
||||
export function ComposePrompt({
|
||||
text = "What's up?",
|
||||
btn = 'Post',
|
||||
isReply = false,
|
||||
onPressCompose,
|
||||
}: {
|
||||
text?: string
|
||||
btn?: string
|
||||
isReply?: boolean
|
||||
onPressCompose: (imagesOpen?: boolean) => void
|
||||
}) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<TouchableOpacity
|
||||
testID="composePromptButton"
|
||||
style={[
|
||||
pal.view,
|
||||
pal.border,
|
||||
styles.container,
|
||||
isReply ? styles.containerReply : undefined,
|
||||
]}
|
||||
testID="replyPromptBtn"
|
||||
style={[pal.view, pal.border, styles.prompt]}
|
||||
onPress={() => onPressCompose()}>
|
||||
{!isReply && (
|
||||
<FontAwesomeIcon
|
||||
icon={['fas', 'pen-nib']}
|
||||
size={18}
|
||||
style={[pal.textLight, styles.iconLeft]}
|
||||
/>
|
||||
)}
|
||||
<View style={styles.textContainer}>
|
||||
<Text type={isReply ? 'lg' : 'lg-medium'} style={pal.textLight}>
|
||||
{text}
|
||||
</Text>
|
||||
</View>
|
||||
{isReply ? (
|
||||
<View
|
||||
style={[styles.btn, {backgroundColor: pal.colors.backgroundLight}]}>
|
||||
<Text type="button" style={pal.textLight}>
|
||||
{btn}
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
<TouchableOpacity onPress={() => onPressCompose(true)}>
|
||||
<FontAwesomeIcon
|
||||
icon={['far', 'image']}
|
||||
size={18}
|
||||
style={[pal.textLight, styles.iconRight]}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<UserAvatar
|
||||
handle={store.me.handle}
|
||||
avatar={store.me.avatar}
|
||||
displayName={store.me.displayName}
|
||||
size={38}
|
||||
/>
|
||||
<Text type="xl" style={[pal.text, styles.label]}>
|
||||
Write your reply
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
iconLeft: {
|
||||
marginLeft: 22,
|
||||
marginRight: 2,
|
||||
},
|
||||
iconRight: {
|
||||
marginRight: 20,
|
||||
},
|
||||
container: {
|
||||
paddingVertical: 16,
|
||||
prompt: {
|
||||
paddingHorizontal: 20,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
containerReply: {
|
||||
paddingVertical: 14,
|
||||
paddingHorizontal: 10,
|
||||
},
|
||||
avatar: {
|
||||
width: 50,
|
||||
},
|
||||
textContainer: {
|
||||
marginLeft: 10,
|
||||
flex: 1,
|
||||
},
|
||||
btn: {
|
||||
paddingVertical: 6,
|
||||
paddingHorizontal: 14,
|
||||
borderRadius: 30,
|
||||
label: {
|
||||
paddingLeft: 12,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -90,10 +90,10 @@ export const FeedItem = observer(function FeedItem({
|
|||
style={
|
||||
item.isRead
|
||||
? undefined
|
||||
: [
|
||||
styles.outerUnread,
|
||||
{backgroundColor: pal.colors.unreadNotifBg},
|
||||
]
|
||||
: {
|
||||
backgroundColor: pal.colors.unreadNotifBg,
|
||||
borderColor: pal.colors.unreadNotifBorder,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Link>
|
||||
|
@ -152,7 +152,10 @@ export const FeedItem = observer(function FeedItem({
|
|||
pal.border,
|
||||
item.isRead
|
||||
? undefined
|
||||
: [styles.outerUnread, {backgroundColor: pal.colors.unreadNotifBg}],
|
||||
: {
|
||||
backgroundColor: pal.colors.unreadNotifBg,
|
||||
borderColor: pal.colors.unreadNotifBorder,
|
||||
},
|
||||
]}
|
||||
href={itemHref}
|
||||
title={itemTitle}
|
||||
|
@ -391,9 +394,6 @@ const styles = StyleSheet.create({
|
|||
paddingRight: 15,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
outerUnread: {
|
||||
borderColor: colors.blue1,
|
||||
},
|
||||
layout: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
|
|
|
@ -96,7 +96,7 @@ export const PostThread = observer(function PostThread({
|
|||
onLayout={onLayout}
|
||||
onScrollToIndexFailed={onScrollToIndexFailed}
|
||||
style={s.hContentRegion}
|
||||
contentContainerStyle={s.contentContainer}
|
||||
contentContainerStyle={s.contentContainerExtra}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -21,8 +21,8 @@ import {useStores} from 'state/index'
|
|||
import {PostMeta} from '../util/PostMeta'
|
||||
import {PostEmbeds} from '../util/PostEmbeds'
|
||||
import {PostCtrls} from '../util/PostCtrls'
|
||||
import {PostMutedWrapper} from '../util/PostMuted'
|
||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||
import {ComposePrompt} from '../composer/Prompt'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
|
||||
const PARENT_REPLY_LINE_LENGTH = 8
|
||||
|
@ -271,23 +271,17 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<ComposePrompt
|
||||
isReply
|
||||
text="Write your reply"
|
||||
btn="Reply"
|
||||
onPressCompose={onPressReply}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<PostMutedWrapper isMuted={item.post.author.viewer?.muted === true}>
|
||||
<Link
|
||||
style={[styles.outer, {borderTopColor: pal.colors.border}, pal.view]}
|
||||
href={itemHref}
|
||||
title={itemTitle}
|
||||
noFeedback>
|
||||
{record.reply && (
|
||||
{item._showParentReplyLine && (
|
||||
<View
|
||||
style={[
|
||||
styles.parentReplyLine,
|
||||
|
@ -295,7 +289,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
]}
|
||||
/>
|
||||
)}
|
||||
{item.replies?.length !== 0 && (
|
||||
{item._showChildReplyLine && (
|
||||
<View
|
||||
style={[
|
||||
styles.childReplyLine,
|
||||
|
@ -322,12 +316,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
did={item.post.author.did}
|
||||
declarationCid={item.post.author.declaration.cid}
|
||||
/>
|
||||
{item.post.author.viewer?.muted ? (
|
||||
<View style={[styles.mutedWarning, pal.btn]}>
|
||||
<FontAwesomeIcon icon={['far', 'eye-slash']} style={s.mr2} />
|
||||
<Text type="sm">This post is by a muted account.</Text>
|
||||
</View>
|
||||
) : item.richText?.text ? (
|
||||
{item.richText?.text ? (
|
||||
<View style={styles.postTextContainer}>
|
||||
<RichText
|
||||
type="post-text"
|
||||
|
@ -384,7 +373,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
/>
|
||||
</Link>
|
||||
) : undefined}
|
||||
</>
|
||||
</PostMutedWrapper>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
@ -441,14 +430,6 @@ const styles = StyleSheet.create({
|
|||
paddingRight: 5,
|
||||
maxWidth: 240,
|
||||
},
|
||||
mutedWarning: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
padding: 10,
|
||||
marginTop: 2,
|
||||
marginBottom: 6,
|
||||
borderRadius: 2,
|
||||
},
|
||||
postTextContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
|
|
|
@ -17,6 +17,7 @@ import {UserInfoText} from '../util/UserInfoText'
|
|||
import {PostMeta} from '../util/PostMeta'
|
||||
import {PostEmbeds} from '../util/PostEmbeds'
|
||||
import {PostCtrls} from '../util/PostCtrls'
|
||||
import {PostMutedWrapper} from '../util/PostMuted'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {RichText} from '../util/text/RichText'
|
||||
import * as Toast from '../util/Toast'
|
||||
|
@ -140,92 +141,89 @@ export const Post = observer(function Post({
|
|||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
style={[styles.outer, pal.view, pal.border, style]}
|
||||
href={itemHref}
|
||||
title={itemTitle}
|
||||
noFeedback>
|
||||
{showReplyLine && <View style={styles.replyLine} />}
|
||||
<View style={styles.layout}>
|
||||
<View style={styles.layoutAvi}>
|
||||
<Link href={authorHref} title={authorTitle}>
|
||||
<UserAvatar
|
||||
size={52}
|
||||
displayName={item.post.author.displayName}
|
||||
handle={item.post.author.handle}
|
||||
avatar={item.post.author.avatar}
|
||||
<PostMutedWrapper isMuted={item.post.author.viewer?.muted === true}>
|
||||
<Link
|
||||
style={[styles.outer, pal.view, pal.border, style]}
|
||||
href={itemHref}
|
||||
title={itemTitle}
|
||||
noFeedback>
|
||||
{showReplyLine && <View style={styles.replyLine} />}
|
||||
<View style={styles.layout}>
|
||||
<View style={styles.layoutAvi}>
|
||||
<Link href={authorHref} title={authorTitle}>
|
||||
<UserAvatar
|
||||
size={52}
|
||||
displayName={item.post.author.displayName}
|
||||
handle={item.post.author.handle}
|
||||
avatar={item.post.author.avatar}
|
||||
/>
|
||||
</Link>
|
||||
</View>
|
||||
<View style={styles.layoutContent}>
|
||||
<PostMeta
|
||||
authorHandle={item.post.author.handle}
|
||||
authorDisplayName={item.post.author.displayName}
|
||||
timestamp={item.post.indexedAt}
|
||||
did={item.post.author.did}
|
||||
declarationCid={item.post.author.declaration.cid}
|
||||
/>
|
||||
</Link>
|
||||
{replyAuthorDid !== '' && (
|
||||
<View style={[s.flexRow, s.mb2, s.alignCenter]}>
|
||||
<FontAwesomeIcon
|
||||
icon="reply"
|
||||
size={9}
|
||||
style={[pal.textLight, s.mr5]}
|
||||
/>
|
||||
<Text type="sm" style={[pal.textLight, s.mr2]} lineHeight={1.2}>
|
||||
Reply to
|
||||
</Text>
|
||||
<UserInfoText
|
||||
type="sm"
|
||||
did={replyAuthorDid}
|
||||
attr="displayName"
|
||||
style={[pal.textLight]}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
{item.richText?.text ? (
|
||||
<View style={styles.postTextContainer}>
|
||||
<RichText
|
||||
type="post-text"
|
||||
richText={item.richText}
|
||||
lineHeight={1.3}
|
||||
/>
|
||||
</View>
|
||||
) : undefined}
|
||||
<PostEmbeds embed={item.post.embed} style={s.mb10} />
|
||||
<PostCtrls
|
||||
itemUri={itemUri}
|
||||
itemCid={itemCid}
|
||||
itemHref={itemHref}
|
||||
itemTitle={itemTitle}
|
||||
author={{
|
||||
avatar: item.post.author.avatar!,
|
||||
handle: item.post.author.handle,
|
||||
displayName: item.post.author.displayName!,
|
||||
}}
|
||||
indexedAt={item.post.indexedAt}
|
||||
text={item.richText?.text || record.text}
|
||||
isAuthor={item.post.author.did === store.me.did}
|
||||
replyCount={item.post.replyCount}
|
||||
repostCount={item.post.repostCount}
|
||||
upvoteCount={item.post.upvoteCount}
|
||||
isReposted={!!item.post.viewer.repost}
|
||||
isUpvoted={!!item.post.viewer.upvote}
|
||||
onPressReply={onPressReply}
|
||||
onPressToggleRepost={onPressToggleRepost}
|
||||
onPressToggleUpvote={onPressToggleUpvote}
|
||||
onCopyPostText={onCopyPostText}
|
||||
onOpenTranslate={onOpenTranslate}
|
||||
onDeletePost={onDeletePost}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.layoutContent}>
|
||||
<PostMeta
|
||||
authorHandle={item.post.author.handle}
|
||||
authorDisplayName={item.post.author.displayName}
|
||||
timestamp={item.post.indexedAt}
|
||||
did={item.post.author.did}
|
||||
declarationCid={item.post.author.declaration.cid}
|
||||
/>
|
||||
{replyAuthorDid !== '' && (
|
||||
<View style={[s.flexRow, s.mb2, s.alignCenter]}>
|
||||
<FontAwesomeIcon
|
||||
icon="reply"
|
||||
size={9}
|
||||
style={[pal.textLight, s.mr5]}
|
||||
/>
|
||||
<Text type="sm" style={[pal.textLight, s.mr2]} lineHeight={1.2}>
|
||||
Reply to
|
||||
</Text>
|
||||
<UserInfoText
|
||||
type="sm"
|
||||
did={replyAuthorDid}
|
||||
attr="displayName"
|
||||
style={[pal.textLight]}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
{item.post.author.viewer?.muted ? (
|
||||
<View style={[styles.mutedWarning, pal.btn]}>
|
||||
<FontAwesomeIcon icon={['far', 'eye-slash']} style={s.mr2} />
|
||||
<Text type="sm">This post is by a muted account.</Text>
|
||||
</View>
|
||||
) : item.richText?.text ? (
|
||||
<View style={styles.postTextContainer}>
|
||||
<RichText
|
||||
type="post-text"
|
||||
richText={item.richText}
|
||||
lineHeight={1.3}
|
||||
/>
|
||||
</View>
|
||||
) : undefined}
|
||||
<PostEmbeds embed={item.post.embed} style={s.mb10} />
|
||||
<PostCtrls
|
||||
itemUri={itemUri}
|
||||
itemCid={itemCid}
|
||||
itemHref={itemHref}
|
||||
itemTitle={itemTitle}
|
||||
author={{
|
||||
avatar: item.post.author.avatar!,
|
||||
handle: item.post.author.handle,
|
||||
displayName: item.post.author.displayName!,
|
||||
}}
|
||||
indexedAt={item.post.indexedAt}
|
||||
text={item.richText?.text || record.text}
|
||||
isAuthor={item.post.author.did === store.me.did}
|
||||
replyCount={item.post.replyCount}
|
||||
repostCount={item.post.repostCount}
|
||||
upvoteCount={item.post.upvoteCount}
|
||||
isReposted={!!item.post.viewer.repost}
|
||||
isUpvoted={!!item.post.viewer.upvote}
|
||||
onPressReply={onPressReply}
|
||||
onPressToggleRepost={onPressToggleRepost}
|
||||
onPressToggleUpvote={onPressToggleUpvote}
|
||||
onCopyPostText={onCopyPostText}
|
||||
onOpenTranslate={onOpenTranslate}
|
||||
onDeletePost={onDeletePost}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</Link>
|
||||
</Link>
|
||||
</PostMutedWrapper>
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -245,14 +243,6 @@ const styles = StyleSheet.create({
|
|||
layoutContent: {
|
||||
flex: 1,
|
||||
},
|
||||
mutedWarning: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
padding: 10,
|
||||
marginTop: 2,
|
||||
marginBottom: 6,
|
||||
borderRadius: 2,
|
||||
},
|
||||
postTextContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
|
|
|
@ -15,6 +15,7 @@ import {UserInfoText} from '../util/UserInfoText'
|
|||
import {PostMeta} from '../util/PostMeta'
|
||||
import {PostCtrls} from '../util/PostCtrls'
|
||||
import {PostEmbeds} from '../util/PostEmbeds'
|
||||
import {PostMutedWrapper} from '../util/PostMuted'
|
||||
import {RichText} from '../util/text/RichText'
|
||||
import * as Toast from '../util/Toast'
|
||||
import {UserAvatar} from '../util/UserAvatar'
|
||||
|
@ -113,6 +114,8 @@ export const FeedItem = observer(function ({
|
|||
item._isThreadChild || (!item.reason && !item._hideParent && item.reply)
|
||||
const isSmallTop = isChild && item._isThreadChild
|
||||
const isNoTop = isChild && !item._isThreadChild
|
||||
const isMuted =
|
||||
item.post.author.viewer?.muted && ignoreMuteFor !== item.post.author.did
|
||||
const outerStyles = [
|
||||
styles.outer,
|
||||
pal.view,
|
||||
|
@ -123,7 +126,7 @@ export const FeedItem = observer(function ({
|
|||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<PostMutedWrapper isMuted={isMuted}>
|
||||
{isChild && !item._isThreadChild && item.replyParent ? (
|
||||
<FeedItem
|
||||
item={item.replyParent}
|
||||
|
@ -160,7 +163,11 @@ export const FeedItem = observer(function ({
|
|||
{color: pal.colors.textLight} as FontAwesomeIconStyle,
|
||||
]}
|
||||
/>
|
||||
<Text type="sm-bold" style={pal.textLight} lineHeight={1.2}>
|
||||
<Text
|
||||
type="sm-bold"
|
||||
style={pal.textLight}
|
||||
lineHeight={1.2}
|
||||
numberOfLines={1}>
|
||||
Reposted by{' '}
|
||||
{item.reasonRepost.by.displayName || item.reasonRepost.by.handle}
|
||||
</Text>
|
||||
|
@ -207,13 +214,7 @@ export const FeedItem = observer(function ({
|
|||
/>
|
||||
</View>
|
||||
)}
|
||||
{item.post.author.viewer?.muted &&
|
||||
ignoreMuteFor !== item.post.author.did ? (
|
||||
<View style={[styles.mutedWarning, pal.btn]}>
|
||||
<FontAwesomeIcon icon={['far', 'eye-slash']} style={s.mr2} />
|
||||
<Text type="sm">This post is by a muted account.</Text>
|
||||
</View>
|
||||
) : item.richText?.text ? (
|
||||
{item.richText?.text ? (
|
||||
<View style={styles.postTextContainer}>
|
||||
<RichText
|
||||
type="post-text"
|
||||
|
@ -222,9 +223,7 @@ export const FeedItem = observer(function ({
|
|||
/>
|
||||
</View>
|
||||
) : undefined}
|
||||
{item.post.embed ? (
|
||||
<PostEmbeds embed={item.post.embed} style={styles.embed} />
|
||||
) : null}
|
||||
<PostEmbeds embed={item.post.embed} style={styles.embed} />
|
||||
<PostCtrls
|
||||
style={styles.ctrls}
|
||||
itemUri={itemUri}
|
||||
|
@ -280,7 +279,7 @@ export const FeedItem = observer(function ({
|
|||
</Text>
|
||||
</Link>
|
||||
) : undefined}
|
||||
</>
|
||||
</PostMutedWrapper>
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -319,6 +318,7 @@ const styles = StyleSheet.create({
|
|||
includeReason: {
|
||||
flexDirection: 'row',
|
||||
paddingLeft: 50,
|
||||
paddingRight: 20,
|
||||
marginTop: 2,
|
||||
marginBottom: 2,
|
||||
},
|
||||
|
@ -336,14 +336,6 @@ const styles = StyleSheet.create({
|
|||
layoutContent: {
|
||||
flex: 1,
|
||||
},
|
||||
mutedWarning: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
padding: 10,
|
||||
marginTop: 2,
|
||||
marginBottom: 6,
|
||||
borderRadius: 2,
|
||||
},
|
||||
postTextContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
|
|
50
src/view/com/util/PostMuted.tsx
Normal file
50
src/view/com/util/PostMuted.tsx
Normal file
|
@ -0,0 +1,50 @@
|
|||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {Text} from './text/Text'
|
||||
|
||||
export function PostMutedWrapper({
|
||||
isMuted,
|
||||
children,
|
||||
}: React.PropsWithChildren<{isMuted: boolean}>) {
|
||||
const pal = usePalette('default')
|
||||
const [override, setOverride] = React.useState(false)
|
||||
if (!isMuted || override) {
|
||||
return <>{children}</>
|
||||
}
|
||||
return (
|
||||
<View style={[styles.container, pal.view, pal.border]}>
|
||||
<FontAwesomeIcon
|
||||
icon={['far', 'eye-slash']}
|
||||
style={[styles.icon, pal.text]}
|
||||
/>
|
||||
<Text type="md" style={pal.textLight}>
|
||||
Post from an account you muted.
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.showBtn}
|
||||
onPress={() => setOverride(true)}>
|
||||
<Text type="md" style={pal.link}>
|
||||
Show post
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 14,
|
||||
paddingHorizontal: 18,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
icon: {
|
||||
marginRight: 10,
|
||||
},
|
||||
showBtn: {
|
||||
marginLeft: 'auto',
|
||||
},
|
||||
})
|
|
@ -1,11 +1,81 @@
|
|||
import Toast from 'react-native-root-toast'
|
||||
import RootSiblings from 'react-native-root-siblings'
|
||||
import React from 'react'
|
||||
import {Animated, StyleSheet, View} from 'react-native'
|
||||
import {Text} from './text/Text'
|
||||
import {colors} from 'lib/styles'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
|
||||
|
||||
const TIMEOUT = 4e3
|
||||
|
||||
export function show(message: string) {
|
||||
Toast.show(message, {
|
||||
duration: Toast.durations.LONG,
|
||||
position: 50,
|
||||
shadow: true,
|
||||
animation: true,
|
||||
hideOnPress: true,
|
||||
})
|
||||
const item = new RootSiblings(<Toast message={message} />)
|
||||
setTimeout(() => {
|
||||
item.destroy()
|
||||
}, TIMEOUT)
|
||||
}
|
||||
|
||||
function Toast({message}: {message: string}) {
|
||||
const theme = useTheme()
|
||||
const pal = usePalette('default')
|
||||
const interp = useAnimatedValue(0)
|
||||
|
||||
React.useEffect(() => {
|
||||
Animated.sequence([
|
||||
Animated.timing(interp, {
|
||||
toValue: 1,
|
||||
duration: 150,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.delay(3700),
|
||||
Animated.timing(interp, {
|
||||
toValue: 0,
|
||||
duration: 150,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
]).start()
|
||||
})
|
||||
|
||||
const opacityStyle = {opacity: interp}
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Animated.View
|
||||
style={[
|
||||
pal.view,
|
||||
pal.border,
|
||||
styles.toast,
|
||||
theme.colorScheme === 'dark' && styles.toastDark,
|
||||
opacityStyle,
|
||||
]}>
|
||||
<Text type="lg-medium" style={pal.text}>
|
||||
{message}
|
||||
</Text>
|
||||
</Animated.View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
position: 'absolute',
|
||||
top: 60,
|
||||
left: 0,
|
||||
right: 0,
|
||||
alignItems: 'center',
|
||||
},
|
||||
toast: {
|
||||
paddingHorizontal: 18,
|
||||
paddingVertical: 10,
|
||||
borderRadius: 24,
|
||||
borderWidth: 1,
|
||||
shadowColor: '#000',
|
||||
shadowOpacity: 0.1,
|
||||
shadowOffset: {width: 0, height: 4},
|
||||
marginHorizontal: 6,
|
||||
},
|
||||
toastDark: {
|
||||
backgroundColor: colors.gray6,
|
||||
shadowOpacity: 0.5,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -58,15 +58,15 @@ export function UserInfoText({
|
|||
let inner
|
||||
if (didFail) {
|
||||
inner = (
|
||||
<Text type={type} style={style}>
|
||||
<Text type={type} style={style} numberOfLines={1}>
|
||||
{failed}
|
||||
</Text>
|
||||
)
|
||||
} else if (profile) {
|
||||
inner = (
|
||||
<Text type={type} style={style} lineHeight={1.2}>{`${prefix || ''}${
|
||||
profile[attr] || profile.handle
|
||||
}`}</Text>
|
||||
<Text type={type} style={style} lineHeight={1.2} numberOfLines={1}>{`${
|
||||
prefix || ''
|
||||
}${profile[attr] || profile.handle}`}</Text>
|
||||
)
|
||||
} else {
|
||||
inner = (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue