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

Merge branch 'main' into release

This commit is contained in:
xmflsct
2022-12-20 10:51:26 +01:00
10 changed files with 75 additions and 103 deletions

View File

@ -53,26 +53,17 @@ const GracefullyImage = ({
}: Props) => { }: Props) => {
const { reduceMotionEnabled } = useAccessibility() const { reduceMotionEnabled } = useAccessibility()
const { colors } = useTheme() const { colors } = useTheme()
const [originalFailed, setOriginalFailed] = useState(false)
const [imageLoaded, setImageLoaded] = useState(false) const [imageLoaded, setImageLoaded] = useState(false)
const source = originalFailed const source = {
? { uri: uri.remote || undefined } uri: reduceMotionEnabled && uri.static ? uri.static : uri.original
: { }
uri: reduceMotionEnabled && uri.static ? uri.static : uri.original
}
const onLoad = () => { const onLoad = () => {
setImageLoaded(true) setImageLoaded(true)
if (setImageDimensions && source.uri) { if (setImageDimensions && source.uri) {
Image.getSize(source.uri, (width, height) => setImageDimensions({ width, height })) Image.getSize(source.uri, (width, height) => setImageDimensions({ width, height }))
} }
} }
const onError = () => {
if (!originalFailed) {
setOriginalFailed(true)
}
}
const blurhashView = useMemo(() => { const blurhashView = useMemo(() => {
if (hidden || !imageLoaded) { if (hidden || !imageLoaded) {
@ -101,10 +92,11 @@ const GracefullyImage = ({
/> />
) : null} ) : null}
<FastImage <FastImage
source={source} source={{
uri: reduceMotionEnabled && uri.static ? uri.static : uri.original
}}
style={[{ flex: 1 }, imageStyle]} style={[{ flex: 1 }, imageStyle]}
onLoad={onLoad} onLoad={onLoad}
onError={onError}
/> />
{blurhashView} {blurhashView}
</Pressable> </Pressable>

View File

@ -13,6 +13,8 @@ import { useQueryClient } from '@tanstack/react-query'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
import { checkInstanceFeature } from '@utils/slices/instancesSlice' import { checkInstanceFeature } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import { View } from 'react-native'
import { useRoute } from '@react-navigation/native'
export interface Props { export interface Props {
id: Mastodon.Account['id'] id: Mastodon.Account['id']
@ -122,9 +124,12 @@ const RelationshipOutgoing: React.FC<Props> = ({ id }: Props) => {
} }
} }
const { name } = useRoute()
const isPageNotifications = name === 'Tab-Notifications-Root'
return ( return (
<> <View style={{ flexDirection: 'row', alignItems: 'center' }}>
{canFollowNotify && query.data?.following ? ( {!isPageNotifications && canFollowNotify && query.data?.following ? (
<Button <Button
type='icon' type='icon'
content={query.data.notifying ? 'BellOff' : 'Bell'} content={query.data.notifying ? 'BellOff' : 'Bell'}
@ -151,7 +156,7 @@ const RelationshipOutgoing: React.FC<Props> = ({ id }: Props) => {
loading={query.isLoading || mutation.isLoading} loading={query.isLoading || mutation.isLoading}
disabled={query.isError || query.data?.blocked_by} disabled={query.isError || query.data?.blocked_by}
/> />
</> </View>
) )
} }

View File

@ -1,32 +1,32 @@
{ {
"buttons": { "buttons": {
"OK": "", "OK": "ОК",
"apply": "", "apply": "Применить",
"cancel": "", "cancel": "Отменить",
"discard": "", "discard": "Отклонить",
"continue": "", "continue": "Продолжить",
"create": "", "create": "Создать",
"delete": "", "delete": "Удалить",
"done": "", "done": "Готово",
"confirm": "" "confirm": "Подтвердить"
}, },
"customEmoji": { "customEmoji": {
"accessibilityLabel": "" "accessibilityLabel": "Пользовательские эмодзи {{emoji}}"
}, },
"message": { "message": {
"success": { "success": {
"message": "" "message": "Успешно {{function}}"
}, },
"warning": { "warning": {
"message": "" "message": ""
}, },
"error": { "error": {
"message": "" "message": "Ошибка {{function}}, попробуйте ещё раз"
} }
}, },
"separator": "", "separator": ", ",
"discard": { "discard": {
"title": "", "title": "Изменения не сохранены",
"message": "" "message": "Ваши изменения не были сохранены. Вы хотите отменить изменения?"
} }
} }

View File

@ -15,13 +15,13 @@
"action_false": "Chặn người này", "action_false": "Chặn người này",
"action_true": "Bỏ chặn người dùng", "action_true": "Bỏ chặn người dùng",
"alert": { "alert": {
"title": "" "title": "Bạn có chắc muốn chặn {{username}}?"
} }
}, },
"reports": { "reports": {
"action": "Báo cáo và chặn", "action": "Báo cáo và chặn",
"alert": { "alert": {
"title": "" "title": "Bạn có chắc muốn báo cáo {{username}}?"
} }
} }
}, },

View File

@ -15,13 +15,13 @@
"action_false": "封鎖使用者", "action_false": "封鎖使用者",
"action_true": "解除封鎖使用者", "action_true": "解除封鎖使用者",
"alert": { "alert": {
"title": "" "title": "確認封鎖使用者 @{{username}}"
} }
}, },
"reports": { "reports": {
"action": "檢舉並封鎖使用者", "action": "檢舉並封鎖使用者",
"alert": { "alert": {
"title": "" "title": "確認檢舉並封鎖使用者 @{{username}}"
} }
} }
}, },

View File

@ -1,9 +1,8 @@
import GracefullyImage from '@components/GracefullyImage' import GracefullyImage from '@components/GracefullyImage'
import navigationRef from '@helpers/navigationRef' import navigationRef from '@helpers/navigationRef'
import { getInstanceActive } from '@utils/slices/instancesSlice' import { getInstanceActive } from '@utils/slices/instancesSlice'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react' import React from 'react'
import { Dimensions, Image, Pressable } from 'react-native' import { Dimensions, Image } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context' import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
@ -12,13 +11,14 @@ export interface Props {
} }
const AccountHeader: React.FC<Props> = ({ account }) => { const AccountHeader: React.FC<Props> = ({ account }) => {
const { colors } = useTheme()
const topInset = useSafeAreaInsets().top const topInset = useSafeAreaInsets().top
useSelector(getInstanceActive) useSelector(getInstanceActive)
return ( return (
<Pressable <GracefullyImage
uri={{ original: account?.header, static: account?.header_static }}
style={{ height: Dimensions.get('window').width / 3 + topInset }}
onPress={() => { onPress={() => {
if (account) { if (account) {
Image.getSize(account.header, (width, height) => Image.getSize(account.header, (width, height) =>
@ -30,15 +30,7 @@ const AccountHeader: React.FC<Props> = ({ account }) => {
) )
} }
}} }}
> />
<GracefullyImage
uri={{ original: account?.header, static: account?.header_static }}
style={{
height: Dimensions.get('window').width / 3 + topInset,
backgroundColor: colors.disabled
}}
/>
</Pressable>
) )
} }

View File

@ -17,51 +17,39 @@ export interface Props {
account: Mastodon.Account | undefined account: Mastodon.Account | undefined
} }
const AccountInformation = React.memo( const AccountInformation: React.FC<Props> = ({ account }) => {
({ account }: Props) => { const { colors } = useTheme()
const { colors } = useTheme()
const { name } = useRoute() const { name } = useRoute()
const myInfo = name !== 'Tab-Shared-Account' const myInfo = name !== 'Tab-Shared-Account'
return ( return (
<View style={styles.base}> <View style={styles.base}>
<Placeholder <Placeholder
Animation={props => ( Animation={props => (
<Fade {...props} style={{ backgroundColor: colors.shimmerHighlight }} /> <Fade {...props} style={{ backgroundColor: colors.shimmerHighlight }} />
)} )}
> >
<View style={styles.avatarAndActions}> <View style={styles.avatarAndActions}>
<AccountInformationAvatar account={account} myInfo={myInfo} /> <AccountInformationAvatar account={account} myInfo={myInfo} />
<AccountInformationActions account={account} myInfo={myInfo} /> <AccountInformationActions account={account} myInfo={myInfo} />
</View> </View>
<AccountInformationName account={account} /> <AccountInformationName account={account} />
<AccountInformationAccount account={account} /> <AccountInformationAccount account={account} />
<AccountInformationFields account={account} myInfo={myInfo} /> <AccountInformationFields account={account} myInfo={myInfo} />
<AccountInformationNote account={account} myInfo={myInfo} /> <AccountInformationNote account={account} myInfo={myInfo} />
<AccountInformationCreated account={account} hidden={myInfo} /> <AccountInformationCreated account={account} hidden={myInfo} />
<AccountInformationStats account={account} myInfo={myInfo} /> <AccountInformationStats account={account} myInfo={myInfo} />
</Placeholder> </Placeholder>
</View> </View>
) )
}, }
(prev, next) => {
let skipUpdate = true
if (prev.account?.id !== next.account?.id) {
skipUpdate = false
}
if (prev.account?.acct === next.account?.acct) {
skipUpdate = false
}
return skipUpdate
}
)
const styles = StyleSheet.create({ const styles = StyleSheet.create({
base: { base: {

View File

@ -6,7 +6,6 @@ import { TabLocalStackParamList } from '@utils/navigation/navigators'
import { getInstanceActive } from '@utils/slices/instancesSlice' import { getInstanceActive } from '@utils/slices/instancesSlice'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
import React from 'react' import React from 'react'
import { Pressable } from 'react-native'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
export interface Props { export interface Props {
@ -18,7 +17,15 @@ const AccountInformationAvatar: React.FC<Props> = ({ account, myInfo }) => {
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>() const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
useSelector(getInstanceActive) useSelector(getInstanceActive)
return ( return (
<Pressable <GracefullyImage
key={account?.avatar}
style={{
borderRadius: 8,
overflow: 'hidden',
width: StyleConstants.Avatar.L,
height: StyleConstants.Avatar.L
}}
uri={{ original: account?.avatar, static: account?.avatar_static }}
onPress={() => { onPress={() => {
if (account) { if (account) {
if (myInfo) { if (myInfo) {
@ -33,19 +40,7 @@ const AccountInformationAvatar: React.FC<Props> = ({ account, myInfo }) => {
} }
} }
}} }}
style={{ />
borderRadius: 8,
overflow: 'hidden',
width: StyleConstants.Avatar.L,
height: StyleConstants.Avatar.L
}}
>
<GracefullyImage
key={account?.avatar}
style={{ flex: 1 }}
uri={{ original: account?.avatar, static: account?.avatar_static }}
/>
</Pressable>
) )
} }

View File

@ -72,7 +72,7 @@ const addInstance = createAsyncThunk(
appData, appData,
url: domain, url: domain,
token, token,
uri: instance.uri, uri: instance.uri.replace(/^https?:\/\//, ''), // Pleroma includes schema
urls: instance.urls, urls: instance.urls,
account: { account: {
id, id,

View File

@ -280,7 +280,7 @@ export const getInstanceUrl = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.url instances[findInstanceActive(instances)]?.url
export const getInstanceUri = ({ instances: { instances } }: RootState) => export const getInstanceUri = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.uri.replace(/^https?:\/\//, '') // Pleroma has schema instances[findInstanceActive(instances)]?.uri
export const getInstanceUrls = ({ instances: { instances } }: RootState) => export const getInstanceUrls = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.urls instances[findInstanceActive(instances)]?.urls