1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00

Some basic styling

This commit is contained in:
Zhiyuan Zheng
2020-11-23 00:07:32 +01:00
parent 6d6b808af2
commit fba1d0d531
40 changed files with 1381 additions and 270 deletions

View File

@ -2,6 +2,7 @@ import React from 'react'
import { Pressable, StyleSheet, Text, View } from 'react-native'
import { useNavigation } from '@react-navigation/native'
import { Feather } from '@expo/vector-icons'
import { useTheme } from 'src/utils/styles/ThemeManager'
export interface Props {
icon?: string
@ -11,6 +12,8 @@ export interface Props {
}
const Core: React.FC<Props> = ({ icon, title, navigateTo }) => {
const { theme } = useTheme()
return (
<View style={styles.core}>
{icon && <Feather name={icon} size={24} style={styles.iconLeading} />}
@ -19,7 +22,7 @@ const Core: React.FC<Props> = ({ icon, title, navigateTo }) => {
<Feather
name='chevron-right'
size={24}
color='lightgray'
color={theme.secondary}
style={styles.iconNavigation}
/>
)}

View File

@ -1,18 +1,22 @@
import React from 'react'
import { StyleSheet, Text } from 'react-native'
import { Text } from 'react-native'
import HTMLView, { HTMLViewNode } from 'react-native-htmlview'
import { useNavigation } from '@react-navigation/native'
import Emojis from 'src/components/Status/Emojis'
import Emojis from 'src/components/Timelines/Timeline/Shared/Emojis'
import { useTheme } from 'src/utils/styles/ThemeManager'
// Prevent going to the same hashtag multiple times
const renderNode = ({
theme,
node,
index,
navigation,
mentions,
showFullLink
}: {
node: HTMLViewNode
theme: any
node: any
index: number
navigation: any
mentions?: Mastodon.Mention[]
@ -26,10 +30,10 @@ const renderNode = ({
return (
<Text
key={index}
style={styles.a}
style={{ color: theme.link }}
onPress={() => {
const tag = href.split(new RegExp(/\/tag\/(.*)|\/tags\/(.*)/))
navigation.push('Hashtag', {
navigation.push('Screen-Shared-Hashtag', {
hashtag: tag[1] || tag[2]
})
}}
@ -42,13 +46,13 @@ const renderNode = ({
return (
<Text
key={index}
style={styles.a}
style={{ color: theme.link }}
onPress={() => {
const username = href.split(new RegExp(/@(.*)/))
const usernameIndex = mentions.findIndex(
m => m.username === username[1]
)
navigation.push('Account', {
navigation.push('Screen-Shared-Account', {
id: mentions[usernameIndex].id
})
}}
@ -63,9 +67,9 @@ const renderNode = ({
return (
<Text
key={index}
style={styles.a}
style={{ color: theme.link }}
onPress={() => {
navigation.navigate('Webview', {
navigation.navigate('Screen-Shared-Webview', {
uri: href,
domain: domain[1]
})
@ -80,8 +84,8 @@ const renderNode = ({
export interface Props {
content: string
size: number
emojis?: Mastodon.Emoji[]
emojiSize?: number
mentions?: Mastodon.Mention[]
showFullLink?: boolean
linesTruncated?: number
@ -89,29 +93,24 @@ export interface Props {
const ParseContent: React.FC<Props> = ({
content,
size,
emojis,
emojiSize = 14,
mentions,
showFullLink = false,
linesTruncated = 10
}) => {
const navigation = useNavigation()
const { theme } = useTheme()
return (
<HTMLView
value={content}
stylesheet={HTMLstyles}
paragraphBreak=''
renderNode={(node, index) =>
renderNode({ node, index, navigation, mentions, showFullLink })
renderNode({ theme, node, index, navigation, mentions, showFullLink })
}
TextComponent={({ children }) =>
emojis && children ? (
<Emojis
content={children.toString()}
emojis={emojis}
dimension={emojiSize}
/>
<Emojis content={children.toString()} emojis={emojis} size={size} />
) : (
<Text>{children}</Text>
)
@ -123,16 +122,4 @@ const ParseContent: React.FC<Props> = ({
)
}
const styles = StyleSheet.create({
a: {
color: 'blue'
}
})
const HTMLstyles = StyleSheet.create({
p: {
marginBottom: 12
}
})
export default ParseContent

View File

@ -0,0 +1,121 @@
import React, { useEffect, useRef, useState } from 'react'
import { Dimensions, FlatList, Text, View } from 'react-native'
import SegmentedControl from '@react-native-community/segmented-control'
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
import { useSelector } from 'react-redux'
import { Feather } from '@expo/vector-icons'
import Timeline from './Timelines/Timeline'
import sharedScreens from 'src/screens/Shared/sharedScreens'
import { InstancesState } from 'src/utils/slices/instancesSlice'
import { RootState } from 'src/store'
import { useTheme } from 'src/utils/styles/ThemeManager'
const Stack = createNativeStackNavigator()
const Page = ({
item: { page },
localRegistered
}: {
item: { page: App.Pages }
localRegistered: InstancesState['local']['url'] | undefined
}) => {
return (
<View style={{ width: Dimensions.get('window').width }}>
{localRegistered || page === 'RemotePublic' ? (
<Timeline page={page} />
) : (
<Text></Text>
)}
</View>
)
}
export interface Props {
name: string
content: { title: string; page: App.Pages }[]
}
const Timelines: React.FC<Props> = ({ name, content }) => {
const { theme } = useTheme()
const localRegistered = useSelector(
(state: RootState) => state.instances.local.url
)
const [segment, setSegment] = useState(0)
const [renderHeader, setRenderHeader] = useState(false)
const [segmentManuallyTriggered, setSegmentManuallyTriggered] = useState(
false
)
useEffect(() => {
const nbr = setTimeout(() => setRenderHeader(true), 50)
return
}, [])
const horizontalPaging = useRef<FlatList>(null!)
return (
<Stack.Navigator>
<Stack.Screen
name={name}
options={{
headerRight: () =>
renderHeader ? (
<Feather name='search' size={24} color={theme.secondary} />
) : null,
headerCenter: () =>
renderHeader ? (
<SegmentedControl
values={[content[0].title, content[1].title]}
selectedIndex={segment}
onChange={({ nativeEvent }) => {
setSegmentManuallyTriggered(true)
setSegment(nativeEvent.selectedSegmentIndex)
horizontalPaging.current.scrollToIndex({
index: nativeEvent.selectedSegmentIndex
})
}}
style={{ width: 150, height: 30 }}
/>
) : null
}}
>
{() => (
<FlatList
style={{ width: Dimensions.get('window').width, height: '100%' }}
data={content}
extraData={localRegistered}
keyExtractor={({ page }) => page}
renderItem={({ item, index }) => (
<Page key={index} item={item} localRegistered={localRegistered} />
)}
ref={horizontalPaging}
bounces={false}
getItemLayout={(data, index) => ({
length: Dimensions.get('window').width,
offset: Dimensions.get('window').width * index,
index
})}
horizontal
onMomentumScrollEnd={() => setSegmentManuallyTriggered(false)}
onScroll={({ nativeEvent }) =>
!segmentManuallyTriggered &&
setSegment(
nativeEvent.contentOffset.x <=
Dimensions.get('window').width / 2
? 0
: 1
)
}
pagingEnabled
showsHorizontalScrollIndicator={false}
/>
)}
</Stack.Screen>
{sharedScreens(Stack)}
</Stack.Navigator>
)
}
export default Timelines

View File

@ -0,0 +1,119 @@
import React from 'react'
import { ActivityIndicator, AppState, FlatList, Text, View } from 'react-native'
import { setFocusHandler, useInfiniteQuery } from 'react-query'
import TimelineNotifications from 'src/components/Timelines/Timeline/Notifications'
import TimelineDefault from 'src/components/Timelines/Timeline/Default'
import TimelineConversation from 'src/components/Timelines/Timeline/Conversation'
import { timelineFetch } from 'src/utils/fetches/timelineFetch'
import TimelineSeparator from './Timeline/Separator'
// Opening nesting hashtag pages
export interface Props {
page: App.Pages
hashtag?: string
list?: string
toot?: string
account?: string
disableRefresh?: boolean
scrollEnabled?: boolean
}
const Timeline: React.FC<Props> = ({
page,
hashtag,
list,
toot,
account,
disableRefresh = false,
scrollEnabled = true
}) => {
setFocusHandler(handleFocus => {
const handleAppStateChange = (appState: string) => {
if (appState === 'active') {
handleFocus()
}
}
AppState.addEventListener('change', handleAppStateChange)
return () => AppState.removeEventListener('change', handleAppStateChange)
})
const queryKey: App.QueryKey = [page, { page, hashtag, list, toot, account }]
const {
isLoading,
isFetchingMore,
isError,
isSuccess,
data,
fetchMore
} = useInfiniteQuery(queryKey, timelineFetch)
const flattenData = data ? data.flatMap(d => [...d?.toots]) : []
// const flattenPointer = data ? data.flatMap(d => [d?.pointer]) : []
let content
if (!isSuccess) {
content = <ActivityIndicator />
} else if (isError) {
content = <Text>Error message</Text>
} else {
content = (
<>
<FlatList
style={{ minHeight: '100%' }}
scrollEnabled={scrollEnabled} // For timeline in Account view
data={flattenData}
keyExtractor={({ id }) => id}
renderItem={({ item, index, separators }) => {
switch (page) {
case 'Conversations':
return <TimelineConversation key={index} item={item} />
case 'Notifications':
return (
<TimelineNotifications
key={index}
notification={item}
queryKey={queryKey}
/>
)
default:
return (
<TimelineDefault
key={index}
item={item}
queryKey={queryKey}
/>
)
}
}}
ItemSeparatorComponent={() => <TimelineSeparator />}
// require getItemLayout
// {...(flattenPointer[0] && { initialScrollIndex: flattenPointer[0] })}
{...(!disableRefresh && {
onRefresh: () =>
fetchMore(
{
direction: 'prev',
id: flattenData[0].id
},
{ previous: true }
),
refreshing: isLoading,
onEndReached: () => {
fetchMore({
direction: 'next',
id: flattenData[flattenData.length - 1].id
})
},
onEndReachedThreshold: 0.5
})}
/>
{isFetchingMore && <ActivityIndicator />}
</>
)
}
return <View>{content}</View>
}
export default Timeline

View File

@ -2,9 +2,11 @@ import React, { useMemo } from 'react'
import { Pressable, StyleSheet, View } from 'react-native'
import { useNavigation } from '@react-navigation/native'
import Avatar from './Status/Avatar'
import HeaderConversation from './Status/HeaderConversation'
import Content from './Status/Content'
import Avatar from './Shared/Avatar'
import HeaderConversation from './Shared/HeaderConversation'
import Content from './Shared/Content'
import constants from 'src/utils/styles/constants'
export interface Props {
item: Mastodon.Conversation
@ -58,7 +60,7 @@ const styles = StyleSheet.create({
statusView: {
flex: 1,
flexDirection: 'column',
padding: 12
padding: constants.GLOBAL_PAGE_PADDING
},
status: {
flex: 1,

View File

@ -2,20 +2,23 @@ import React, { useMemo } from 'react'
import { Dimensions, Pressable, StyleSheet, View } from 'react-native'
import { useNavigation } from '@react-navigation/native'
import Actioned from './Status/Actioned'
import Avatar from './Status/Avatar'
import Header from './Status/Header'
import Content from './Status/Content'
import Poll from './Status/Poll'
import Attachment from './Status/Attachment'
import Card from './Status/Card'
import ActionsStatus from './Status/ActionsStatus'
import Actioned from './Shared/Actioned'
import Avatar from './Shared/Avatar'
import HeaderDefault from './Shared/HeaderDefault'
import Content from './Shared/Content'
import Poll from './Shared/Poll'
import Attachment from './Shared/Attachment'
import Card from './Shared/Card'
import ActionsStatus from './Shared/ActionsStatus'
import constants from 'src/utils/styles/constants'
export interface Props {
item: Mastodon.Status
queryKey: App.QueryKey
}
// When the poll is long
const TimelineDefault: React.FC<Props> = ({ item, queryKey }) => {
const navigation = useNavigation()
@ -37,7 +40,7 @@ const TimelineDefault: React.FC<Props> = ({ item, queryKey }) => {
id={actualStatus.account.id}
/>
<View style={styles.details}>
<Header
<HeaderDefault
queryKey={queryKey}
accountId={actualStatus.account.id}
domain={actualStatus.uri.split(new RegExp(/\/\/(.*?)\//))[1]}
@ -75,7 +78,12 @@ const TimelineDefault: React.FC<Props> = ({ item, queryKey }) => {
<Attachment
media_attachments={actualStatus.media_attachments}
sensitive={actualStatus.sensitive}
width={Dimensions.get('window').width - 24 - 50 - 8}
width={
Dimensions.get('window').width -
constants.SPACING_M * 2 -
50 -
8
}
/>
)}
{actualStatus.card && <Card card={actualStatus.card} />}
@ -94,7 +102,7 @@ const styles = StyleSheet.create({
statusView: {
flex: 1,
flexDirection: 'column',
padding: 12
padding: constants.GLOBAL_PAGE_PADDING
},
status: {
flex: 1,

View File

@ -2,21 +2,23 @@ import React, { useMemo } from 'react'
import { Dimensions, Pressable, StyleSheet, View } from 'react-native'
import { useNavigation } from '@react-navigation/native'
import Actioned from './Status/Actioned'
import Avatar from './Status/Avatar'
import Header from './Status/Header'
import Content from './Status/Content'
import Poll from './Status/Poll'
import Attachment from './Status/Attachment'
import Card from './Status/Card'
import ActionsStatus from './Status/ActionsStatus'
import Actioned from './Shared/Actioned'
import Avatar from './Shared/Avatar'
import HeaderDefault from './Shared/HeaderDefault'
import Content from './Shared/Content'
import Poll from './Shared/Poll'
import Attachment from './Shared/Attachment'
import Card from './Shared/Card'
import ActionsStatus from './Shared/ActionsStatus'
import constants from 'src/utils/styles/constants'
export interface Props {
notification: Mastodon.Notification
queryKey: App.QueryKey
}
const TootNotification: React.FC<Props> = ({ notification, queryKey }) => {
const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
const navigation = useNavigation()
const actualAccount = notification.status
? notification.status.account
@ -37,7 +39,7 @@ const TootNotification: React.FC<Props> = ({ notification, queryKey }) => {
<View style={styles.notification}>
<Avatar uri={actualAccount.avatar} id={actualAccount.id} />
<View style={styles.details}>
<Header
<HeaderDefault
name={actualAccount.display_name || actualAccount.username}
emojis={actualAccount.emojis}
account={actualAccount.acct}
@ -96,7 +98,7 @@ const styles = StyleSheet.create({
notificationView: {
flex: 1,
flexDirection: 'column',
padding: 12
padding: constants.GLOBAL_PAGE_PADDING
},
notification: {
flex: 1,
@ -108,4 +110,4 @@ const styles = StyleSheet.create({
}
})
export default TootNotification
export default TimelineNotifications

View File

@ -0,0 +1,20 @@
import React from 'react'
import { StyleSheet, View } from 'react-native'
import constants from 'src/utils/styles/constants'
import { useTheme } from 'src/utils/styles/ThemeManager'
const TimelineSeparator = () => {
const { theme } = useTheme()
return <View style={[styles.base, { borderTopColor: theme.separator }]} />
}
const styles = StyleSheet.create({
base: {
borderTopWidth: 1,
marginLeft: constants.SPACING_M + constants.AVATAR_S + constants.SPACING_S
}
})
export default TimelineSeparator

View File

@ -3,6 +3,9 @@ import { StyleSheet, Text, View } from 'react-native'
import { Feather } from '@expo/vector-icons'
import Emojis from './Emojis'
import { useTheme } from 'src/utils/styles/ThemeManager'
import constants from 'src/utils/styles/constants'
export interface Props {
action: 'favourite' | 'follow' | 'mention' | 'poll' | 'reblog'
@ -17,18 +20,31 @@ const Actioned: React.FC<Props> = ({
emojis,
notification = false
}) => {
const { theme } = useTheme()
const iconColor = theme.primary
let icon
let content
switch (action) {
case 'favourite':
icon = (
<Feather name='heart' size={12} color='black' style={styles.icon} />
<Feather
name='heart'
size={constants.FONT_SIZE_S}
color={iconColor}
style={styles.icon}
/>
)
content = `${name} 喜欢了你的嘟嘟`
break
case 'follow':
icon = (
<Feather name='user-plus' size={12} color='black' style={styles.icon} />
<Feather
name='user-plus'
size={constants.FONT_SIZE_S}
color={iconColor}
style={styles.icon}
/>
)
content = `${name} 开始关注你`
break
@ -36,7 +52,7 @@ const Actioned: React.FC<Props> = ({
icon = (
<Feather
name='bar-chart-2'
size={12}
size={constants.FONT_SIZE_S}
color='black'
style={styles.icon}
/>
@ -45,7 +61,12 @@ const Actioned: React.FC<Props> = ({
break
case 'reblog':
icon = (
<Feather name='repeat' size={12} color='black' style={styles.icon} />
<Feather
name='repeat'
size={constants.FONT_SIZE_S}
color={iconColor}
style={styles.icon}
/>
)
content = `${name} 转嘟了${notification ? '你的嘟嘟' : ''}`
break
@ -57,7 +78,11 @@ const Actioned: React.FC<Props> = ({
{content ? (
<View style={styles.content}>
{emojis ? (
<Emojis content={content} emojis={emojis} dimension={12} />
<Emojis
content={content}
emojis={emojis}
size={constants.FONT_SIZE_S}
/>
) : (
<Text>{content}</Text>
)}
@ -72,11 +97,11 @@ const Actioned: React.FC<Props> = ({
const styles = StyleSheet.create({
actioned: {
flexDirection: 'row',
marginBottom: 8
marginBottom: constants.SPACING_S
},
icon: {
marginLeft: 50 - 12,
marginRight: 8
marginLeft: constants.AVATAR_S - constants.FONT_SIZE_S,
marginRight: constants.SPACING_S
},
content: {
flexDirection: 'row'

View File

@ -14,7 +14,9 @@ import { Feather } from '@expo/vector-icons'
import client from 'src/api/client'
import { getLocalAccountId } from 'src/utils/slices/instancesSlice'
import {store} from 'src/store'
import { store } from 'src/store'
import { useTheme } from 'src/utils/styles/ThemeManager'
import constants from 'src/utils/styles/constants'
const fireMutation = async ({
id,
@ -112,6 +114,11 @@ export interface Props {
}
const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
const { theme } = useTheme()
const iconColor = theme.secondary
const iconColorAction = (state: boolean) =>
state ? theme.primary : theme.secondary
const localAccountId = getLocalAccountId(store.getState())
const [modalVisible, setModalVisible] = useState(false)
@ -153,8 +160,22 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
<>
<View style={styles.actions}>
<Pressable style={styles.action}>
<Feather name='message-circle' color='gray' />
{status.replies_count > 0 && <Text>{status.replies_count}</Text>}
<Feather
name='message-circle'
color={iconColor}
size={constants.FONT_SIZE_M + 2}
/>
{status.replies_count > 0 && (
<Text
style={{
color: theme.secondary,
fontSize: constants.FONT_SIZE_M,
marginLeft: constants.SPACING_XS
}}
>
{status.replies_count}
</Text>
)}
</Pressable>
<Pressable
@ -168,7 +189,11 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
})
}
>
<Feather name='repeat' color={status.reblogged ? 'black' : 'gray'} />
<Feather
name='repeat'
color={iconColorAction(status.reblogged)}
size={constants.FONT_SIZE_M + 2}
/>
</Pressable>
<Pressable
@ -182,7 +207,11 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
})
}
>
<Feather name='heart' color={status.favourited ? 'black' : 'gray'} />
<Feather
name='heart'
color={iconColorAction(status.favourited)}
size={constants.FONT_SIZE_M + 2}
/>
</Pressable>
<Pressable
@ -198,12 +227,17 @@ const ActionsStatus: React.FC<Props> = ({ queryKey, status }) => {
>
<Feather
name='bookmark'
color={status.bookmarked ? 'black' : 'gray'}
color={iconColorAction(status.bookmarked)}
size={constants.FONT_SIZE_M + 2}
/>
</Pressable>
<Pressable style={styles.action} onPress={() => setModalVisible(true)}>
<Feather name='more-horizontal' color='gray' />
<Feather
name='share-2'
color={iconColor}
size={constants.FONT_SIZE_M + 2}
/>
</Pressable>
</View>
@ -319,14 +353,12 @@ const styles = StyleSheet.create({
width: '100%',
flex: 1,
flexDirection: 'row',
marginTop: 8
marginTop: constants.SPACING_M
},
action: {
width: '20%',
flexDirection: 'row',
justifyContent: 'center',
paddingTop: 8,
paddingBottom: 8
justifyContent: 'center'
},
modalBackground: {
width: '100%',

View File

@ -2,6 +2,8 @@ import React from 'react'
import { Image, Pressable, StyleSheet } from 'react-native'
import { useNavigation } from '@react-navigation/native'
import constants from 'src/utils/styles/constants'
export interface Props {
uri: string
id: string
@ -26,13 +28,14 @@ const Avatar: React.FC<Props> = ({ uri, id }) => {
const styles = StyleSheet.create({
avatar: {
width: 50,
height: 50,
marginRight: 8
width: constants.AVATAR_S,
height: constants.AVATAR_S,
marginRight: constants.SPACING_S
},
image: {
width: '100%',
height: '100%'
height: '100%',
borderRadius: 8
}
})

View File

@ -4,6 +4,9 @@ import Collapsible from 'react-native-collapsible'
import ParseContent from 'src/components/ParseContent'
import constants from 'src/utils/styles/constants'
import { useTheme } from 'src/utils/styles/ThemeManager'
export interface Props {
content: string
emojis: Mastodon.Emoji[]
@ -17,6 +20,7 @@ const Content: React.FC<Props> = ({
mentions,
spoiler_text
}) => {
const { theme } = useTheme()
const [spoilerCollapsed, setSpoilerCollapsed] = useState(true)
return (
@ -26,15 +30,18 @@ const Content: React.FC<Props> = ({
<>
<Text>
{spoiler_text}{' '}
<Text onPress={() => setSpoilerCollapsed(!spoilerCollapsed)}>
<Text
onPress={() => setSpoilerCollapsed(!spoilerCollapsed)}
style={{ color: theme.link }}
>
{spoilerCollapsed ? '点击展开' : '点击收起'}
</Text>
</Text>
<Collapsible collapsed={spoilerCollapsed}>
<ParseContent
content={content}
size={constants.FONT_SIZE_M}
emojis={emojis}
emojiSize={14}
mentions={mentions}
/>
</Collapsible>
@ -42,8 +49,8 @@ const Content: React.FC<Props> = ({
) : (
<ParseContent
content={content}
size={constants.FONT_SIZE_M}
emojis={emojis}
emojiSize={14}
mentions={mentions}
/>
))}

View File

@ -1,16 +1,37 @@
import React from 'react'
import { Image, Text } from 'react-native'
import { Image, StyleSheet, Text } from 'react-native'
import { useTheme } from 'src/utils/styles/ThemeManager'
const regexEmoji = new RegExp(/(:[a-z0-9_]+:)/)
export interface Props {
content: string
emojis: Mastodon.Emoji[]
dimension: number
size: number
fontBold?: boolean
}
const Emojis: React.FC<Props> = ({ content, emojis, dimension }) => {
const Emojis: React.FC<Props> = ({
content,
emojis,
size,
fontBold = false
}) => {
const { theme } = useTheme()
const styles = StyleSheet.create({
text: {
fontSize: size,
lineHeight: size + 2,
color: theme.primary,
...(fontBold && { fontWeight: 'bold' })
},
image: {
width: size,
height: size
}
})
const hasEmojis = content.match(regexEmoji)
return hasEmojis ? (
<>
{content.split(regexEmoji).map((str, i) => {
@ -20,20 +41,19 @@ const Emojis: React.FC<Props> = ({ content, emojis, dimension }) => {
return emojiShortcode === `:${emoji.shortcode}:`
})
return emojiIndex === -1 ? (
<Text key={i}>{emojiShortcode}</Text>
<Text key={i} style={styles.text}>
{emojiShortcode}
</Text>
) : (
<Image
key={i}
source={{ uri: emojis[emojiIndex].url }}
style={{ width: dimension, height: dimension }}
style={styles.image}
/>
)
} else {
return (
<Text
key={i}
style={{ fontSize: dimension, lineHeight: dimension + 1 }}
>
<Text key={i} style={styles.text}>
{str}
</Text>
)
@ -41,9 +61,7 @@ const Emojis: React.FC<Props> = ({ content, emojis, dimension }) => {
})}
</>
) : (
<Text style={{ fontSize: dimension, lineHeight: dimension + 1 }}>
{content}
</Text>
<Text style={styles.text}>{content}</Text>
)
}

View File

@ -18,7 +18,7 @@ const HeaderConversation: React.FC<Props> = ({ account, created_at }) => {
<Emojis
content={account.display_name || account.username}
emojis={account.emojis}
dimension={14}
size={14}
/>
) : (
<Text numberOfLines={1}>

View File

@ -8,12 +8,10 @@ import { useMutation, useQueryCache } from 'react-query'
import Emojis from './Emojis'
import relativeTime from 'src/utils/relativeTime'
import client from 'src/api/client'
import { useSelector } from 'react-redux'
import {
getLocalAccountId,
getLocalUrl
} from 'src/utils/slices/instancesSlice'
import {store} from 'src/store'
import { getLocalAccountId, getLocalUrl } from 'src/utils/slices/instancesSlice'
import { store } from 'src/store'
import { useTheme } from 'src/utils/styles/ThemeManager'
import constants from 'src/utils/styles/constants'
const fireMutation = async ({
id,
@ -131,7 +129,7 @@ export interface Props {
application?: Mastodon.Application
}
const Header: React.FC<Props> = ({
const HeaderDefault: React.FC<Props> = ({
queryKey,
accountId,
domain,
@ -141,6 +139,8 @@ const Header: React.FC<Props> = ({
created_at,
application
}) => {
const { theme } = useTheme()
const navigation = useNavigation()
const localAccountId = getLocalAccountId(store.getState())
const localDomain = getLocalUrl(store.getState())
@ -194,26 +194,42 @@ const Header: React.FC<Props> = ({
<View style={styles.nameAndAction}>
<View style={styles.name}>
{emojis ? (
<Emojis content={name} emojis={emojis} dimension={14} />
<Emojis
content={name}
emojis={emojis}
size={constants.FONT_SIZE_M}
fontBold={true}
/>
) : (
<Text numberOfLines={1}>{name}</Text>
<Text numberOfLines={1} style={{ color: theme.primary }}>
{name}
</Text>
)}
<Text
style={[styles.account, { color: theme.secondary }]}
numberOfLines={1}
>
@{account}
</Text>
</View>
{accountId !== localAccountId && domain !== localDomain && (
<Pressable
style={styles.action}
onPress={() => setModalVisible(true)}
>
<Feather name='more-horizontal' color='gray' />
<Feather
name='more-horizontal'
color={theme.secondary}
size={constants.FONT_SIZE_M + 2}
/>
</Pressable>
)}
</View>
<Text style={styles.account} numberOfLines={1}>
@{account}
</Text>
<View style={styles.meta}>
<View>
<Text style={styles.created_at}>{since}</Text>
<Text style={[styles.created_at, { color: theme.secondary }]}>
{since}
</Text>
</View>
{application && application.name !== 'Web' && (
<View>
@ -223,9 +239,9 @@ const Header: React.FC<Props> = ({
uri: application.website
})
}}
style={styles.application}
style={[styles.application, { color: theme.secondary }]}
>
{application.name}
- {application.name}
</Text>
</View>
)}
@ -310,32 +326,29 @@ const styles = StyleSheet.create({
justifyContent: 'space-between'
},
name: {
flexDirection: 'row',
marginRight: 8,
fontWeight: '900'
},
action: {
width: 14,
height: 14,
marginLeft: 8
},
account: {
lineHeight: 14,
flexShrink: 1
},
meta: {
flexBasis: '80%',
flexDirection: 'row'
},
action: {
flexBasis: '20%',
alignItems: 'center'
},
account: {
flexShrink: 1,
marginLeft: constants.SPACING_XS,
lineHeight: constants.FONT_SIZE_M + 2
},
meta: {
flexDirection: 'row',
marginTop: constants.SPACING_XS,
marginBottom: constants.SPACING_S
},
created_at: {
fontSize: 12,
lineHeight: 12,
marginTop: 8,
marginBottom: 8,
marginRight: 8
fontSize: constants.FONT_SIZE_S
},
application: {
fontSize: 12,
lineHeight: 11
fontSize: constants.FONT_SIZE_S,
marginLeft: constants.SPACING_S
},
modalBackground: {
width: '100%',
@ -354,4 +367,4 @@ const styles = StyleSheet.create({
}
})
export default Header
export default HeaderDefault

View File

@ -19,7 +19,7 @@ const Poll: React.FC<Props> = ({ poll }) => {
<Emojis
content={option.title}
emojis={poll.emojis}
dimension={14}
size={14}
/>
</View>
<View