1
0
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:
Zhiyuan Zheng
2020-12-26 23:27:53 +01:00
parent da79674548
commit bd5601f8f9
11 changed files with 132 additions and 142 deletions

View File

@ -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>
) )
} }

View File

@ -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>
) )
} }

View File

@ -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} />
) )
}) })
}} }}

View File

@ -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,

View File

@ -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()}
/>
)
})} })}
/> />

View File

@ -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)}
/> />
) )

View File

@ -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>
) )
} }

View File

@ -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()

View File

@ -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(
{ {

View File

@ -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

View File

@ -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