mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Rewrite header buttons
This commit is contained in:
@ -1,52 +1,51 @@
|
|||||||
import { Feather } from '@expo/vector-icons'
|
import React, { useMemo } from 'react'
|
||||||
import React from 'react'
|
|
||||||
import { Pressable, StyleSheet, Text } from 'react-native'
|
import { Pressable, StyleSheet, Text } from 'react-native'
|
||||||
|
import { Feather } from '@expo/vector-icons'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
type?: 'icon' | 'text'
|
||||||
|
content?: string
|
||||||
|
|
||||||
type PropsBase = {
|
|
||||||
onPress: () => void
|
onPress: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PropsText extends PropsBase {
|
const HeaderLeft: React.FC<Props> = ({ type = 'icon', content, onPress }) => {
|
||||||
text: string
|
|
||||||
icon?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PropsIcon extends PropsBase {
|
|
||||||
text?: string
|
|
||||||
icon: any
|
|
||||||
}
|
|
||||||
|
|
||||||
const HeaderLeft: React.FC<PropsText | PropsIcon> = ({
|
|
||||||
onPress,
|
|
||||||
text,
|
|
||||||
icon
|
|
||||||
}) => {
|
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
|
const children = useMemo(() => {
|
||||||
|
switch (type) {
|
||||||
|
case 'icon':
|
||||||
|
return (
|
||||||
|
<Feather
|
||||||
|
name={content || ('chevron-left' as any)}
|
||||||
|
color={theme.primary}
|
||||||
|
size={StyleConstants.Spacing.M * 1.25}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case 'text':
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
style={[styles.text, { color: theme.primary }]}
|
||||||
|
children={content}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [theme])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
children={children}
|
||||||
style={[
|
style={[
|
||||||
styles.base,
|
styles.base,
|
||||||
{
|
{
|
||||||
backgroundColor: theme.backgroundGradientStart,
|
backgroundColor: theme.backgroundGradientStart,
|
||||||
...(icon && { height: 44, width: 44, marginLeft: -9 })
|
...(type === 'icon' && { height: 44, width: 44, marginLeft: -9 })
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
/>
|
||||||
{text ? (
|
|
||||||
<Text style={[styles.text, { color: theme.primary }]}>{text}</Text>
|
|
||||||
) : (
|
|
||||||
<Feather
|
|
||||||
name={icon || 'chevron-left'}
|
|
||||||
color={theme.primary}
|
|
||||||
size={StyleConstants.Spacing.L}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Pressable>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,62 +1,86 @@
|
|||||||
|
import React, { useMemo } from 'react'
|
||||||
|
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
||||||
|
import { Chase } from 'react-native-animated-spinkit'
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
import React from 'react'
|
|
||||||
import { Pressable, StyleSheet, Text } from 'react-native'
|
|
||||||
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
|
||||||
type PropsBase = {
|
export interface Props {
|
||||||
|
type?: 'icon' | 'text'
|
||||||
|
content?: string
|
||||||
|
|
||||||
|
loading?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
|
|
||||||
onPress: () => void
|
onPress: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PropsText extends PropsBase {
|
const HeaderRight: React.FC<Props> = ({
|
||||||
text: string
|
type = 'icon',
|
||||||
icon?: any
|
content,
|
||||||
}
|
loading,
|
||||||
|
|
||||||
export interface PropsIcon extends PropsBase {
|
|
||||||
text?: string
|
|
||||||
icon: any
|
|
||||||
}
|
|
||||||
|
|
||||||
const HeaderRight: React.FC<PropsText | PropsIcon> = ({
|
|
||||||
disabled,
|
disabled,
|
||||||
onPress,
|
onPress
|
||||||
text,
|
|
||||||
icon
|
|
||||||
}) => {
|
}) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
|
const loadingSpinkit = useMemo(
|
||||||
|
() => (
|
||||||
|
<View style={{ position: 'absolute' }}>
|
||||||
|
<Chase
|
||||||
|
size={StyleConstants.Font.Size.M * 1.25}
|
||||||
|
color={theme.secondary}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
[theme]
|
||||||
|
)
|
||||||
|
|
||||||
|
const children = useMemo(() => {
|
||||||
|
switch (type) {
|
||||||
|
case 'icon':
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Feather
|
||||||
|
name={content as any}
|
||||||
|
color={disabled ? theme.secondary : theme.primary}
|
||||||
|
size={StyleConstants.Spacing.M * 1.25}
|
||||||
|
style={{ opacity: loading ? 0 : 1 }}
|
||||||
|
/>
|
||||||
|
{loading && loadingSpinkit}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
case 'text':
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.text,
|
||||||
|
{
|
||||||
|
color: disabled ? theme.secondary : theme.primary,
|
||||||
|
opacity: loading ? 0 : 1
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
children={content}
|
||||||
|
/>
|
||||||
|
{loading && loadingSpinkit}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [theme, loading, disabled])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
{...(!disabled && { onPress })}
|
{...(!disabled && !loading && { onPress })}
|
||||||
|
children={children}
|
||||||
style={[
|
style={[
|
||||||
styles.base,
|
styles.base,
|
||||||
{
|
{
|
||||||
backgroundColor: theme.backgroundGradientStart,
|
backgroundColor: theme.backgroundGradientStart,
|
||||||
...(icon && { height: 44, width: 44, marginRight: -9 })
|
...(type === 'icon' && { height: 44, width: 44, marginRight: -9 })
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
/>
|
||||||
{text && (
|
|
||||||
<Text
|
|
||||||
style={[
|
|
||||||
styles.text,
|
|
||||||
{ color: disabled ? theme.secondary : theme.primary }
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{text}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{icon && (
|
|
||||||
<Feather
|
|
||||||
name={icon}
|
|
||||||
color={disabled ? theme.secondary : theme.primary}
|
|
||||||
size={StyleConstants.Spacing.L}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Pressable>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ const Timelines: React.FC<Props> = ({ name, content }) => {
|
|||||||
</View>
|
</View>
|
||||||
),
|
),
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<HeaderRight icon='search' onPress={onPressSearch} />
|
<HeaderRight content='search' onPress={onPressSearch} />
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback, useMemo } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { ActionSheetIOS, Pressable, StyleSheet, Text, View } from 'react-native'
|
import { ActionSheetIOS, Pressable, StyleSheet, Text, View } from 'react-native'
|
||||||
import { InfiniteData, useMutation, useQueryClient } from 'react-query'
|
import { useMutation, useQueryClient } from 'react-query'
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
|
||||||
import client from '@api/client'
|
import client from '@api/client'
|
||||||
@ -11,8 +11,6 @@ import { useNavigation } from '@react-navigation/native'
|
|||||||
import getCurrentTab from '@utils/getCurrentTab'
|
import getCurrentTab from '@utils/getCurrentTab'
|
||||||
import { findIndex } from 'lodash'
|
import { findIndex } from 'lodash'
|
||||||
import { TimelineData } from '../../Timeline'
|
import { TimelineData } from '../../Timeline'
|
||||||
import { useSelector } from 'react-redux'
|
|
||||||
import { getLocalAccountId } from '@root/utils/slices/instancesSlice'
|
|
||||||
|
|
||||||
const fireMutation = async ({
|
const fireMutation = async ({
|
||||||
id,
|
id,
|
||||||
|
@ -34,12 +34,7 @@ const ScreenMe: React.FC = () => {
|
|||||||
component={ScreenMeConversations}
|
component={ScreenMeConversations}
|
||||||
options={({ navigation }: any) => ({
|
options={({ navigation }: any) => ({
|
||||||
headerTitle: t('meConversations:heading'),
|
headerTitle: t('meConversations:heading'),
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft
|
|
||||||
icon='chevron-left'
|
|
||||||
onPress={() => navigation.goBack()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@ -47,12 +42,7 @@ const ScreenMe: React.FC = () => {
|
|||||||
component={ScreenMeBookmarks}
|
component={ScreenMeBookmarks}
|
||||||
options={({ navigation }: any) => ({
|
options={({ navigation }: any) => ({
|
||||||
headerTitle: t('meBookmarks:heading'),
|
headerTitle: t('meBookmarks:heading'),
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft
|
|
||||||
icon='chevron-left'
|
|
||||||
onPress={() => navigation.goBack()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@ -60,12 +50,7 @@ const ScreenMe: React.FC = () => {
|
|||||||
component={ScreenMeFavourites}
|
component={ScreenMeFavourites}
|
||||||
options={({ navigation }: any) => ({
|
options={({ navigation }: any) => ({
|
||||||
headerTitle: t('meFavourites:heading'),
|
headerTitle: t('meFavourites:heading'),
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft
|
|
||||||
icon='chevron-left'
|
|
||||||
onPress={() => navigation.goBack()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@ -73,12 +58,7 @@ const ScreenMe: React.FC = () => {
|
|||||||
component={ScreenMeLists}
|
component={ScreenMeLists}
|
||||||
options={({ navigation }: any) => ({
|
options={({ navigation }: any) => ({
|
||||||
headerTitle: t('meLists:heading'),
|
headerTitle: t('meLists:heading'),
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft
|
|
||||||
icon='chevron-left'
|
|
||||||
onPress={() => navigation.goBack()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@ -86,12 +66,7 @@ const ScreenMe: React.FC = () => {
|
|||||||
component={ScreenMeListsList}
|
component={ScreenMeListsList}
|
||||||
options={({ route, navigation }: any) => ({
|
options={({ route, navigation }: any) => ({
|
||||||
headerTitle: t('meListsList:heading', { list: route.params.title }),
|
headerTitle: t('meListsList:heading', { list: route.params.title }),
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft
|
|
||||||
icon='chevron-left'
|
|
||||||
onPress={() => navigation.goBack()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@ -99,12 +74,7 @@ const ScreenMe: React.FC = () => {
|
|||||||
component={ScreenMeSettings}
|
component={ScreenMeSettings}
|
||||||
options={({ navigation }: any) => ({
|
options={({ navigation }: any) => ({
|
||||||
headerTitle: t('meSettings:heading'),
|
headerTitle: t('meSettings:heading'),
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft
|
|
||||||
icon='chevron-left'
|
|
||||||
onPress={() => navigation.goBack()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ const ScreenSharedAccount: React.FC<Props> = ({
|
|||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<HeaderRight
|
<HeaderRight
|
||||||
icon='more-horizontal'
|
content='more-horizontal'
|
||||||
onPress={() => setBottomSheetVisible(true)}
|
onPress={() => setBottomSheetVisible(true)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -540,6 +540,8 @@ const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
|
|||||||
const headerLeft = useCallback(
|
const headerLeft = useCallback(
|
||||||
() => (
|
() => (
|
||||||
<HeaderLeft
|
<HeaderLeft
|
||||||
|
type='text'
|
||||||
|
content='退出编辑'
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
Alert.alert('确认取消编辑?', '', [
|
Alert.alert('确认取消编辑?', '', [
|
||||||
{ text: '继续编辑', style: 'cancel' },
|
{ text: '继续编辑', style: 'cancel' },
|
||||||
@ -550,7 +552,6 @@ const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
text='退出编辑'
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[]
|
[]
|
||||||
@ -571,16 +572,15 @@ const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
|
|||||||
[totalTextCount]
|
[totalTextCount]
|
||||||
)
|
)
|
||||||
const headerRight = useCallback(
|
const headerRight = useCallback(
|
||||||
() =>
|
() => (
|
||||||
isSubmitting ? (
|
<HeaderRight
|
||||||
<ActivityIndicator />
|
type='text'
|
||||||
) : (
|
content={params?.type ? postButtonText[params.type] : '发嘟嘟'}
|
||||||
<HeaderRight
|
onPress={async () => tootPost()}
|
||||||
onPress={async () => tootPost()}
|
loading={isSubmitting}
|
||||||
text={params?.type ? postButtonText[params.type] : '发嘟嘟'}
|
disabled={rawCount < 1 || totalTextCount > 500}
|
||||||
disabled={rawCount < 1 || totalTextCount > 500}
|
/>
|
||||||
/>
|
),
|
||||||
),
|
|
||||||
[isSubmitting, rawCount, totalTextCount]
|
[isSubmitting, rawCount, totalTextCount]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -605,7 +605,6 @@ const Compose: React.FC<Props> = ({ route: { params }, navigation }) => {
|
|||||||
</Stack.Screen>
|
</Stack.Screen>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
<Toast ref={(ref: any) => Toast.setRef(ref)} config={toastConfig} />
|
|
||||||
</KeyboardAvoidingView>
|
</KeyboardAvoidingView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -230,11 +230,16 @@ const ComposeEditAttachment: React.FC<Props> = ({
|
|||||||
options={{
|
options={{
|
||||||
title: '编辑附件',
|
title: '编辑附件',
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<HeaderLeft text='取消' onPress={() => navigation.goBack()} />
|
<HeaderLeft
|
||||||
|
type='text'
|
||||||
|
content='取消'
|
||||||
|
onPress={() => navigation.goBack()}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<HeaderRight
|
<HeaderRight
|
||||||
text='应用'
|
type='text'
|
||||||
|
content='应用'
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ const ScreenSharedImagesViewer: React.FC<Props> = ({
|
|||||||
contentStyle: { backgroundColor: 'black' },
|
contentStyle: { backgroundColor: 'black' },
|
||||||
headerStyle: { backgroundColor: 'black' },
|
headerStyle: { backgroundColor: 'black' },
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<HeaderLeft icon='x' onPress={() => navigation.goBack()} />
|
<HeaderLeft content='x' onPress={() => navigation.goBack()} />
|
||||||
),
|
),
|
||||||
headerCenter: () => (
|
headerCenter: () => (
|
||||||
<Text style={styles.headerCenter}>
|
<Text style={styles.headerCenter}>
|
||||||
@ -102,7 +102,7 @@ const ScreenSharedImagesViewer: React.FC<Props> = ({
|
|||||||
),
|
),
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<HeaderRight
|
<HeaderRight
|
||||||
icon='share'
|
content='share'
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
ActionSheetIOS.showShareActionSheetWithOptions(
|
ActionSheetIOS.showShareActionSheetWithOptions(
|
||||||
{
|
{
|
||||||
|
@ -242,7 +242,11 @@ const ScreenSharedSearch: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.searchCancel}>
|
<View style={styles.searchCancel}>
|
||||||
<HeaderRight text='取消' onPress={() => navigation.goBack()} />
|
<HeaderRight
|
||||||
|
type='text'
|
||||||
|
content='取消'
|
||||||
|
onPress={() => navigation.goBack()}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<SectionList
|
<SectionList
|
||||||
|
@ -26,12 +26,7 @@ const sharedScreens = (Stack: any) => {
|
|||||||
backgroundColor: `rgba(255, 255, 255, 0)`
|
backgroundColor: `rgba(255, 255, 255, 0)`
|
||||||
},
|
},
|
||||||
headerCenter: () => null,
|
headerCenter: () => null,
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft
|
|
||||||
icon='chevron-left'
|
|
||||||
onPress={() => navigation.goBack()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
@ -41,9 +36,7 @@ const sharedScreens = (Stack: any) => {
|
|||||||
component={ScreenSharedHashtag}
|
component={ScreenSharedHashtag}
|
||||||
options={({ route, navigation }: any) => ({
|
options={({ route, navigation }: any) => ({
|
||||||
title: `#${decodeURIComponent(route.params.hashtag)}`,
|
title: `#${decodeURIComponent(route.params.hashtag)}`,
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft icon='chevron-left' onPress={() => navigation.goBack()} />
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
/>,
|
/>,
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@ -52,9 +45,7 @@ const sharedScreens = (Stack: any) => {
|
|||||||
component={ScreenSharedToot}
|
component={ScreenSharedToot}
|
||||||
options={({ navigation }: any) => ({
|
options={({ navigation }: any) => ({
|
||||||
title: t('sharedToot:heading'),
|
title: t('sharedToot:heading'),
|
||||||
headerLeft: () => (
|
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
|
||||||
<HeaderLeft icon='chevron-left' onPress={() => navigation.goBack()} />
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
/>,
|
/>,
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
|
Reference in New Issue
Block a user