mirror of https://github.com/tooot-app/app
Merge branch 'main' into release
This commit is contained in:
commit
f401f5fcb7
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "tooot",
|
||||
"version": "4.8.0",
|
||||
"version": "4.8.1",
|
||||
"description": "tooot for Mastodon",
|
||||
"author": "xmflsct <me@xmflsct.com>",
|
||||
"license": "GPL-3.0-or-later",
|
||||
|
@ -81,6 +81,7 @@
|
|||
"react-native-language-detection": "^0.2.2",
|
||||
"react-native-mmkv": "^2.5.1",
|
||||
"react-native-pager-view": "^6.1.2",
|
||||
"react-native-quick-base64": "^2.0.5",
|
||||
"react-native-reanimated": "^2.13.0",
|
||||
"react-native-reanimated-zoom": "^0.3.3",
|
||||
"react-native-safe-area-context": "^4.4.1",
|
||||
|
|
|
@ -60,7 +60,10 @@ const GracefullyImage = ({
|
|||
uri: reduceMotionEnabled && uri.static ? uri.static : currentUri
|
||||
}
|
||||
useEffect(() => {
|
||||
if (currentUri !== uri.original && currentUri !== uri.remote) {
|
||||
if (
|
||||
(uri.original ? currentUri !== uri.original : true) &&
|
||||
(uri.remote ? currentUri !== uri.remote : true)
|
||||
) {
|
||||
setCurrentUri(uri.original || uri.remote)
|
||||
}
|
||||
}, [currentUri, uri.original, uri.remote])
|
||||
|
|
|
@ -19,12 +19,14 @@ import {
|
|||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as AuthSession from 'expo-auth-session'
|
||||
import * as Random from 'expo-random'
|
||||
import * as WebBrowser from 'expo-web-browser'
|
||||
import { debounce } from 'lodash'
|
||||
import React, { RefObject, useCallback, useState } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { Alert, Image, KeyboardAvoidingView, Platform, TextInput, View } from 'react-native'
|
||||
import { ScrollView } from 'react-native-gesture-handler'
|
||||
import { fromByteArray } from 'react-native-quick-base64'
|
||||
import parse from 'url-parse'
|
||||
import CustomText from '../Text'
|
||||
|
||||
|
@ -158,7 +160,7 @@ const ComponentInstance: React.FC<Props> = ({
|
|||
'admin.sign_up': false,
|
||||
'admin.report': false
|
||||
},
|
||||
key: Math.random().toString(36).slice(2, 12)
|
||||
key: fromByteArray(Random.getRandomBytes(16))
|
||||
},
|
||||
page_local: {
|
||||
showBoosts: true,
|
||||
|
@ -182,7 +184,7 @@ const ComponentInstance: React.FC<Props> = ({
|
|||
)
|
||||
|
||||
if (!account) {
|
||||
setGlobalStorage('accounts', accounts?.concat([accountKey]))
|
||||
setGlobalStorage('accounts', (accounts || []).concat([accountKey]))
|
||||
}
|
||||
setAccount(accountKey)
|
||||
|
||||
|
|
|
@ -197,7 +197,8 @@ const TimelineRefresh: React.FC<Props> = ({
|
|||
const insert = prevCache.current?.slice(-PREV_PER_BATCH)
|
||||
prevCache.current = prevCache.current?.slice(0, -PREV_PER_BATCH)
|
||||
if (insert) {
|
||||
return { ...page, body: [...insert, ...page.body] }
|
||||
page.body.unshift(...insert)
|
||||
return page
|
||||
} else {
|
||||
return page
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@ const HeaderSharedReplies: React.FC = () => {
|
|||
const { t } = useTranslation(['common', 'componentTimeline'])
|
||||
const { colors } = useTheme()
|
||||
|
||||
const mentionsBeginning = rawContent?.current?.[0]
|
||||
.match(new RegExp(/^(?:@\S+\s+)+/))?.[0]
|
||||
?.match(new RegExp(/@\S+/, 'g'))
|
||||
const mentionsBeginning = rawContent?.current?.[0]?.length
|
||||
? rawContent?.current?.[0]
|
||||
.match(new RegExp(/^(?:@\S+\s+)+/))?.[0]
|
||||
?.match(new RegExp(/@\S+/, 'g'))
|
||||
: undefined
|
||||
excludeMentions &&
|
||||
(excludeMentions.current =
|
||||
mentionsBeginning?.length && status?.mentions
|
||||
|
|
|
@ -92,7 +92,7 @@ const ScreenAccountSelection = ({
|
|||
const { colors } = useTheme()
|
||||
const { t } = useTranslation('screenAccountSelection')
|
||||
|
||||
const accounts = getReadableAccounts()
|
||||
const accounts = getReadableAccounts(true)
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
|
|
|
@ -17,7 +17,7 @@ const ComposeDrafts: React.FC<Props> = ({ accessibleRefDrafts }) => {
|
|||
const navigation = useNavigation<any>()
|
||||
const { composeState } = useContext(ComposeContext)
|
||||
const [drafts] = useAccountStorage.object('drafts')
|
||||
const draftsCount = drafts.filter(draft => draft.timestamp !== composeState.timestamp).length
|
||||
const draftsCount = drafts?.filter(draft => draft.timestamp !== composeState.timestamp).length
|
||||
|
||||
useEffect(() => {
|
||||
layoutAnimation()
|
||||
|
|
|
@ -7,8 +7,8 @@ import { useTranslation } from 'react-i18next'
|
|||
import { View } from 'react-native'
|
||||
|
||||
const ComposePostingAs = () => {
|
||||
const accounts = useGlobalStorage.object('accounts')
|
||||
if (!accounts.length) return null
|
||||
const [accounts] = useGlobalStorage.object('accounts')
|
||||
if (!accounts?.length) return null
|
||||
|
||||
const { t } = useTranslation('screenCompose')
|
||||
const { colors } = useTheme()
|
||||
|
|
|
@ -7,7 +7,7 @@ import ComposeRoot from '@screens/Compose/Root'
|
|||
import { formatText } from '@screens/Compose/utils/processText'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { handleError } from '@utils/api/helpers'
|
||||
import { RootStackScreenProps, useNavState } from '@utils/navigation/navigators'
|
||||
import { RootStackScreenProps } from '@utils/navigation/navigators'
|
||||
import { useInstanceQuery } from '@utils/queryHooks/instance'
|
||||
import { usePreferencesQuery } from '@utils/queryHooks/preferences'
|
||||
import { searchLocalStatus } from '@utils/queryHooks/search'
|
||||
|
@ -346,13 +346,6 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
|
|||
}
|
||||
|
||||
switch (params?.type) {
|
||||
case undefined:
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['Timeline', { page: 'Following' }],
|
||||
exact: false
|
||||
})
|
||||
break
|
||||
case 'conversation':
|
||||
case 'edit': // doesn't work
|
||||
// mutateTimeline.mutate({
|
||||
// type: 'editItem',
|
||||
|
@ -361,11 +354,20 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
|
|||
// })
|
||||
// break
|
||||
case 'deleteEdit':
|
||||
case 'reply':
|
||||
for (const navState of params.navigationState) {
|
||||
navState && queryClient.invalidateQueries(navState)
|
||||
}
|
||||
break
|
||||
case 'conversation':
|
||||
case 'reply':
|
||||
if (params.navigationState) {
|
||||
for (const navState of params.navigationState) {
|
||||
navState &&
|
||||
navState[1].page !== 'Following' &&
|
||||
queryClient.invalidateQueries(navState)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
removeDraft(composeState.timestamp)
|
||||
navigation.goBack()
|
||||
|
|
|
@ -17,10 +17,12 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import * as Random from 'expo-random'
|
||||
import * as WebBrowser from 'expo-web-browser'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { AppState, Linking, Platform, ScrollView, View } from 'react-native'
|
||||
import { fromByteArray } from 'react-native-quick-base64'
|
||||
|
||||
const TabMePush: React.FC = () => {
|
||||
const { colors } = useTheme()
|
||||
|
@ -178,6 +180,11 @@ const TabMePush: React.FC = () => {
|
|||
|
||||
setAccountStorage([{ key: 'push', value: { ...push, global: false } }])
|
||||
} else {
|
||||
// Fix a bug for some users of v4.8.0
|
||||
let authKey = push.key
|
||||
if (push.key.length <= 10) {
|
||||
authKey = fromByteArray(Random.getRandomBytes(16))
|
||||
}
|
||||
// Turning on
|
||||
const randomPath = (Math.random() + 1).toString(36).substring(2)
|
||||
|
||||
|
@ -189,7 +196,7 @@ const TabMePush: React.FC = () => {
|
|||
'subscription[keys][p256dh]',
|
||||
'BMn2PLpZrMefG981elzG6SB1EY9gU7QZwmtZ/a/J2vUeWG+zXgeskMPwHh4T/bxsD4l7/8QT94F57CbZqYRRfJo='
|
||||
)
|
||||
formData.append('subscription[keys][auth]', push.key)
|
||||
formData.append('subscription[keys][auth]', authKey)
|
||||
for (const [key, value] of Object.entries(push.alerts)) {
|
||||
formData.append(`data[alerts][${key}]`, value.toString())
|
||||
}
|
||||
|
@ -225,7 +232,9 @@ const TabMePush: React.FC = () => {
|
|||
}
|
||||
})
|
||||
|
||||
setAccountStorage([{ key: 'push', value: { ...push, global: true } }])
|
||||
setAccountStorage([
|
||||
{ key: 'push', value: { ...push, global: true, key: authKey } }
|
||||
])
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
setChannels(true)
|
||||
|
|
|
@ -60,7 +60,7 @@ const Collections: React.FC = () => {
|
|||
title={t('screenTabs:me.stacks.favourites.name')}
|
||||
onPress={() => navigation.navigate('Tab-Me-Favourites')}
|
||||
/>
|
||||
{pageMe.lists.shown ? (
|
||||
{pageMe.lists?.shown ? (
|
||||
<MenuRow
|
||||
iconFront='List'
|
||||
iconBack='ChevronRight'
|
||||
|
@ -68,7 +68,7 @@ const Collections: React.FC = () => {
|
|||
onPress={() => navigation.navigate('Tab-Me-List-List')}
|
||||
/>
|
||||
) : null}
|
||||
{pageMe.followedTags.shown ? (
|
||||
{pageMe.followedTags?.shown ? (
|
||||
<MenuRow
|
||||
iconFront='Hash'
|
||||
iconBack='ChevronRight'
|
||||
|
@ -76,7 +76,7 @@ const Collections: React.FC = () => {
|
|||
onPress={() => navigation.navigate('Tab-Me-FollowedTags')}
|
||||
/>
|
||||
) : null}
|
||||
{pageMe.announcements.shown ? (
|
||||
{pageMe.announcements?.shown ? (
|
||||
<MenuRow
|
||||
iconFront='Clipboard'
|
||||
iconBack='ChevronRight'
|
||||
|
|
|
@ -70,8 +70,8 @@ const TabNotificationsFilters: React.FC<
|
|||
<MenuRow
|
||||
key={index}
|
||||
title={t(`screenTabs:me.push.${type}.heading`)}
|
||||
switchValue={filters[type]}
|
||||
switchOnValueChange={() => setFilters({ ...filters, [type]: !filters[type] })}
|
||||
switchValue={filters?.[type]}
|
||||
switchOnValueChange={() => setFilters({ ...filters, [type]: !filters?.[type] })}
|
||||
/>
|
||||
))}
|
||||
</MenuContainer>
|
||||
|
@ -80,8 +80,8 @@ const TabNotificationsFilters: React.FC<
|
|||
<MenuRow
|
||||
key={type}
|
||||
title={t(`screenTabs:me.push.${type}.heading`)}
|
||||
switchValue={filters[type]}
|
||||
switchOnValueChange={() => setFilters({ ...filters, [type]: !filters[type] })}
|
||||
switchValue={filters?.[type]}
|
||||
switchOnValueChange={() => setFilters({ ...filters, [type]: !filters?.[type] })}
|
||||
/>
|
||||
))}
|
||||
</MenuContainer>
|
||||
|
|
|
@ -38,7 +38,10 @@ const Root: React.FC<NativeStackScreenProps<TabPublicStackParamList, 'Tab-Public
|
|||
const previousSegment = getGlobalStorage.string('app.prev_public_segment')
|
||||
const segments: StorageGlobal['app.prev_public_segment'][] = ['Local', 'LocalPublic', 'Trending']
|
||||
const [segment, setSegment] = useState<number>(
|
||||
segments.findIndex(segment => segment === previousSegment)
|
||||
Math.min(
|
||||
0,
|
||||
segments.findIndex(segment => segment === previousSegment)
|
||||
)
|
||||
)
|
||||
const [routes] = useState([
|
||||
{ key: 'Local', title: t('tabs.public.segments.local') },
|
||||
|
|
|
@ -52,7 +52,7 @@ export const searchLocalStatus = async (uri: Mastodon.Status['uri']): Promise<Ma
|
|||
return await queryClient
|
||||
.fetchQuery(queryKey, queryFunction, { staleTime: 3600, cacheTime: 3600 })
|
||||
.then(res =>
|
||||
res.statuses[0].uri === uri || res.statuses[0].url === uri
|
||||
res.statuses[0]?.uri === uri || res.statuses[0]?.url === uri
|
||||
? res.statuses[0]
|
||||
: Promise.reject()
|
||||
)
|
||||
|
|
|
@ -233,14 +233,15 @@ export type ReadableAccountType = {
|
|||
key: string
|
||||
active: boolean
|
||||
}
|
||||
export const getReadableAccounts = (): ReadableAccountType[] => {
|
||||
const accountActive = getGlobalStorage.string('account.active')
|
||||
export const getReadableAccounts = (withoutActive: boolean = false): ReadableAccountType[] => {
|
||||
const accountActive = !withoutActive && getGlobalStorage.string('account.active')
|
||||
const accounts = getGlobalStorage.object('accounts')?.sort((a, b) => a.localeCompare(b))
|
||||
accounts?.splice(
|
||||
accounts.findIndex(a => a === accountActive),
|
||||
1
|
||||
)
|
||||
accounts?.unshift(accountActive || '')
|
||||
!withoutActive &&
|
||||
accounts?.splice(
|
||||
accounts.findIndex(a => a === accountActive),
|
||||
1
|
||||
)
|
||||
!withoutActive && accounts?.unshift(accountActive || '')
|
||||
return (
|
||||
accounts?.map(account => {
|
||||
const details = getAccountDetails(
|
||||
|
|
13
yarn.lock
13
yarn.lock
|
@ -9718,6 +9718,18 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-quick-base64@npm:^2.0.5":
|
||||
version: 2.0.5
|
||||
resolution: "react-native-quick-base64@npm:2.0.5"
|
||||
dependencies:
|
||||
base64-js: ^1.5.1
|
||||
peerDependencies:
|
||||
react: "*"
|
||||
react-native: "*"
|
||||
checksum: 964599ad68d54dd741357850c72b4a5e08f247fa294590f18866896662107b734b6810703fdd972560cee8087095f14f06fc6ef69944c59c41dbbd885a7832bb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-native-reanimated-zoom@npm:^0.3.3":
|
||||
version: 0.3.3
|
||||
resolution: "react-native-reanimated-zoom@npm:0.3.3"
|
||||
|
@ -11412,6 +11424,7 @@ __metadata:
|
|||
react-native-language-detection: ^0.2.2
|
||||
react-native-mmkv: ^2.5.1
|
||||
react-native-pager-view: ^6.1.2
|
||||
react-native-quick-base64: ^2.0.5
|
||||
react-native-reanimated: ^2.13.0
|
||||
react-native-reanimated-zoom: ^0.3.3
|
||||
react-native-safe-area-context: ^4.4.1
|
||||
|
|
Loading…
Reference in New Issue