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

Merge branch 'main' into candidate

This commit is contained in:
xmflsct
2023-02-06 23:52:41 +01:00
8 changed files with 41 additions and 49 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "tooot", "name": "tooot",
"version": "4.8.7", "version": "4.8.8",
"description": "tooot for Mastodon", "description": "tooot for Mastodon",
"author": "xmflsct <me@xmflsct.com>", "author": "xmflsct <me@xmflsct.com>",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",

View File

@ -160,7 +160,7 @@ const Timeline: React.FC<Props> = ({
viewabilityConfig: { viewabilityConfig: {
minimumViewTime: 300, minimumViewTime: 300,
itemVisiblePercentThreshold: 80, itemVisiblePercentThreshold: 80,
waitForInteraction: true waitForInteraction: false
}, },
onViewableItemsChanged: ({ viewableItems }) => { onViewableItemsChanged: ({ viewableItems }) => {
const marker = readMarker ? getAccountStorage.string(readMarker) : undefined const marker = readMarker ? getAccountStorage.string(readMarker) : undefined

View File

@ -46,17 +46,9 @@ const openLink = async (url: string, navigation?: any) => {
// If an account can be found // If an account can be found
if (match?.account) { if (match?.account) {
if (!match.account._remote && match.account.id) {
handleNavigation('Tab-Shared-Account', { account: match.account.id })
return
}
let response: Mastodon.Account | undefined = undefined let response: Mastodon.Account | undefined = undefined
const queryKey: QueryKeyAccount = [ const queryKey: QueryKeyAccount = ['Account', { url: url, _remote: match.account._remote }]
'Account',
{ id: match.account.id, url: url, _remote: match.account._remote }
]
const cache = queryClient.getQueryData<Mastodon.Status>(queryKey) const cache = queryClient.getQueryData<Mastodon.Status>(queryKey)
if (cache) { if (cache) {

View File

@ -1,5 +1,6 @@
import Button from '@components/Button' import Button from '@components/Button'
import Icon from '@components/Icon' import Icon from '@components/Icon'
import { Loading } from '@components/Loading'
import { MenuContainer, MenuRow } from '@components/Menu' import { MenuContainer, MenuRow } from '@components/Menu'
import { displayMessage } from '@components/Message' import { displayMessage } from '@components/Message'
import CustomText from '@components/Text' import CustomText from '@components/Text'
@ -7,7 +8,6 @@ import * as Sentry from '@sentry/react-native'
import apiInstance from '@utils/api/instance' import apiInstance from '@utils/api/instance'
import apiTooot, { TOOOT_API_DOMAIN } from '@utils/api/tooot' import apiTooot, { TOOOT_API_DOMAIN } from '@utils/api/tooot'
import browserPackage from '@utils/helpers/browserPackage' import browserPackage from '@utils/helpers/browserPackage'
import { isDevelopment } from '@utils/helpers/checkEnvironment'
import { PUSH_ADMIN, PUSH_DEFAULT, setChannels } from '@utils/push/constants' import { PUSH_ADMIN, PUSH_DEFAULT, setChannels } from '@utils/push/constants'
import { updateExpoToken } from '@utils/push/updateExpoToken' import { updateExpoToken } from '@utils/push/updateExpoToken'
import { useAppsQuery } from '@utils/queryHooks/apps' import { useAppsQuery } from '@utils/queryHooks/apps'
@ -35,24 +35,7 @@ const TabMePush: React.FC = () => {
const [accountDomain] = useAccountStorage.string('auth.account.domain') const [accountDomain] = useAccountStorage.string('auth.account.domain')
const [accountId] = useAccountStorage.string('auth.account.id') const [accountId] = useAccountStorage.string('auth.account.id')
const appsQuery = useAppsQuery({ const appsQuery = useAppsQuery()
options: {
enabled: false,
onSuccess: async data => {
if (data.vapid_key) {
await checkPush()
if (isDevelopment) {
setPushAvailable(true)
} else {
setPushAvailable(!!expoToken?.length)
}
}
}
}
})
useEffect(() => {
appsQuery.refetch()
}, [])
const checkPush = async () => { const checkPush = async () => {
const permissions = await Notifications.getPermissionsAsync() const permissions = await Notifications.getPermissionsAsync()
@ -61,11 +44,9 @@ const TabMePush: React.FC = () => {
layoutAnimation() layoutAnimation()
await updateExpoToken() await updateExpoToken()
} }
useEffect(() => {
const [pushAvailable, setPushAvailable] = useState<boolean>() checkPush()
const [pushEnabled, setPushEnabled] = useState<boolean>() }, [])
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
useEffect(() => { useEffect(() => {
const subscription = AppState.addEventListener('change', checkPush) const subscription = AppState.addEventListener('change', checkPush)
return () => { return () => {
@ -73,6 +54,9 @@ const TabMePush: React.FC = () => {
} }
}, []) }, [])
const [pushEnabled, setPushEnabled] = useState<boolean>()
const [pushCanAskAgain, setPushCanAskAgain] = useState<boolean>()
const alerts = () => const alerts = () =>
push?.alerts push?.alerts
? PUSH_DEFAULT().map(alert => ( ? PUSH_DEFAULT().map(alert => (
@ -133,11 +117,11 @@ const TabMePush: React.FC = () => {
const pushPath = `${expoToken}/${domain}/${accountId}` const pushPath = `${expoToken}/${domain}/${accountId}`
const accountFull = `@${accountAcct}@${accountDomain}` const accountFull = `@${accountAcct}@${accountDomain}`
return ( return appsQuery.isFetched ? (
<ScrollView> <ScrollView>
{!!appsQuery.data?.vapid_key ? ( {!!appsQuery.data?.vapid_key ? (
<> <>
{!!pushAvailable ? ( {!!expoToken?.length ? (
<> <>
{pushEnabled === false ? ( {pushEnabled === false ? (
<MenuContainer> <MenuContainer>
@ -249,6 +233,7 @@ const TabMePush: React.FC = () => {
method: 'delete', method: 'delete',
url: 'push/subscription' url: 'push/subscription'
}) })
return Promise.reject()
}) })
setAccountStorage([ setAccountStorage([
@ -352,6 +337,8 @@ const TabMePush: React.FC = () => {
</View> </View>
)} )}
</ScrollView> </ScrollView>
) : (
<Loading style={{ flex: 1 }} />
) )
} }

View File

@ -248,7 +248,11 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
body: data.map(remote => { body: data.map(remote => {
const localMatch = old?.pages[0].body.find(local => local.uri === remote.uri) const localMatch = old?.pages[0].body.find(local => local.uri === remote.uri)
if (localMatch) { if (localMatch) {
return { ...localMatch, _level: remote._level } return {
...localMatch,
_level: remote._level,
key: `${localMatch.id}_remote`
}
} else { } else {
return appendRemote.status(remote) return appendRemote.status(remote)
} }
@ -275,6 +279,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
ref={flRef} ref={flRef}
windowSize={5} windowSize={5}
data={query.data?.pages?.[0].body} data={query.data?.pages?.[0].body}
extraData={query.dataUpdatedAt}
renderItem={({ item, index }) => { renderItem={({ item, index }) => {
const prev = query.data?.pages[0].body[index - 1]?._level || 0 const prev = query.data?.pages[0].body[index - 1]?._level || 0
const curr = item._level || 0 const curr = item._level || 0

View File

@ -9,7 +9,7 @@ export const urlMatcher = (
): ):
| { | {
domain: string domain: string
account?: Partial<Pick<Mastodon.Account, 'id' | 'acct' | '_remote'>> account?: Partial<Pick<Mastodon.Account, 'acct' | '_remote'>>
status?: Partial<Pick<Mastodon.Status, 'id' | '_remote'>> status?: Partial<Pick<Mastodon.Status, 'id' | '_remote'>>
} }
| undefined => { | undefined => {
@ -24,13 +24,18 @@ export const urlMatcher = (
const _remote = parsed.hostname !== getAccountStorage.string('auth.domain') const _remote = parsed.hostname !== getAccountStorage.string('auth.domain')
let statusId: string | undefined let statusId: string | undefined
let accountId: string | undefined
let accountAcct: string | undefined let accountAcct: string | undefined
const segments = parsed.pathname.split('/') const segments = parsed.pathname.split('/')
const last = segments[segments.length - 1] const last = segments[segments.length - 1]
const length = segments.length // there is a starting slash const length = segments.length // there is a starting slash
const testAndAssignStatusId = (id: string) => {
if (!!parseInt(id)) {
statusId = id
}
}
switch (last?.startsWith('@')) { switch (last?.startsWith('@')) {
case true: case true:
if (length === 2 || (length === 3 && segments[length - 2] === 'web')) { if (length === 2 || (length === 3 && segments[length - 2] === 'web')) {
@ -45,14 +50,14 @@ export const urlMatcher = (
if (nextToLast === 'statuses') { if (nextToLast === 'statuses') {
if (length === 4 && segments[length - 3] === 'web') { if (length === 4 && segments[length - 3] === 'web') {
// https://social.xmflsct.com/web/statuses/105590085754428765 <- old // https://social.xmflsct.com/web/statuses/105590085754428765 <- old
statusId = last testAndAssignStatusId(last)
} else if ( } else if (
length === 5 && length === 5 &&
segments[length - 2] === 'statuses' && segments[length - 2] === 'statuses' &&
segments[length - 4] === 'users' segments[length - 4] === 'users'
) { ) {
// https://social.xmflsct.com/users/tooot/statuses/105590085754428765 <- default Mastodon // https://social.xmflsct.com/users/tooot/statuses/105590085754428765 <- default Mastodon
statusId = last testAndAssignStatusId(last)
// accountAcct = `@${segments[length - 3]}@${domain}` // accountAcct = `@${segments[length - 3]}@${domain}`
} }
} else if ( } else if (
@ -61,7 +66,7 @@ export const urlMatcher = (
) { ) {
// https://social.xmflsct.com/web/@tooot/105590085754428765 <- pretty Mastodon v3.5 and below // https://social.xmflsct.com/web/@tooot/105590085754428765 <- pretty Mastodon v3.5 and below
// https://social.xmflsct.com/@tooot/105590085754428765 <- pretty Mastodon v4.0 and above // https://social.xmflsct.com/@tooot/105590085754428765 <- pretty Mastodon v4.0 and above
statusId = last testAndAssignStatusId(last)
// accountAcct = `${nextToLast}@${domain}` // accountAcct = `${nextToLast}@${domain}`
} }
} }
@ -70,7 +75,7 @@ export const urlMatcher = (
return { return {
domain, domain,
...((accountId || accountAcct) && { account: { id: accountId, acct: accountAcct, _remote } }), ...(accountAcct && { account: { acct: accountAcct, _remote } }),
...(statusId && { status: { id: statusId, _remote } }) ...(statusId && { status: { id: statusId, _remote } })
} }
} }

View File

@ -25,7 +25,7 @@ const accountQueryFunction = async ({ queryKey }: QueryFunctionContext<QueryKeyA
const match = urlMatcher(key.url) const match = urlMatcher(key.url)
const domain = match?.domain const domain = match?.domain
const id = key.id || match?.account?.id const id = key.id
const acct = key.acct || key.username || match?.account?.acct const acct = key.acct || key.username || match?.account?.acct
if (!key._local && domain) { if (!key._local && domain) {

View File

@ -43,6 +43,11 @@ const useColorSchemeDelay = (delay = 250) => {
return colorScheme return colorScheme
} }
const determineMode = (
osTheme: 'light' | 'dark' | null | undefined,
userTheme: StorageGlobal['app.theme']
): 'light' | 'dark' =>
!userTheme || userTheme === 'auto' ? osTheme || 'light' : userTheme || 'light'
const determineTheme = ( const determineTheme = (
osTheme: 'light' | 'dark' | null | undefined, osTheme: 'light' | 'dark' | null | undefined,
userTheme: StorageGlobal['app.theme'], userTheme: StorageGlobal['app.theme'],
@ -75,13 +80,11 @@ const ThemeManager: React.FC<PropsWithChildren> = ({ children }) => {
const [userTheme] = useGlobalStorage.string('app.theme') const [userTheme] = useGlobalStorage.string('app.theme')
const [darkTheme] = useGlobalStorage.string('app.theme.dark') const [darkTheme] = useGlobalStorage.string('app.theme.dark')
const [mode, setMode] = useState<'light' | 'dark'>( const [mode, setMode] = useState<'light' | 'dark'>(determineMode(osTheme, userTheme))
userTheme === 'auto' ? osTheme || 'light' : userTheme || 'light'
)
const [theme, setTheme] = useState<Theme>(determineTheme(osTheme, userTheme, darkTheme)) const [theme, setTheme] = useState<Theme>(determineTheme(osTheme, userTheme, darkTheme))
useEffect(() => { useEffect(() => {
setMode(userTheme === 'auto' ? osTheme || 'light' : userTheme || 'light') setMode(determineMode(osTheme, userTheme))
}, [osTheme, userTheme]) }, [osTheme, userTheme])
useEffect(() => { useEffect(() => {
setTheme(determineTheme(osTheme, userTheme, darkTheme)) setTheme(determineTheme(osTheme, userTheme, darkTheme))