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:
@@ -29,6 +29,8 @@ Please **do not** create a pull request to update translation. tooot's translati
|
|||||||
|
|
||||||
[@janlindblom](https://github.com/janlindblom) for Swedish
|
[@janlindblom](https://github.com/janlindblom) for Swedish
|
||||||
|
|
||||||
|
[@ihoryan](https://crowdin.com/profile/ihoryan) for Ukrainian
|
||||||
|
|
||||||
[@duy@mas.to](https://mas.to/@duy) for Vietnamese translation
|
[@duy@mas.to](https://mas.to/@duy) for Vietnamese translation
|
||||||
|
|
||||||
[@jimmyorz](https://github.com/jimmyorz) for Traditional Chinese translation
|
[@jimmyorz](https://github.com/jimmyorz) for Traditional Chinese translation
|
||||||
|
@@ -1,10 +1 @@
|
|||||||
Enjoy toooting! This version includes following improvements and fixes:
|
Enjoy toooting! This version includes following improvements and fixes:
|
||||||
- Added 🇺🇦 Slava Ukraini
|
|
||||||
- Automatic setting detected language when tooting
|
|
||||||
- Remember public timeline type selection
|
|
||||||
- Show diffing of edit history
|
|
||||||
- Allow hiding boosts and replies in home timeline
|
|
||||||
- Support toot in RTL languages
|
|
||||||
- Added notification for admins
|
|
||||||
- Fix whole word filter matching
|
|
||||||
- Fix tablet cannot delete toot drafts
|
|
@@ -1,10 +1 @@
|
|||||||
toooting愉快!此版本包括以下改进和修复:
|
toooting愉快!此版本包括以下改进和修复:
|
||||||
- 增加 🇺🇦 Slava Ukraini
|
|
||||||
- 自动识别发嘟语言
|
|
||||||
- 记住上次公共时间轴选项
|
|
||||||
- 显示编辑历史的差异
|
|
||||||
- 关注列表可隐藏转嘟和回复
|
|
||||||
- 新增管理员推送通知
|
|
||||||
- 支持嘟文右到左文字
|
|
||||||
- 修复过滤整词功能
|
|
||||||
- 修复平板不能删除草稿
|
|
@@ -303,8 +303,6 @@ PODS:
|
|||||||
- React-Core
|
- React-Core
|
||||||
- react-native-language-detection (0.2.2):
|
- react-native-language-detection (0.2.2):
|
||||||
- React
|
- React
|
||||||
- react-native-live-text-image-view (0.4.0):
|
|
||||||
- React-Core
|
|
||||||
- react-native-menu (0.7.2):
|
- react-native-menu (0.7.2):
|
||||||
- React
|
- React
|
||||||
- react-native-netinfo (9.3.7):
|
- react-native-netinfo (9.3.7):
|
||||||
@@ -428,9 +426,9 @@ PODS:
|
|||||||
- RNScreens (3.18.2):
|
- RNScreens (3.18.2):
|
||||||
- React-Core
|
- React-Core
|
||||||
- React-RCTImage
|
- React-RCTImage
|
||||||
- RNSentry (4.11.0):
|
- RNSentry (4.12.0):
|
||||||
- React-Core
|
- React-Core
|
||||||
- Sentry/HybridSDK (= 7.31.2)
|
- Sentry/HybridSDK (= 7.31.3)
|
||||||
- RNShareMenu (6.0.0):
|
- RNShareMenu (6.0.0):
|
||||||
- React
|
- React
|
||||||
- RNSVG (13.6.0):
|
- RNSVG (13.6.0):
|
||||||
@@ -441,7 +439,7 @@ PODS:
|
|||||||
- SDWebImageWebPCoder (0.9.1):
|
- SDWebImageWebPCoder (0.9.1):
|
||||||
- libwebp (~> 1.0)
|
- libwebp (~> 1.0)
|
||||||
- SDWebImage/Core (~> 5.13)
|
- SDWebImage/Core (~> 5.13)
|
||||||
- Sentry/HybridSDK (7.31.2)
|
- Sentry/HybridSDK (7.31.3)
|
||||||
- Swime (3.0.6)
|
- Swime (3.0.6)
|
||||||
- Yoga (1.14.0)
|
- Yoga (1.14.0)
|
||||||
|
|
||||||
@@ -495,7 +493,6 @@ DEPENDENCIES:
|
|||||||
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
|
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
|
||||||
- react-native-ios-context-menu (from `../node_modules/react-native-ios-context-menu`)
|
- react-native-ios-context-menu (from `../node_modules/react-native-ios-context-menu`)
|
||||||
- react-native-language-detection (from `../node_modules/react-native-language-detection`)
|
- react-native-language-detection (from `../node_modules/react-native-language-detection`)
|
||||||
- react-native-live-text-image-view (from `../node_modules/react-native-live-text-image-view`)
|
|
||||||
- "react-native-menu (from `../node_modules/@react-native-menu/menu`)"
|
- "react-native-menu (from `../node_modules/@react-native-menu/menu`)"
|
||||||
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
|
||||||
- react-native-pager-view (from `../node_modules/react-native-pager-view`)
|
- react-native-pager-view (from `../node_modules/react-native-pager-view`)
|
||||||
@@ -630,8 +627,6 @@ EXTERNAL SOURCES:
|
|||||||
:path: "../node_modules/react-native-ios-context-menu"
|
:path: "../node_modules/react-native-ios-context-menu"
|
||||||
react-native-language-detection:
|
react-native-language-detection:
|
||||||
:path: "../node_modules/react-native-language-detection"
|
:path: "../node_modules/react-native-language-detection"
|
||||||
react-native-live-text-image-view:
|
|
||||||
:path: "../node_modules/react-native-live-text-image-view"
|
|
||||||
react-native-menu:
|
react-native-menu:
|
||||||
:path: "../node_modules/@react-native-menu/menu"
|
:path: "../node_modules/@react-native-menu/menu"
|
||||||
react-native-netinfo:
|
react-native-netinfo:
|
||||||
@@ -740,7 +735,6 @@ SPEC CHECKSUMS:
|
|||||||
react-native-image-picker: bf34f3f516d139ed3e24c5f5a381a91819e349ea
|
react-native-image-picker: bf34f3f516d139ed3e24c5f5a381a91819e349ea
|
||||||
react-native-ios-context-menu: b170594b4448c0cd10c79e13432216bac99de1ac
|
react-native-ios-context-menu: b170594b4448c0cd10c79e13432216bac99de1ac
|
||||||
react-native-language-detection: f414937fa715108ab50a6269a3de0bcb95e4ceb0
|
react-native-language-detection: f414937fa715108ab50a6269a3de0bcb95e4ceb0
|
||||||
react-native-live-text-image-view: 483bacfdba464162b8cf176bba555364f18b584c
|
|
||||||
react-native-menu: 8e172cfcf0e42e92f028e7781eddf84d430cae24
|
react-native-menu: 8e172cfcf0e42e92f028e7781eddf84d430cae24
|
||||||
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
|
react-native-netinfo: 2517ad504b3d303e90d7a431b0fcaef76d207983
|
||||||
react-native-pager-view: 54bed894cecebe28cede54c01038d9d1e122de43
|
react-native-pager-view: 54bed894cecebe28cede54c01038d9d1e122de43
|
||||||
@@ -765,12 +759,12 @@ SPEC CHECKSUMS:
|
|||||||
RNGestureHandler: 62232ba8f562f7dea5ba1b3383494eb5bf97a4d3
|
RNGestureHandler: 62232ba8f562f7dea5ba1b3383494eb5bf97a4d3
|
||||||
RNReanimated: ce445c233a6ff5600223484a88ad5704945d972a
|
RNReanimated: ce445c233a6ff5600223484a88ad5704945d972a
|
||||||
RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d
|
RNScreens: 34cc502acf1b916c582c60003dc3089fa01dc66d
|
||||||
RNSentry: f052387ebe939949c74c2cae0c850e76f6d14ddb
|
RNSentry: 4c09f4dd9740cb9b33e94303de5b6d0dbeb0737d
|
||||||
RNShareMenu: cb9dac548c8bf147d06f0bf07296ad51ea9f5fc3
|
RNShareMenu: cb9dac548c8bf147d06f0bf07296ad51ea9f5fc3
|
||||||
RNSVG: 3a79c0c4992213e4f06c08e62730c5e7b9e4dc17
|
RNSVG: 3a79c0c4992213e4f06c08e62730c5e7b9e4dc17
|
||||||
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
|
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
|
||||||
SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0
|
SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0
|
||||||
Sentry: b15765d11769852fe78c9add942f7df60ed5dbf5
|
Sentry: 08884c523575ec0f6690d94ed3ccb0246a1600bf
|
||||||
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
|
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
|
||||||
Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc
|
Yoga: 99caf8d5ab45e9d637ee6e0174ec16fbbb01bcfc
|
||||||
|
|
||||||
|
19
package.json
19
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "tooot",
|
"name": "tooot",
|
||||||
"version": "4.7.0",
|
"version": "4.7.1",
|
||||||
"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",
|
||||||
@@ -34,14 +34,14 @@
|
|||||||
"@react-native-community/netinfo": "9.3.7",
|
"@react-native-community/netinfo": "9.3.7",
|
||||||
"@react-native-community/segmented-control": "^2.2.2",
|
"@react-native-community/segmented-control": "^2.2.2",
|
||||||
"@react-native-menu/menu": "^0.7.2",
|
"@react-native-menu/menu": "^0.7.2",
|
||||||
"@react-navigation/bottom-tabs": "^6.5.0",
|
"@react-navigation/bottom-tabs": "^6.5.1",
|
||||||
"@react-navigation/native": "^6.1.0",
|
"@react-navigation/native": "^6.1.1",
|
||||||
"@react-navigation/native-stack": "^6.9.5",
|
"@react-navigation/native-stack": "^6.9.6",
|
||||||
"@react-navigation/stack": "^6.3.8",
|
"@react-navigation/stack": "^6.3.9",
|
||||||
"@reduxjs/toolkit": "^1.9.1",
|
"@reduxjs/toolkit": "^1.9.1",
|
||||||
"@sentry/react-native": "4.11.0",
|
"@sentry/react-native": "4.12.0",
|
||||||
"@sharcoux/slider": "^6.1.1",
|
"@sharcoux/slider": "^6.1.1",
|
||||||
"@tanstack/react-query": "^4.19.1",
|
"@tanstack/react-query": "^4.20.4",
|
||||||
"axios": "^1.2.1",
|
"axios": "^1.2.1",
|
||||||
"diff": "^5.1.0",
|
"diff": "^5.1.0",
|
||||||
"expo": "^47.0.8",
|
"expo": "^47.0.8",
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
"expo-store-review": "^6.0.0",
|
"expo-store-review": "^6.0.0",
|
||||||
"expo-video-thumbnails": "^7.0.0",
|
"expo-video-thumbnails": "^7.0.0",
|
||||||
"expo-web-browser": "~12.0.0",
|
"expo-web-browser": "~12.0.0",
|
||||||
"i18next": "^22.4.1",
|
"i18next": "^22.4.5",
|
||||||
"linkify-it": "^4.0.1",
|
"linkify-it": "^4.0.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
@@ -80,7 +80,6 @@
|
|||||||
"react-native-image-picker": "^4.10.2",
|
"react-native-image-picker": "^4.10.2",
|
||||||
"react-native-ios-context-menu": "^1.15.1",
|
"react-native-ios-context-menu": "^1.15.1",
|
||||||
"react-native-language-detection": "^0.2.2",
|
"react-native-language-detection": "^0.2.2",
|
||||||
"react-native-live-text-image-view": "^0.4.0",
|
|
||||||
"react-native-pager-view": "^6.1.2",
|
"react-native-pager-view": "^6.1.2",
|
||||||
"react-native-reanimated": "^2.13.0",
|
"react-native-reanimated": "^2.13.0",
|
||||||
"react-native-reanimated-zoom": "^0.3.3",
|
"react-native-reanimated-zoom": "^0.3.3",
|
||||||
@@ -89,7 +88,7 @@
|
|||||||
"react-native-share-menu": "^6.0.0",
|
"react-native-share-menu": "^6.0.0",
|
||||||
"react-native-svg": "^13.6.0",
|
"react-native-svg": "^13.6.0",
|
||||||
"react-native-swipe-list-view": "^3.2.9",
|
"react-native-swipe-list-view": "^3.2.9",
|
||||||
"react-native-tab-view": "^3.3.3",
|
"react-native-tab-view": "^3.3.4",
|
||||||
"react-redux": "^8.0.5",
|
"react-redux": "^8.0.5",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"rn-placeholder": "^3.0.3",
|
"rn-placeholder": "^3.0.3",
|
||||||
|
3
src/@types/mastodon.d.ts
vendored
3
src/@types/mastodon.d.ts
vendored
@@ -395,6 +395,7 @@ declare namespace Mastodon {
|
|||||||
mention: boolean
|
mention: boolean
|
||||||
poll: boolean
|
poll: boolean
|
||||||
status: boolean
|
status: boolean
|
||||||
|
update: boolean
|
||||||
'admin.sign_up': boolean
|
'admin.sign_up': boolean
|
||||||
'admin.report': boolean
|
'admin.report': boolean
|
||||||
}
|
}
|
||||||
@@ -405,6 +406,8 @@ declare namespace Mastodon {
|
|||||||
id: string
|
id: string
|
||||||
following: boolean
|
following: boolean
|
||||||
showing_reblogs: boolean
|
showing_reblogs: boolean
|
||||||
|
notifying?: boolean
|
||||||
|
languages?: string[]
|
||||||
followed_by: boolean
|
followed_by: boolean
|
||||||
blocking: boolean
|
blocking: boolean
|
||||||
blocked_by: boolean
|
blocked_by: boolean
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { ctx, handleError, userAgent } from './helpers'
|
import { ctx, handleError, PagedResponse, userAgent } from './helpers'
|
||||||
|
|
||||||
export type Params = {
|
export type Params = {
|
||||||
method: 'get' | 'post' | 'put' | 'delete'
|
method: 'get' | 'post' | 'put' | 'delete'
|
||||||
@@ -19,7 +19,7 @@ const apiGeneral = async <T = unknown>({
|
|||||||
params,
|
params,
|
||||||
headers,
|
headers,
|
||||||
body
|
body
|
||||||
}: Params): Promise<{ body: T }> => {
|
}: Params): Promise<PagedResponse<T>> => {
|
||||||
console.log(
|
console.log(
|
||||||
ctx.bgGreen.bold(' API general ') +
|
ctx.bgGreen.bold(' API general ') +
|
||||||
' ' +
|
' ' +
|
||||||
|
@@ -54,13 +54,19 @@ const handleError =
|
|||||||
console.error(ctx.bold(' API '), ctx.bold('request'), error)
|
console.error(ctx.bold(' API '), ctx.bold('request'), error)
|
||||||
|
|
||||||
shouldReportToSentry && Sentry.captureMessage(config.message)
|
shouldReportToSentry && Sentry.captureMessage(config.message)
|
||||||
return Promise.reject()
|
return Promise.reject(error)
|
||||||
} else {
|
} else {
|
||||||
console.error(ctx.bold(' API '), ctx.bold('internal'), error?.message)
|
console.error(ctx.bold(' API '), ctx.bold('internal'), error?.message)
|
||||||
|
|
||||||
shouldReportToSentry && Sentry.captureMessage(config.message)
|
shouldReportToSentry && Sentry.captureMessage(config.message)
|
||||||
return Promise.reject()
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LinkFormat = { id: string; isOffset: boolean }
|
||||||
|
export type PagedResponse<T = unknown> = {
|
||||||
|
body: T
|
||||||
|
links: { prev?: LinkFormat; next?: LinkFormat }
|
||||||
|
}
|
||||||
|
|
||||||
export { ctx, handleError, userAgent }
|
export { ctx, handleError, userAgent }
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { RootState } from '@root/store'
|
import { RootState } from '@root/store'
|
||||||
import axios, { AxiosRequestConfig } from 'axios'
|
import axios, { AxiosRequestConfig } from 'axios'
|
||||||
import { ctx, handleError, userAgent } from './helpers'
|
import { ctx, handleError, PagedResponse, userAgent } from './helpers'
|
||||||
|
|
||||||
export type Params = {
|
export type Params = {
|
||||||
method: 'get' | 'post' | 'put' | 'delete' | 'patch'
|
method: 'get' | 'post' | 'put' | 'delete' | 'patch'
|
||||||
@@ -14,12 +14,6 @@ export type Params = {
|
|||||||
extras?: Omit<AxiosRequestConfig, 'method' | 'url' | 'params' | 'headers' | 'data'>
|
extras?: Omit<AxiosRequestConfig, 'method' | 'url' | 'params' | 'headers' | 'data'>
|
||||||
}
|
}
|
||||||
|
|
||||||
type LinkFormat = { id: string; isOffset: boolean }
|
|
||||||
export type InstanceResponse<T = unknown> = {
|
|
||||||
body: T
|
|
||||||
links: { prev?: LinkFormat; next?: LinkFormat }
|
|
||||||
}
|
|
||||||
|
|
||||||
const apiInstance = async <T = unknown>({
|
const apiInstance = async <T = unknown>({
|
||||||
method,
|
method,
|
||||||
version = 'v1',
|
version = 'v1',
|
||||||
@@ -28,7 +22,7 @@ const apiInstance = async <T = unknown>({
|
|||||||
headers,
|
headers,
|
||||||
body,
|
body,
|
||||||
extras
|
extras
|
||||||
}: Params): Promise<InstanceResponse<T>> => {
|
}: Params): Promise<PagedResponse<T>> => {
|
||||||
const { store } = require('@root/store')
|
const { store } = require('@root/store')
|
||||||
const state = store.getState() as RootState
|
const state = store.getState() as RootState
|
||||||
const instanceActive = state.instances.instances.findIndex(instance => instance.active)
|
const instanceActive = state.instances.instances.findIndex(instance => instance.active)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import * as Sentry from '@sentry/react-native'
|
|
||||||
import { mapEnvironment } from '@utils/checkEnvironment'
|
import { mapEnvironment } from '@utils/checkEnvironment'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { ctx, handleError, userAgent } from './helpers'
|
import { ctx, handleError, userAgent } from './helpers'
|
||||||
@@ -37,7 +36,7 @@ const apiTooot = async <T = unknown>({
|
|||||||
)
|
)
|
||||||
|
|
||||||
return axios({
|
return axios({
|
||||||
timeout: method === 'post' ? 1000 * 60 : 1000 * 15,
|
timeout: method === 'post' ? 1000 * 60 : 1000 * 30,
|
||||||
method,
|
method,
|
||||||
baseURL: `https://${TOOOT_API_DOMAIN}/`,
|
baseURL: `https://${TOOOT_API_DOMAIN}/`,
|
||||||
url: `${url}`,
|
url: `${url}`,
|
||||||
|
@@ -4,15 +4,13 @@ import React, { useMemo, useState } from 'react'
|
|||||||
import {
|
import {
|
||||||
AccessibilityProps,
|
AccessibilityProps,
|
||||||
Image,
|
Image,
|
||||||
ImageStyle,
|
|
||||||
Platform,
|
|
||||||
Pressable,
|
Pressable,
|
||||||
StyleProp,
|
StyleProp,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
ViewStyle
|
ViewStyle
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
import FastImage, { ImageStyle } from 'react-native-fast-image'
|
||||||
import { Blurhash } from 'react-native-blurhash'
|
import { Blurhash } from 'react-native-blurhash'
|
||||||
|
|
||||||
// blurhas -> if blurhash, show before any loading succeed
|
// blurhas -> if blurhash, show before any loading succeed
|
||||||
@@ -97,30 +95,17 @@ const GracefullyImage = ({
|
|||||||
{...(onPress ? (hidden ? { disabled: true } : { onPress }) : { disabled: true })}
|
{...(onPress ? (hidden ? { disabled: true } : { onPress }) : { disabled: true })}
|
||||||
>
|
>
|
||||||
{uri.preview && !imageLoaded ? (
|
{uri.preview && !imageLoaded ? (
|
||||||
<Image
|
<FastImage
|
||||||
fadeDuration={0}
|
|
||||||
source={{ uri: uri.preview }}
|
source={{ uri: uri.preview }}
|
||||||
style={[styles.placeholder, { backgroundColor: colors.shimmerDefault }]}
|
style={[styles.placeholder, { backgroundColor: colors.shimmerDefault }]}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{Platform.OS === 'ios' ? (
|
|
||||||
<Image
|
|
||||||
fadeDuration={0}
|
|
||||||
source={source}
|
|
||||||
style={[{ flex: 1 }, imageStyle]}
|
|
||||||
onLoad={onLoad}
|
|
||||||
onError={onError}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<FastImage
|
<FastImage
|
||||||
fadeDuration={0}
|
|
||||||
source={source}
|
source={source}
|
||||||
// @ts-ignore
|
|
||||||
style={[{ flex: 1 }, imageStyle]}
|
style={[{ flex: 1 }, imageStyle]}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
onError={onError}
|
onError={onError}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
{blurhashView}
|
{blurhashView}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)
|
)
|
||||||
|
@@ -15,6 +15,7 @@ import { Alert, Image, KeyboardAvoidingView, Platform, TextInput, View } from 'r
|
|||||||
import { ScrollView } from 'react-native-gesture-handler'
|
import { ScrollView } from 'react-native-gesture-handler'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import { Placeholder } from 'rn-placeholder'
|
import { Placeholder } from 'rn-placeholder'
|
||||||
|
import validUrl from 'valid-url'
|
||||||
import InstanceInfo from './Info'
|
import InstanceInfo from './Info'
|
||||||
import CustomText from '../Text'
|
import CustomText from '../Text'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
@@ -39,12 +40,26 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
const navigation = useNavigation<TabMeStackNavigationProp<'Tab-Me-Root' | 'Tab-Me-Switch'>>()
|
const navigation = useNavigation<TabMeStackNavigationProp<'Tab-Me-Root' | 'Tab-Me-Switch'>>()
|
||||||
|
|
||||||
const [domain, setDomain] = useState<string>('')
|
const [domain, setDomain] = useState<string>('')
|
||||||
|
const [errorCode, setErrorCode] = useState<number | null>(null)
|
||||||
|
const whitelisted: boolean =
|
||||||
|
!!domain.length &&
|
||||||
|
!!errorCode &&
|
||||||
|
!!validUrl.isHttpsUri(`https://${domain}`) &&
|
||||||
|
errorCode === 401
|
||||||
|
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const instances = useSelector(getInstances, () => true)
|
const instances = useSelector(getInstances, () => true)
|
||||||
const instanceQuery = useInstanceQuery({
|
const instanceQuery = useInstanceQuery({
|
||||||
domain,
|
domain,
|
||||||
options: { enabled: !!domain, retry: false }
|
options: {
|
||||||
|
enabled: !!domain,
|
||||||
|
retry: false,
|
||||||
|
onError: err => {
|
||||||
|
if (err.status) {
|
||||||
|
setErrorCode(err.status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const deprecateAuthFollow = useSelector(checkInstanceFeature('deprecate_auth_follow'))
|
const deprecateAuthFollow = useSelector(checkInstanceFeature('deprecate_auth_follow'))
|
||||||
@@ -146,7 +161,11 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
...StyleConstants.FontStyle.M,
|
...StyleConstants.FontStyle.M,
|
||||||
color: colors.primaryDefault,
|
color: colors.primaryDefault,
|
||||||
borderBottomColor: instanceQuery.isError ? colors.red : colors.border,
|
borderBottomColor: instanceQuery.isError
|
||||||
|
? whitelisted
|
||||||
|
? colors.yellow
|
||||||
|
: colors.red
|
||||||
|
: colors.border,
|
||||||
...(Platform.OS === 'android' && { paddingRight: 0 })
|
...(Platform.OS === 'android' && { paddingRight: 0 })
|
||||||
}}
|
}}
|
||||||
editable={false}
|
editable={false}
|
||||||
@@ -159,12 +178,23 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
...StyleConstants.FontStyle.M,
|
...StyleConstants.FontStyle.M,
|
||||||
marginRight: StyleConstants.Spacing.M,
|
marginRight: StyleConstants.Spacing.M,
|
||||||
color: colors.primaryDefault,
|
color: colors.primaryDefault,
|
||||||
borderBottomColor: instanceQuery.isError ? colors.red : colors.border,
|
borderBottomColor: instanceQuery.isError
|
||||||
|
? whitelisted
|
||||||
|
? colors.yellow
|
||||||
|
: colors.red
|
||||||
|
: colors.border,
|
||||||
...(Platform.OS === 'android' && { paddingLeft: 0 })
|
...(Platform.OS === 'android' && { paddingLeft: 0 })
|
||||||
}}
|
}}
|
||||||
onChangeText={debounce(text => setDomain(text.replace(/^http(s)?\:\/\//i, '')), 1000, {
|
onChangeText={debounce(
|
||||||
|
text => {
|
||||||
|
setDomain(text.replace(/^http(s)?\:\/\//i, ''))
|
||||||
|
setErrorCode(null)
|
||||||
|
},
|
||||||
|
1000,
|
||||||
|
{
|
||||||
trailing: true
|
trailing: true
|
||||||
})}
|
}
|
||||||
|
)}
|
||||||
autoCapitalize='none'
|
autoCapitalize='none'
|
||||||
clearButtonMode='never'
|
clearButtonMode='never'
|
||||||
keyboardType='url'
|
keyboardType='url'
|
||||||
@@ -194,12 +224,24 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
type='text'
|
type='text'
|
||||||
content={t('server.button')}
|
content={t('server.button')}
|
||||||
onPress={processUpdate}
|
onPress={processUpdate}
|
||||||
disabled={!instanceQuery.data?.uri}
|
disabled={!instanceQuery.data?.uri && !whitelisted}
|
||||||
loading={instanceQuery.isFetching || appsMutation.isLoading}
|
loading={instanceQuery.isFetching || appsMutation.isLoading}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View>
|
<View>
|
||||||
|
{whitelisted ? (
|
||||||
|
<CustomText
|
||||||
|
fontStyle='S'
|
||||||
|
style={{
|
||||||
|
color: colors.yellow,
|
||||||
|
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||||
|
paddingTop: StyleConstants.Spacing.XS
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('server.whitelisted')}
|
||||||
|
</CustomText>
|
||||||
|
) : (
|
||||||
<Placeholder>
|
<Placeholder>
|
||||||
<InstanceInfo
|
<InstanceInfo
|
||||||
header={t('server.information.name')}
|
header={t('server.information.name')}
|
||||||
@@ -227,6 +269,7 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</Placeholder>
|
</Placeholder>
|
||||||
|
)}
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
@@ -276,7 +319,7 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
style={{ color: colors.blue }}
|
style={{ color: colors.blue }}
|
||||||
onPress={async () =>
|
onPress={async () =>
|
||||||
WebBrowser.openBrowserAsync('https://tooot.app/privacy-policy', {
|
WebBrowser.openBrowserAsync('https://tooot.app/privacy-policy', {
|
||||||
browserPackage: await browserPackage()
|
...(await browserPackage())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>,
|
/>,
|
||||||
@@ -285,7 +328,7 @@ const ComponentInstance: React.FC<Props> = ({
|
|||||||
style={{ color: colors.blue }}
|
style={{ color: colors.blue }}
|
||||||
onPress={async () =>
|
onPress={async () =>
|
||||||
WebBrowser.openBrowserAsync('https://tooot.app/terms-of-service', {
|
WebBrowser.openBrowserAsync('https://tooot.app/terms-of-service', {
|
||||||
browserPackage: await browserPackage()
|
...(await browserPackage())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@@ -65,7 +65,6 @@ const MenuRow: React.FC<Props> = ({
|
|||||||
>
|
>
|
||||||
<TapGestureHandler
|
<TapGestureHandler
|
||||||
onHandlerStateChange={async ({ nativeEvent }) => {
|
onHandlerStateChange={async ({ nativeEvent }) => {
|
||||||
if (typeof iconBack !== 'string') return // Let icon back handles the gesture
|
|
||||||
if (nativeEvent.state === State.ACTIVE && !loading) {
|
if (nativeEvent.state === State.ACTIVE && !loading) {
|
||||||
if (screenReaderEnabled && switchOnValueChange) {
|
if (screenReaderEnabled && switchOnValueChange) {
|
||||||
switchOnValueChange()
|
switchOnValueChange()
|
||||||
@@ -86,7 +85,7 @@ const MenuRow: React.FC<Props> = ({
|
|||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
flexGrow: 3,
|
flexShrink: 3,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginRight: StyleConstants.Spacing.M
|
marginRight: StyleConstants.Spacing.M
|
||||||
|
@@ -6,21 +6,24 @@ import {
|
|||||||
useRelationshipMutation,
|
useRelationshipMutation,
|
||||||
useRelationshipQuery
|
useRelationshipQuery
|
||||||
} from '@utils/queryHooks/relationship'
|
} from '@utils/queryHooks/relationship'
|
||||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useQueryClient } from '@tanstack/react-query'
|
import { useQueryClient } from '@tanstack/react-query'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import { checkInstanceFeature } from '@utils/slices/instancesSlice'
|
||||||
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
id: Mastodon.Account['id']
|
id: Mastodon.Account['id']
|
||||||
}
|
}
|
||||||
|
|
||||||
const RelationshipOutgoing = React.memo(
|
const RelationshipOutgoing: React.FC<Props> = ({ id }: Props) => {
|
||||||
({ id }: Props) => {
|
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const { t } = useTranslation('componentRelationship')
|
const { t } = useTranslation('componentRelationship')
|
||||||
|
|
||||||
|
const canFollowNotify = useSelector(checkInstanceFeature('account_follow_notify'))
|
||||||
|
|
||||||
const query = useRelationshipQuery({ id })
|
const query = useRelationshipQuery({ id })
|
||||||
|
|
||||||
const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id }]
|
const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id }]
|
||||||
@@ -120,6 +123,27 @@ const RelationshipOutgoing = React.memo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{canFollowNotify && query.data?.following ? (
|
||||||
|
<Button
|
||||||
|
type='icon'
|
||||||
|
content={query.data.notifying ? 'BellOff' : 'Bell'}
|
||||||
|
round
|
||||||
|
onPress={() =>
|
||||||
|
mutation.mutate({
|
||||||
|
id,
|
||||||
|
type: 'outgoing',
|
||||||
|
payload: {
|
||||||
|
action: 'follow',
|
||||||
|
state: false,
|
||||||
|
notify: !query.data.notifying
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
loading={query.isLoading || mutation.isLoading}
|
||||||
|
style={{ marginRight: StyleConstants.Spacing.S }}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
<Button
|
<Button
|
||||||
type='text'
|
type='text'
|
||||||
content={content}
|
content={content}
|
||||||
@@ -127,9 +151,8 @@ const RelationshipOutgoing = React.memo(
|
|||||||
loading={query.isLoading || mutation.isLoading}
|
loading={query.isLoading || mutation.isLoading}
|
||||||
disabled={query.isError || query.data?.blocked_by}
|
disabled={query.isError || query.data?.blocked_by}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
() => true
|
|
||||||
)
|
|
||||||
|
|
||||||
export default RelationshipOutgoing
|
export default RelationshipOutgoing
|
||||||
|
@@ -34,6 +34,7 @@ export interface Props {
|
|||||||
highlighted?: boolean
|
highlighted?: boolean
|
||||||
disableDetails?: boolean
|
disableDetails?: boolean
|
||||||
disableOnPress?: boolean
|
disableOnPress?: boolean
|
||||||
|
isConversation?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the poll is long
|
// When the poll is long
|
||||||
@@ -43,7 +44,8 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
rootQueryKey,
|
rootQueryKey,
|
||||||
highlighted = false,
|
highlighted = false,
|
||||||
disableDetails = false,
|
disableDetails = false,
|
||||||
disableOnPress = false
|
disableOnPress = false,
|
||||||
|
isConversation = false
|
||||||
}) => {
|
}) => {
|
||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
||||||
@@ -53,15 +55,16 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
const status = item.reblog ? item.reblog : item
|
const status = item.reblog ? item.reblog : item
|
||||||
const ownAccount = status.account?.id === instanceAccount?.id
|
const ownAccount = status.account?.id === instanceAccount?.id
|
||||||
const [spoilerExpanded, setSpoilerExpanded] = useState(
|
const [spoilerExpanded, setSpoilerExpanded] = useState(
|
||||||
instanceAccount?.preferences['reading:expand:spoilers'] || false
|
instanceAccount?.preferences?.['reading:expand:spoilers'] || false
|
||||||
)
|
)
|
||||||
const spoilerHidden = status.spoiler_text?.length
|
const spoilerHidden = status.spoiler_text?.length
|
||||||
? !instanceAccount?.preferences['reading:expand:spoilers'] && !spoilerExpanded
|
? !instanceAccount?.preferences?.['reading:expand:spoilers'] && !spoilerExpanded
|
||||||
: false
|
: false
|
||||||
const copiableContent = useRef<{ content: string; complete: boolean }>({
|
const copiableContent = useRef<{ content: string; complete: boolean }>({
|
||||||
content: '',
|
content: '',
|
||||||
complete: false
|
complete: false
|
||||||
})
|
})
|
||||||
|
const detectedLanguage = useRef<string>(status.language || '')
|
||||||
|
|
||||||
const filtered = queryKey && shouldFilter({ copiableContent, status, queryKey })
|
const filtered = queryKey && shouldFilter({ copiableContent, status, queryKey })
|
||||||
if (queryKey && filtered && !highlighted) {
|
if (queryKey && filtered && !highlighted) {
|
||||||
@@ -74,7 +77,7 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
? StyleConstants.Spacing.Global.PagePadding / 1.5
|
? StyleConstants.Spacing.Global.PagePadding / 1.5
|
||||||
: StyleConstants.Spacing.Global.PagePadding,
|
: StyleConstants.Spacing.Global.PagePadding,
|
||||||
backgroundColor: colors.backgroundDefault,
|
backgroundColor: colors.backgroundDefault,
|
||||||
paddingBottom: disableDetails ? StyleConstants.Spacing.Global.PagePadding / 1.5 : 0,
|
paddingBottom: disableDetails ? StyleConstants.Spacing.Global.PagePadding / 1.5 : 0
|
||||||
}
|
}
|
||||||
const main = () => (
|
const main = () => (
|
||||||
<>
|
<>
|
||||||
@@ -137,10 +140,12 @@ const TimelineDefault: React.FC<Props> = ({
|
|||||||
ownAccount,
|
ownAccount,
|
||||||
spoilerHidden,
|
spoilerHidden,
|
||||||
copiableContent,
|
copiableContent,
|
||||||
|
detectedLanguage,
|
||||||
highlighted,
|
highlighted,
|
||||||
inThread: queryKey?.[1].page === 'Toot',
|
inThread: queryKey?.[1].page === 'Toot',
|
||||||
disableDetails,
|
disableDetails,
|
||||||
disableOnPress
|
disableOnPress,
|
||||||
|
isConversation
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{disableOnPress ? (
|
{disableOnPress ? (
|
||||||
|
@@ -42,10 +42,10 @@ const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
|
|||||||
: notification.account
|
: notification.account
|
||||||
const ownAccount = notification.account?.id === instanceAccount?.id
|
const ownAccount = notification.account?.id === instanceAccount?.id
|
||||||
const [spoilerExpanded, setSpoilerExpanded] = useState(
|
const [spoilerExpanded, setSpoilerExpanded] = useState(
|
||||||
instanceAccount.preferences['reading:expand:spoilers'] || false
|
instanceAccount.preferences?.['reading:expand:spoilers'] || false
|
||||||
)
|
)
|
||||||
const spoilerHidden = notification.status?.spoiler_text?.length
|
const spoilerHidden = notification.status?.spoiler_text?.length
|
||||||
? !instanceAccount.preferences['reading:expand:spoilers'] && !spoilerExpanded
|
? !instanceAccount.preferences?.['reading:expand:spoilers'] && !spoilerExpanded
|
||||||
: false
|
: false
|
||||||
const copiableContent = useRef<{ content: string; complete: boolean }>({
|
const copiableContent = useRef<{ content: string; complete: boolean }>({
|
||||||
content: '',
|
content: '',
|
||||||
|
@@ -31,10 +31,10 @@ const TimelineAttachment = () => {
|
|||||||
const account = useSelector(
|
const account = useSelector(
|
||||||
getInstanceAccount,
|
getInstanceAccount,
|
||||||
(prev, next) =>
|
(prev, next) =>
|
||||||
prev.preferences['reading:expand:media'] === next.preferences['reading:expand:media']
|
prev.preferences?.['reading:expand:media'] === next.preferences?.['reading:expand:media']
|
||||||
)
|
)
|
||||||
const defaultSensitive = () => {
|
const defaultSensitive = () => {
|
||||||
switch (account.preferences['reading:expand:media']) {
|
switch (account.preferences?.['reading:expand:media']) {
|
||||||
case 'show_all':
|
case 'show_all':
|
||||||
return false
|
return false
|
||||||
case 'hide_all':
|
case 'hide_all':
|
||||||
|
@@ -12,7 +12,8 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TimelineAvatar: React.FC<Props> = ({ account }) => {
|
const TimelineAvatar: React.FC<Props> = ({ account }) => {
|
||||||
const { status, highlighted, disableDetails, disableOnPress } = useContext(StatusContext)
|
const { status, highlighted, disableDetails, disableOnPress, isConversation } =
|
||||||
|
useContext(StatusContext)
|
||||||
const actualAccount = account || status?.account
|
const actualAccount = account || status?.account
|
||||||
if (!actualAccount) return null
|
if (!actualAccount) return null
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ const TimelineAvatar: React.FC<Props> = ({ account }) => {
|
|||||||
}
|
}
|
||||||
uri={{ original: actualAccount.avatar, static: actualAccount.avatar_static }}
|
uri={{ original: actualAccount.avatar, static: actualAccount.avatar_static }}
|
||||||
dimension={
|
dimension={
|
||||||
disableDetails
|
disableDetails || isConversation
|
||||||
? {
|
? {
|
||||||
width: StyleConstants.Avatar.XS,
|
width: StyleConstants.Avatar.XS,
|
||||||
height: StyleConstants.Avatar.XS
|
height: StyleConstants.Avatar.XS
|
||||||
@@ -47,7 +48,8 @@ const TimelineAvatar: React.FC<Props> = ({ account }) => {
|
|||||||
style={{
|
style={{
|
||||||
borderRadius: StyleConstants.Avatar.M,
|
borderRadius: StyleConstants.Avatar.M,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
marginRight: StyleConstants.Spacing.S
|
marginRight: StyleConstants.Spacing.S,
|
||||||
|
marginLeft: isConversation ? StyleConstants.Avatar.M - StyleConstants.Avatar.XS : undefined
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@@ -145,6 +145,7 @@ const TimelineCard: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<View style={{ flex: 1, padding: StyleConstants.Spacing.S }}>
|
<View style={{ flex: 1, padding: StyleConstants.Spacing.S }}>
|
||||||
|
{status.card?.title.length ? (
|
||||||
<CustomText
|
<CustomText
|
||||||
fontStyle='S'
|
fontStyle='S'
|
||||||
numberOfLines={2}
|
numberOfLines={2}
|
||||||
@@ -155,9 +156,10 @@ const TimelineCard: React.FC = () => {
|
|||||||
fontWeight='Bold'
|
fontWeight='Bold'
|
||||||
testID='title'
|
testID='title'
|
||||||
>
|
>
|
||||||
{status.card?.title}
|
{status.card.title}
|
||||||
</CustomText>
|
</CustomText>
|
||||||
{status.card?.description ? (
|
) : null}
|
||||||
|
{status.card?.description.length ? (
|
||||||
<CustomText
|
<CustomText
|
||||||
fontStyle='S'
|
fontStyle='S'
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
@@ -170,9 +172,11 @@ const TimelineCard: React.FC = () => {
|
|||||||
{status.card.description}
|
{status.card.description}
|
||||||
</CustomText>
|
</CustomText>
|
||||||
) : null}
|
) : null}
|
||||||
|
{status.card?.url.length ? (
|
||||||
<CustomText fontStyle='S' numberOfLines={1} style={{ color: colors.secondary }}>
|
<CustomText fontStyle='S' numberOfLines={1} style={{ color: colors.secondary }}>
|
||||||
{status.card?.url}
|
{status.card.url}
|
||||||
</CustomText>
|
</CustomText>
|
||||||
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
@@ -187,10 +191,6 @@ const TimelineCard: React.FC = () => {
|
|||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
minHeight:
|
|
||||||
(isStatus && foundStatus) || (isAccount && foundAccount)
|
|
||||||
? undefined
|
|
||||||
: StyleConstants.Font.LineHeight.M * 5,
|
|
||||||
marginTop: StyleConstants.Spacing.M,
|
marginTop: StyleConstants.Spacing.M,
|
||||||
borderWidth: StyleSheet.hairlineWidth,
|
borderWidth: StyleSheet.hairlineWidth,
|
||||||
borderRadius: StyleConstants.Spacing.S,
|
borderRadius: StyleConstants.Spacing.S,
|
||||||
|
@@ -47,7 +47,7 @@ const TimelineContent: React.FC<Props> = ({ notificationOwnToot = false, setSpoi
|
|||||||
mentions={status.mentions}
|
mentions={status.mentions}
|
||||||
tags={status.tags}
|
tags={status.tags}
|
||||||
numberOfLines={
|
numberOfLines={
|
||||||
instanceAccount.preferences['reading:expand:spoilers'] || inThread
|
instanceAccount.preferences?.['reading:expand:spoilers'] || inThread
|
||||||
? notificationOwnToot
|
? notificationOwnToot
|
||||||
? 2
|
? 2
|
||||||
: 999
|
: 999
|
||||||
|
@@ -14,11 +14,13 @@ type ContextType = {
|
|||||||
content: string
|
content: string
|
||||||
complete: boolean
|
complete: boolean
|
||||||
}>
|
}>
|
||||||
|
detectedLanguage?: React.MutableRefObject<string>
|
||||||
|
|
||||||
highlighted?: boolean
|
highlighted?: boolean
|
||||||
inThread?: boolean
|
inThread?: boolean
|
||||||
disableDetails?: boolean
|
disableDetails?: boolean
|
||||||
disableOnPress?: boolean
|
disableOnPress?: boolean
|
||||||
|
isConversation?: boolean
|
||||||
}
|
}
|
||||||
const StatusContext = createContext<ContextType>({} as ContextType)
|
const StatusContext = createContext<ContextType>({} as ContextType)
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ import { StyleSheet, View } from 'react-native'
|
|||||||
import StatusContext from './Context'
|
import StatusContext from './Context'
|
||||||
|
|
||||||
const TimelineFeedback = () => {
|
const TimelineFeedback = () => {
|
||||||
const { status, highlighted } = useContext(StatusContext)
|
const { status, highlighted, detectedLanguage } = useContext(StatusContext)
|
||||||
if (!status || !highlighted) return null
|
if (!status || !highlighted) return null
|
||||||
|
|
||||||
const { t } = useTranslation('componentTimeline')
|
const { t } = useTranslation('componentTimeline')
|
||||||
@@ -80,7 +80,12 @@ const TimelineFeedback = () => {
|
|||||||
accessibilityHint={t('shared.actionsUsers.history.accessibilityHint')}
|
accessibilityHint={t('shared.actionsUsers.history.accessibilityHint')}
|
||||||
accessibilityRole='button'
|
accessibilityRole='button'
|
||||||
style={[styles.text, { marginRight: 0, color: colors.blue }]}
|
style={[styles.text, { marginRight: 0, color: colors.blue }]}
|
||||||
onPress={() => navigation.push('Tab-Shared-History', { id: status.id })}
|
onPress={() =>
|
||||||
|
navigation.push('Tab-Shared-History', {
|
||||||
|
id: status.id,
|
||||||
|
detectedLanguage: detectedLanguage?.current || status.language || ''
|
||||||
|
})
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{t('shared.actionsUsers.history.text', {
|
{t('shared.actionsUsers.history.text', {
|
||||||
count: data.length - 1
|
count: data.length - 1
|
||||||
|
@@ -36,7 +36,12 @@ const TimelineHeaderAndroid: React.FC = () => {
|
|||||||
{queryKey ? (
|
{queryKey ? (
|
||||||
<DropdownMenu.Root onOpenChange={setOpenChange}>
|
<DropdownMenu.Root onOpenChange={setOpenChange}>
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
<View style={{ padding: StyleConstants.Spacing.L }}>
|
<View
|
||||||
|
style={{
|
||||||
|
padding: StyleConstants.Spacing.L,
|
||||||
|
backgroundColor: colors.backgroundDefault
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Icon
|
<Icon
|
||||||
name='MoreHorizontal'
|
name='MoreHorizontal'
|
||||||
color={colors.secondary}
|
color={colors.secondary}
|
||||||
|
@@ -65,7 +65,7 @@ const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => {
|
|||||||
`https://${url}/admin/reports/${notification.report.id}`,
|
`https://${url}/admin/reports/${notification.report.id}`,
|
||||||
'tooot://tooot',
|
'tooot://tooot',
|
||||||
{
|
{
|
||||||
browserPackage: await browserPackage(),
|
...(await browserPackage()),
|
||||||
dismissButtonStyle: 'done',
|
dismissButtonStyle: 'done',
|
||||||
readerMode: false
|
readerMode: false
|
||||||
}
|
}
|
||||||
|
@@ -7,12 +7,13 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { View } from 'react-native'
|
import { View } from 'react-native'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
account: Mastodon.Account
|
account?: Mastodon.Account
|
||||||
withoutName?: boolean // For notification follow request etc.
|
withoutName?: boolean // For notification follow request etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeaderSharedAccount = React.memo(
|
const HeaderSharedAccount: React.FC<Props> = ({ account, withoutName = false }) => {
|
||||||
({ account, withoutName = false }: Props) => {
|
if (!account) return null
|
||||||
|
|
||||||
const { t } = useTranslation('componentTimeline')
|
const { t } = useTranslation('componentTimeline')
|
||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
|
|
||||||
@@ -25,8 +26,8 @@ const HeaderSharedAccount = React.memo(
|
|||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
>
|
>
|
||||||
<ParseEmojis
|
<ParseEmojis
|
||||||
content={account?.display_name || account?.username}
|
content={account.display_name || account.username}
|
||||||
emojis={account?.emojis}
|
emojis={account.emojis}
|
||||||
fontBold
|
fontBold
|
||||||
/>
|
/>
|
||||||
</CustomText>
|
</CustomText>
|
||||||
@@ -40,8 +41,6 @@ const HeaderSharedAccount = React.memo(
|
|||||||
</CustomText>
|
</CustomText>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
() => true
|
|
||||||
)
|
|
||||||
|
|
||||||
export default HeaderSharedAccount
|
export default HeaderSharedAccount
|
||||||
|
@@ -13,7 +13,7 @@ import { Circle } from 'react-native-animated-spinkit'
|
|||||||
import StatusContext from './Context'
|
import StatusContext from './Context'
|
||||||
|
|
||||||
const TimelineTranslate = () => {
|
const TimelineTranslate = () => {
|
||||||
const { status, highlighted, copiableContent } = useContext(StatusContext)
|
const { status, highlighted, copiableContent, detectedLanguage } = useContext(StatusContext)
|
||||||
if (!status || !highlighted) return null
|
if (!status || !highlighted) return null
|
||||||
|
|
||||||
const { t } = useTranslation('componentTimeline')
|
const { t } = useTranslation('componentTimeline')
|
||||||
@@ -38,14 +38,19 @@ const TimelineTranslate = () => {
|
|||||||
? [copiableContent?.current.content]
|
? [copiableContent?.current.content]
|
||||||
: backupTextProcessing()
|
: backupTextProcessing()
|
||||||
|
|
||||||
const [detectedLanguage, setDetectedLanguage] = useState<{
|
const [detected, setDetected] = useState<{
|
||||||
language: string
|
language: string
|
||||||
confidence: number
|
confidence: number
|
||||||
}>({ language: status.language || '', confidence: 0 })
|
}>({ language: status.language || '', confidence: 0 })
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const detect = async () => {
|
const detect = async () => {
|
||||||
const result = await detectLanguage(text.join('\n\n'))
|
const result = await detectLanguage(text.join('\n\n'))
|
||||||
result && setDetectedLanguage(result)
|
if (result) {
|
||||||
|
setDetected(result)
|
||||||
|
if (detectedLanguage) {
|
||||||
|
detectedLanguage.current = result.language
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
detect()
|
detect()
|
||||||
}, [])
|
}, [])
|
||||||
@@ -57,7 +62,7 @@ const TimelineTranslate = () => {
|
|||||||
|
|
||||||
const [enabled, setEnabled] = useState(false)
|
const [enabled, setEnabled] = useState(false)
|
||||||
const { refetch, data, isFetching, isSuccess, isError } = useTranslateQuery({
|
const { refetch, data, isFetching, isSuccess, isError } = useTranslateQuery({
|
||||||
source: detectedLanguage.language,
|
source: detected.language,
|
||||||
target: targetLanguage,
|
target: targetLanguage,
|
||||||
text,
|
text,
|
||||||
options: { enabled }
|
options: { enabled }
|
||||||
@@ -66,9 +71,9 @@ const TimelineTranslate = () => {
|
|||||||
const devView = () => {
|
const devView = () => {
|
||||||
return __DEV__ ? (
|
return __DEV__ ? (
|
||||||
<CustomText fontStyle='S' style={{ color: colors.secondary }}>{` Source: ${
|
<CustomText fontStyle='S' style={{ color: colors.secondary }}>{` Source: ${
|
||||||
detectedLanguage?.language
|
detected?.language
|
||||||
}; Confidence: ${
|
}; Confidence: ${
|
||||||
detectedLanguage?.confidence.toString().slice(0, 5) || 'null'
|
detected?.confidence.toString().slice(0, 5) || 'null'
|
||||||
}; Target: ${targetLanguage}`}</CustomText>
|
}; Target: ${targetLanguage}`}</CustomText>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
@@ -78,13 +83,13 @@ const TimelineTranslate = () => {
|
|||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
Platform.OS === 'ios' &&
|
Platform.OS === 'ios' &&
|
||||||
Localization.locale.slice(0, 2).includes(detectedLanguage.language.slice(0, 2))
|
Localization.locale.slice(0, 2).includes(detected.language.slice(0, 2))
|
||||||
) {
|
) {
|
||||||
return devView()
|
return devView()
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
Platform.OS === 'android' &&
|
Platform.OS === 'android' &&
|
||||||
settingsLanguage?.slice(0, 2).includes(detectedLanguage.language.slice(0, 2))
|
settingsLanguage?.slice(0, 2).includes(detected.language.slice(0, 2))
|
||||||
) {
|
) {
|
||||||
return devView()
|
return devView()
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,7 @@ const menuAccount = ({
|
|||||||
|
|
||||||
const menus: ContextMenu[][] = [[]]
|
const menus: ContextMenu[][] = [[]]
|
||||||
|
|
||||||
const instanceAccount = useSelector(getInstanceAccount, (prev, next) => prev.id === next.id)
|
const instanceAccount = useSelector(getInstanceAccount)
|
||||||
const ownAccount = instanceAccount?.id === account.id
|
const ownAccount = instanceAccount?.id === account.id
|
||||||
|
|
||||||
const [enabled, setEnabled] = useState(openChange)
|
const [enabled, setEnabled] = useState(openChange)
|
||||||
|
@@ -17,7 +17,6 @@ const openLink = async (url: string, navigation?: any) => {
|
|||||||
|
|
||||||
const handleNavigation = (page: 'Tab-Shared-Toot' | 'Tab-Shared-Account', options: {}) => {
|
const handleNavigation = (page: 'Tab-Shared-Toot' | 'Tab-Shared-Account', options: {}) => {
|
||||||
if (navigation) {
|
if (navigation) {
|
||||||
// @ts-ignore
|
|
||||||
navigation.push(page, options)
|
navigation.push(page, options)
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -93,7 +92,7 @@ const openLink = async (url: string, navigation?: any) => {
|
|||||||
await WebBrowser.openBrowserAsync(encodeURI(url), {
|
await WebBrowser.openBrowserAsync(encodeURI(url), {
|
||||||
dismissButtonStyle: 'close',
|
dismissButtonStyle: 'close',
|
||||||
enableBarCollapsing: true,
|
enableBarCollapsing: true,
|
||||||
browserPackage: await browserPackage()
|
...(await browserPackage())
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'external':
|
case 'external':
|
||||||
|
@@ -1,16 +1,18 @@
|
|||||||
import * as WebBrowser from 'expo-web-browser'
|
import * as WebBrowser from 'expo-web-browser'
|
||||||
import { Platform } from 'react-native'
|
import { Platform } from 'react-native'
|
||||||
|
|
||||||
const browserPackage = async () => {
|
const browserPackage = async (): Promise<{ browserPackage?: string }> => {
|
||||||
let browserPackage: string | undefined
|
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
const tabsSupportingBrowsers = await WebBrowser.getCustomTabsSupportingBrowsersAsync()
|
const tabsSupportingBrowsers = await WebBrowser.getCustomTabsSupportingBrowsersAsync()
|
||||||
browserPackage =
|
return {
|
||||||
|
browserPackage:
|
||||||
tabsSupportingBrowsers?.preferredBrowserPackage ||
|
tabsSupportingBrowsers?.preferredBrowserPackage ||
|
||||||
tabsSupportingBrowsers.browserPackages[0] ||
|
tabsSupportingBrowsers.browserPackages[0] ||
|
||||||
tabsSupportingBrowsers.servicePackages[0]
|
tabsSupportingBrowsers.servicePackages[0]
|
||||||
}
|
}
|
||||||
return browserPackage
|
} else {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default browserPackage
|
export default browserPackage
|
||||||
|
@@ -1,47 +1,46 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"feature": "account_follow_notify",
|
||||||
|
"version": 3.3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"feature": "notification_type_status",
|
||||||
|
"version": 3.3
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"feature": "account_return_suspended",
|
"feature": "account_return_suspended",
|
||||||
"version": 3.3,
|
"version": 3.3
|
||||||
"reference": "https://github.com/mastodon/mastodon/releases/tag/v3.3.0"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"feature": "edit_post",
|
"feature": "edit_post",
|
||||||
"version": 3.5,
|
"version": 3.5
|
||||||
"reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"feature": "deprecate_auth_follow",
|
"feature": "deprecate_auth_follow",
|
||||||
"version": 3.5,
|
"version": 3.5
|
||||||
"reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"feature": "notification_type_update",
|
"feature": "notification_type_update",
|
||||||
"version": 3.5,
|
"version": 3.5
|
||||||
"reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"feature": "notification_type_admin_signup",
|
"feature": "notification_type_admin_signup",
|
||||||
"version": 3.5,
|
"version": 3.5
|
||||||
"reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"feature": "notification_types_positive_filter",
|
"feature": "notification_types_positive_filter",
|
||||||
"version": 3.5,
|
"version": 3.5
|
||||||
"reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"feature": "trends_new_path",
|
"feature": "trends_new_path",
|
||||||
"version": 3.5,
|
"version": 3.5
|
||||||
"reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"feature": "follow_tags",
|
"feature": "follow_tags",
|
||||||
"version": 4.0,
|
"version": 4.0
|
||||||
"reference": "https://github.com/mastodon/mastodon/releases/tag/v4.0.0"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"feature": "notification_type_admin_report",
|
"feature": "notification_type_admin_report",
|
||||||
"version": 4.0,
|
"version": 4.0
|
||||||
"reference": "https://github.com/mastodon/mastodon/releases/tag/v3.5.0"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Publicació d'usuaris subscrits"
|
"heading": "Publicació d'usuaris subscrits"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "L'impuls ha sigut editat"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "Administració: Registra"
|
"heading": "Administració: Registra"
|
||||||
},
|
},
|
||||||
@@ -348,7 +351,7 @@
|
|||||||
"notInLists": "Altres llistes"
|
"notInLists": "Altres llistes"
|
||||||
},
|
},
|
||||||
"attachments": {
|
"attachments": {
|
||||||
"name": ""
|
"name": "Multimèdia de <0 /><1></1>"
|
||||||
},
|
},
|
||||||
"hashtag": {
|
"hashtag": {
|
||||||
"follow": "Segueix",
|
"follow": "Segueix",
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} impulsats",
|
"reblogged_by": "{{count}} impulsats",
|
||||||
"favourited_by": "{{count}} favorits"
|
"favourited_by": "{{count}} favorits"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "",
|
"reblogged_by": "",
|
||||||
"favourited_by": ""
|
"favourited_by": ""
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -55,7 +55,7 @@
|
|||||||
"accessibilityLabel": "Lesezeichen hinzufügen",
|
"accessibilityLabel": "Lesezeichen hinzufügen",
|
||||||
"function": "Lesezeichen setzen"
|
"function": "Lesezeichen setzen"
|
||||||
},
|
},
|
||||||
"openReport": ""
|
"openReport": "Meldung öffnen"
|
||||||
},
|
},
|
||||||
"actionsUsers": {
|
"actionsUsers": {
|
||||||
"reblogged_by": {
|
"reblogged_by": {
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
"local": {
|
"local": {
|
||||||
"name": "Gefolgt",
|
"name": "Gefolgt",
|
||||||
"options": {
|
"options": {
|
||||||
"showBoosts": "",
|
"showBoosts": "Boosts anzeigen",
|
||||||
"showReplies": ""
|
"showReplies": "Antworten anzeigen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"public": {
|
"public": {
|
||||||
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Toot eines abonnierten Nutzers"
|
"heading": "Toot eines abonnierten Nutzers"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "Boost wurde bearbeitet"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "Admin: Registrierung"
|
"heading": "Admin: Registrierung"
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} mal geboosted",
|
"reblogged_by": "{{count}} mal geboosted",
|
||||||
"favourited_by": "{{count}} mal geherzt"
|
"favourited_by": "{{count}} mal geherzt"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": "Ergebnisse einer Instanz sind unvollständig"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -3,6 +3,7 @@
|
|||||||
"textInput": {
|
"textInput": {
|
||||||
"placeholder": "Instance's domain"
|
"placeholder": "Instance's domain"
|
||||||
},
|
},
|
||||||
|
"whitelisted": "This may be a whitelisted instance that tooot cannot retrieve data from before logging in.",
|
||||||
"button": "Login",
|
"button": "Login",
|
||||||
"information": {
|
"information": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Toot from subscribed users"
|
"heading": "Toot from subscribed users"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "Reblog has been edited"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "Admin: sign up"
|
"heading": "Admin: sign up"
|
||||||
},
|
},
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
"local": {
|
"local": {
|
||||||
"name": "Siguiendo",
|
"name": "Siguiendo",
|
||||||
"options": {
|
"options": {
|
||||||
"showBoosts": "",
|
"showBoosts": "Mostrar retoots",
|
||||||
"showReplies": ""
|
"showReplies": "Mostrar respuestas"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"public": {
|
"public": {
|
||||||
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Toot de usuarios suscritos"
|
"heading": "Toot de usuarios suscritos"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "El impulso ha sido editado"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "Administración: Registrarse"
|
"heading": "Administración: Registrarse"
|
||||||
},
|
},
|
||||||
@@ -348,7 +351,7 @@
|
|||||||
"notInLists": "Otras listas"
|
"notInLists": "Otras listas"
|
||||||
},
|
},
|
||||||
"attachments": {
|
"attachments": {
|
||||||
"name": ""
|
"name": "Multimedia de <0 /><1></1>"
|
||||||
},
|
},
|
||||||
"hashtag": {
|
"hashtag": {
|
||||||
"follow": "Seguir",
|
"follow": "Seguir",
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} impulsados",
|
"reblogged_by": "{{count}} impulsados",
|
||||||
"favourited_by": "{{count}} favoritos"
|
"favourited_by": "{{count}} favoritos"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Pouet des utilisateurs inscrits"
|
"heading": "Pouet des utilisateurs inscrits"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} boosté",
|
"reblogged_by": "{{count}} boosté",
|
||||||
"favourited_by": "{{count}} mis en favori"
|
"favourited_by": "{{count}} mis en favori"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Toot da utenti seguiti"
|
"heading": "Toot da utenti seguiti"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "Il link è stato modificato"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
@@ -348,7 +351,7 @@
|
|||||||
"notInLists": ""
|
"notInLists": ""
|
||||||
},
|
},
|
||||||
"attachments": {
|
"attachments": {
|
||||||
"name": ""
|
"name": "Media di <0 /><1>\"</1>"
|
||||||
},
|
},
|
||||||
"hashtag": {
|
"hashtag": {
|
||||||
"follow": "Segui",
|
"follow": "Segui",
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} ricondivisioni",
|
"reblogged_by": "{{count}} ricondivisioni",
|
||||||
"favourited_by": "{{count}} apprezzamenti"
|
"favourited_by": "{{count}} apprezzamenti"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "購読したユーザーのトゥート"
|
"heading": "購読したユーザーのトゥート"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "ブーストしたトゥートが編集されました"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} ブースト",
|
"reblogged_by": "{{count}} ブースト",
|
||||||
"favourited_by": "{{count}} お気に入り"
|
"favourited_by": "{{count}} お気に入り"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -70,7 +70,7 @@
|
|||||||
"name": "{{list}} 리스트의 사용자"
|
"name": "{{list}} 리스트의 사용자"
|
||||||
},
|
},
|
||||||
"listAdd": {
|
"listAdd": {
|
||||||
"name": ""
|
"name": "목록 만들기"
|
||||||
},
|
},
|
||||||
"listEdit": {
|
"listEdit": {
|
||||||
"name": "리스트 상세 편집"
|
"name": "리스트 상세 편집"
|
||||||
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "구독한 사용자의 툿"
|
"heading": "구독한 사용자의 툿"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "부스트한 툿이 수정됨"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
@@ -348,7 +351,7 @@
|
|||||||
"notInLists": "다른 리스트"
|
"notInLists": "다른 리스트"
|
||||||
},
|
},
|
||||||
"attachments": {
|
"attachments": {
|
||||||
"name": ""
|
"name": "<0 /><1>의 미디어</1>"
|
||||||
},
|
},
|
||||||
"hashtag": {
|
"hashtag": {
|
||||||
"follow": "팔로우",
|
"follow": "팔로우",
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} 부스트",
|
"reblogged_by": "{{count}} 부스트",
|
||||||
"favourited_by": "{{count}} 즐겨찾기"
|
"favourited_by": "{{count}} 즐겨찾기"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -3,8 +3,8 @@
|
|||||||
"local": {
|
"local": {
|
||||||
"name": "Volgend",
|
"name": "Volgend",
|
||||||
"options": {
|
"options": {
|
||||||
"showBoosts": "",
|
"showBoosts": "Boosts tonen",
|
||||||
"showReplies": ""
|
"showReplies": "Reacties tonen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"public": {
|
"public": {
|
||||||
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Toot van geabonneerde gebruikers"
|
"heading": "Toot van geabonneerde gebruikers"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "De reblog is bewerkt"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "Admin: registreren"
|
"heading": "Admin: registreren"
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} boostten",
|
"reblogged_by": "{{count}} boostten",
|
||||||
"favourited_by": "{{count}} markeerden als favoriet"
|
"favourited_by": "{{count}} markeerden als favoriet"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": "Resultaten van een externe instantie zijn onvolledig"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -8,58 +8,58 @@
|
|||||||
},
|
},
|
||||||
"inLists": "",
|
"inLists": "",
|
||||||
"mute": {
|
"mute": {
|
||||||
"action_false": "",
|
"action_false": "Wycisz użytkownika",
|
||||||
"action_true": ""
|
"action_true": "Wyłącz wyciszenie"
|
||||||
},
|
},
|
||||||
"block": {
|
"block": {
|
||||||
"action_false": "",
|
"action_false": "Zablokuj użytkownika",
|
||||||
"action_true": ""
|
"action_true": "Odblokuj użytkownika"
|
||||||
},
|
},
|
||||||
"reports": {
|
"reports": {
|
||||||
"action": "Zgłoś i zablokuj"
|
"action": "Zgłoś i zablokuj"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"at": {
|
"at": {
|
||||||
"direct": "",
|
"direct": "Bezpośrednia wiadomość",
|
||||||
"public": ""
|
"public": "Wiadomość publiczna"
|
||||||
},
|
},
|
||||||
"copy": {
|
"copy": {
|
||||||
"action": "",
|
"action": "Skopiuj wpis",
|
||||||
"succeed": ""
|
"succeed": "Skopiowano"
|
||||||
},
|
},
|
||||||
"instance": {
|
"instance": {
|
||||||
"title": "",
|
"title": "",
|
||||||
"block": {
|
"block": {
|
||||||
"action": "",
|
"action": "Zablokuj instancję {{instance}}",
|
||||||
"alert": {
|
"alert": {
|
||||||
"title": "",
|
"title": "Na pewno zablokować {{instance}}?",
|
||||||
"message": "",
|
"message": "Zazwyczaj wycisza się (albo blokuje) konkretnych użytkowników. \n\nGdy zablokujesz instancję, cała jej zawartość (włączając np. obserwujące Cię osoby, które do niej należą) zostanie usunięta!",
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"confirm": ""
|
"confirm": "Na pewno?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"share": {
|
"share": {
|
||||||
"status": {
|
"status": {
|
||||||
"action": ""
|
"action": "Udostępnij wpis"
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
"action": ""
|
"action": "Udostępnij konto"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"title": "",
|
"title": "",
|
||||||
"edit": {
|
"edit": {
|
||||||
"action": ""
|
"action": "Edytuj wpis"
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"action": "",
|
"action": "Usuń wpis",
|
||||||
"alert": {
|
"alert": {
|
||||||
"title": "",
|
"title": "Na pewno usunąć?",
|
||||||
"message": "",
|
"message": "Wszystkie podbite i polubione wpisy zostaną wyczyszczone - wraz z odpowiedziami.",
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"confirm": ""
|
"confirm": "Na pewno?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -78,8 +78,8 @@
|
|||||||
"action_true": ""
|
"action_true": ""
|
||||||
},
|
},
|
||||||
"pin": {
|
"pin": {
|
||||||
"action_false": "",
|
"action_false": "Przypnij wpis",
|
||||||
"action_true": ""
|
"action_true": "Odepnij wpis"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -3,8 +3,8 @@
|
|||||||
"local": {
|
"local": {
|
||||||
"name": "",
|
"name": "",
|
||||||
"options": {
|
"options": {
|
||||||
"showBoosts": "",
|
"showBoosts": "Pokaż podbicia",
|
||||||
"showReplies": ""
|
"showReplies": "Pokaż odpowiedzi"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"public": {
|
"public": {
|
||||||
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": ""
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "",
|
"reblogged_by": "",
|
||||||
"favourited_by": ""
|
"favourited_by": ""
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Toot de usuários inscritos"
|
"heading": "Toot de usuários inscritos"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "Toot foi editado"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": ""
|
"heading": ""
|
||||||
},
|
},
|
||||||
@@ -348,7 +351,7 @@
|
|||||||
"notInLists": ""
|
"notInLists": ""
|
||||||
},
|
},
|
||||||
"attachments": {
|
"attachments": {
|
||||||
"name": ""
|
"name": "<0 /><1>\"s mídia</1>"
|
||||||
},
|
},
|
||||||
"hashtag": {
|
"hashtag": {
|
||||||
"follow": "Seguir",
|
"follow": "Seguir",
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} boostou",
|
"reblogged_by": "{{count}} boostou",
|
||||||
"favourited_by": "{{count}} favoritados"
|
"favourited_by": "{{count}} favoritados"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Inlägg från följda användare"
|
"heading": "Inlägg från följda användare"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "Boosten har redigerats"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "Admin: registrera dig"
|
"heading": "Admin: registrera dig"
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} boostade",
|
"reblogged_by": "{{count}} boostade",
|
||||||
"favourited_by": "{{count}} favoriter"
|
"favourited_by": "{{count}} favoriter"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": "Resultat från fjärrinstans är ofullständiga"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Дмух від підписників"
|
"heading": "Дмух від підписників"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "Передмух був відредагований"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "Адмін: реєстрація"
|
"heading": "Адмін: реєстрація"
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} передмухів",
|
"reblogged_by": "{{count}} передмухів",
|
||||||
"favourited_by": "{{count}} улюблених"
|
"favourited_by": "{{count}} улюблених"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": "Результати з віддаленого інстанса неповні"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -3,8 +3,8 @@
|
|||||||
"local": {
|
"local": {
|
||||||
"name": "Đang theo dõi",
|
"name": "Đang theo dõi",
|
||||||
"options": {
|
"options": {
|
||||||
"showBoosts": "",
|
"showBoosts": "Hiện lượt đăng lại",
|
||||||
"showReplies": ""
|
"showReplies": "Hiện lượt trả lời"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"public": {
|
"public": {
|
||||||
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "Tút từ người đã theo dõi"
|
"heading": "Tút từ người đã theo dõi"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "Đăng lại đã được sửa"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "Admin: đăng ký"
|
"heading": "Admin: đăng ký"
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} đăng lại",
|
"reblogged_by": "{{count}} đăng lại",
|
||||||
"favourited_by": "{{count}} thích"
|
"favourited_by": "{{count}} thích"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": "Kết quả từ máy chủ khác luôn không đầy đủ"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -231,6 +231,9 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "订阅用户的嘟文"
|
"heading": "订阅用户的嘟文"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "转嘟被编辑"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "管理员:用户注册"
|
"heading": "管理员:用户注册"
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} 人转嘟",
|
"reblogged_by": "{{count}} 人转嘟",
|
||||||
"favourited_by": "{{count}} 人喜欢"
|
"favourited_by": "{{count}} 人喜欢"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": "来自远程实例的结果不完整"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -31,8 +31,8 @@
|
|||||||
"notification": "{{name}} 轉嘟了您的嘟文"
|
"notification": "{{name}} 轉嘟了您的嘟文"
|
||||||
},
|
},
|
||||||
"update": "轉嘟已編輯",
|
"update": "轉嘟已編輯",
|
||||||
"admin.sign_up": "",
|
"admin.sign_up": "{{name}} 加入了站點",
|
||||||
"admin.report": ""
|
"admin.report": "{{name}} 檢舉:"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"reply": {
|
"reply": {
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
"accessibilityLabel": "將嘟文加入書籤",
|
"accessibilityLabel": "將嘟文加入書籤",
|
||||||
"function": "加入書籤"
|
"function": "加入書籤"
|
||||||
},
|
},
|
||||||
"openReport": ""
|
"openReport": "打開檢舉"
|
||||||
},
|
},
|
||||||
"actionsUsers": {
|
"actionsUsers": {
|
||||||
"reblogged_by": {
|
"reblogged_by": {
|
||||||
|
@@ -3,8 +3,8 @@
|
|||||||
"local": {
|
"local": {
|
||||||
"name": "跟隨中",
|
"name": "跟隨中",
|
||||||
"options": {
|
"options": {
|
||||||
"showBoosts": "",
|
"showBoosts": "顯示轉嘟",
|
||||||
"showReplies": ""
|
"showReplies": "顯示回覆"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"public": {
|
"public": {
|
||||||
@@ -231,11 +231,14 @@
|
|||||||
"status": {
|
"status": {
|
||||||
"heading": "訂閱使用者的嘟文"
|
"heading": "訂閱使用者的嘟文"
|
||||||
},
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "轉嘟被編輯"
|
||||||
|
},
|
||||||
"admin.sign_up": {
|
"admin.sign_up": {
|
||||||
"heading": "管理員:註冊"
|
"heading": "管理員:使用者註冊"
|
||||||
},
|
},
|
||||||
"admin.report": {
|
"admin.report": {
|
||||||
"heading": "管理員:回報"
|
"heading": "管理員:檢舉"
|
||||||
},
|
},
|
||||||
"howitworks": "了解通知訊息轉發如何工作"
|
"howitworks": "了解通知訊息轉發如何工作"
|
||||||
},
|
},
|
||||||
@@ -395,7 +398,8 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"reblogged_by": "{{count}} 人轉嘟",
|
"reblogged_by": "{{count}} 人轉嘟",
|
||||||
"favourited_by": "{{count}} 人喜歡"
|
"favourited_by": "{{count}} 人喜歡"
|
||||||
}
|
},
|
||||||
|
"resultIncomplete": "來自遠端站點的結果不完整"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -286,7 +286,7 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
|
|||||||
type: 'editItem',
|
type: 'editItem',
|
||||||
queryKey: params.queryKey,
|
queryKey: params.queryKey,
|
||||||
rootQueryKey: params.rootQueryKey,
|
rootQueryKey: params.rootQueryKey,
|
||||||
status: res.body
|
status: res
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'deleteEdit':
|
case 'deleteEdit':
|
||||||
|
@@ -7,9 +7,8 @@ import { ComposeState } from './types'
|
|||||||
const assignVisibility = (
|
const assignVisibility = (
|
||||||
target: ComposeState['visibility']
|
target: ComposeState['visibility']
|
||||||
): Pick<ComposeState, 'visibility' | 'visibilityLock'> => {
|
): Pick<ComposeState, 'visibility' | 'visibilityLock'> => {
|
||||||
const accountPreference = getInstanceAccount(store.getState())?.preferences[
|
const accountPreference =
|
||||||
'posting:default:visibility'
|
getInstanceAccount(store.getState())?.preferences?.['posting:default:visibility'] || 'public'
|
||||||
]
|
|
||||||
|
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case 'direct':
|
case 'direct':
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import apiInstance, { InstanceResponse } from '@api/instance'
|
import apiInstance from '@api/instance'
|
||||||
import detectLanguage from '@helpers/detectLanguage'
|
import detectLanguage from '@helpers/detectLanguage'
|
||||||
import { ComposeState } from '@screens/Compose/utils/types'
|
import { ComposeState } from '@screens/Compose/utils/types'
|
||||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||||
@@ -8,7 +8,7 @@ import { getPureContent } from './processText'
|
|||||||
const composePost = async (
|
const composePost = async (
|
||||||
params: RootStackParamList['Screen-Compose'],
|
params: RootStackParamList['Screen-Compose'],
|
||||||
composeState: ComposeState
|
composeState: ComposeState
|
||||||
): Promise<InstanceResponse<Mastodon.Status>> => {
|
): Promise<Mastodon.Status> => {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
|
|
||||||
const detectedLanguage = await detectLanguage(
|
const detectedLanguage = await detectLanguage(
|
||||||
@@ -74,7 +74,7 @@ const composePost = async (
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
body: formData
|
body: formData
|
||||||
})
|
}).then(res => res.body)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default composePost
|
export default composePost
|
||||||
|
@@ -16,7 +16,6 @@ import {
|
|||||||
ViewToken
|
ViewToken
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import { Directions, Gesture, LongPressGestureHandler } from 'react-native-gesture-handler'
|
import { Directions, Gesture, LongPressGestureHandler } from 'react-native-gesture-handler'
|
||||||
import { LiveTextImageView } from 'react-native-live-text-image-view'
|
|
||||||
import { runOnJS, useSharedValue } from 'react-native-reanimated'
|
import { runOnJS, useSharedValue } from 'react-native-reanimated'
|
||||||
import { Zoom, createZoomListComponent } from 'react-native-reanimated-zoom'
|
import { Zoom, createZoomListComponent } from 'react-native-reanimated-zoom'
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||||
@@ -117,10 +116,8 @@ const ScreenImagesViewer = ({
|
|||||||
justifyContent: 'center'
|
justifyContent: 'center'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<LiveTextImageView>
|
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{ preview: item.preview_url, remote: item.remote_url, original: item.url }}
|
uri={{ preview: item.preview_url, remote: item.remote_url, original: item.url }}
|
||||||
blurhash={item.blurhash}
|
|
||||||
dimension={{
|
dimension={{
|
||||||
width:
|
width:
|
||||||
screenRatio > imageRatio
|
screenRatio > imageRatio
|
||||||
@@ -132,7 +129,6 @@ const ScreenImagesViewer = ({
|
|||||||
: (SCREEN_WIDTH / imageWidth) * imageHeight
|
: (SCREEN_WIDTH / imageWidth) * imageHeight
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</LiveTextImageView>
|
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@@ -3,13 +3,17 @@ import Icon from '@components/Icon'
|
|||||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||||
import CustomText from '@components/Text'
|
import CustomText from '@components/Text'
|
||||||
import browserPackage from '@helpers/browserPackage'
|
import browserPackage from '@helpers/browserPackage'
|
||||||
import { checkPermission } from '@helpers/permissions'
|
|
||||||
import { useAppDispatch } from '@root/store'
|
import { useAppDispatch } from '@root/store'
|
||||||
import { isDevelopment } from '@utils/checkEnvironment'
|
import { isDevelopment } from '@utils/checkEnvironment'
|
||||||
import { useAppsQuery } from '@utils/queryHooks/apps'
|
import { useAppsQuery } from '@utils/queryHooks/apps'
|
||||||
import { useProfileQuery } from '@utils/queryHooks/profile'
|
import { useProfileQuery } from '@utils/queryHooks/profile'
|
||||||
import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
|
import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
|
||||||
import { PUSH_ADMIN, PUSH_DEFAULT, setChannels } from '@utils/slices/instances/push/utils'
|
import {
|
||||||
|
PUSH_ADMIN,
|
||||||
|
PUSH_DEFAULT,
|
||||||
|
setChannels,
|
||||||
|
usePushFeatures
|
||||||
|
} from '@utils/slices/instances/push/utils'
|
||||||
import { updateInstancePush } from '@utils/slices/instances/updatePush'
|
import { updateInstancePush } from '@utils/slices/instances/updatePush'
|
||||||
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
|
import { updateInstancePushAlert } from '@utils/slices/instances/updatePushAlert'
|
||||||
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
|
import { updateInstancePushDecode } from '@utils/slices/instances/updatePushDecode'
|
||||||
@@ -73,9 +77,11 @@ const TabMePush: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [appsQuery.data?.vapid_key])
|
}, [appsQuery.data?.vapid_key])
|
||||||
|
|
||||||
|
const pushFeatures = usePushFeatures()
|
||||||
|
|
||||||
const alerts = () =>
|
const alerts = () =>
|
||||||
instancePush?.alerts
|
instancePush?.alerts
|
||||||
? PUSH_DEFAULT.map(alert => (
|
? PUSH_DEFAULT(pushFeatures).map(alert => (
|
||||||
<MenuRow
|
<MenuRow
|
||||||
key={alert}
|
key={alert}
|
||||||
title={t(`me.push.${alert}.heading`)}
|
title={t(`me.push.${alert}.heading`)}
|
||||||
@@ -86,7 +92,7 @@ const TabMePush: React.FC = () => {
|
|||||||
updateInstancePushAlert({
|
updateInstancePushAlert({
|
||||||
alerts: {
|
alerts: {
|
||||||
...instancePush?.alerts,
|
...instancePush?.alerts,
|
||||||
[alert]: instancePush?.alerts[alert]
|
[alert]: !instancePush?.alerts[alert]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -98,8 +104,7 @@ const TabMePush: React.FC = () => {
|
|||||||
const profileQuery = useProfileQuery()
|
const profileQuery = useProfileQuery()
|
||||||
const adminAlerts = () =>
|
const adminAlerts = () =>
|
||||||
profileQuery.data?.role?.permissions
|
profileQuery.data?.role?.permissions
|
||||||
? PUSH_ADMIN.map(({ type, permission }) =>
|
? PUSH_ADMIN(pushFeatures, profileQuery.data?.role?.permissions).map(({ type }) => (
|
||||||
checkPermission(permission, profileQuery.data.role?.permissions) ? (
|
|
||||||
<MenuRow
|
<MenuRow
|
||||||
key={type}
|
key={type}
|
||||||
title={t(`me.push.${type}.heading`)}
|
title={t(`me.push.${type}.heading`)}
|
||||||
@@ -110,14 +115,13 @@ const TabMePush: React.FC = () => {
|
|||||||
updateInstancePushAlert({
|
updateInstancePushAlert({
|
||||||
alerts: {
|
alerts: {
|
||||||
...instancePush?.alerts,
|
...instancePush?.alerts,
|
||||||
[type]: instancePush?.alerts[type]
|
[type]: !instancePush?.alerts[type]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : null
|
))
|
||||||
)
|
|
||||||
: null
|
: null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -164,7 +168,6 @@ const TabMePush: React.FC = () => {
|
|||||||
<MenuRow
|
<MenuRow
|
||||||
title={t('me.push.decode.heading')}
|
title={t('me.push.decode.heading')}
|
||||||
description={t('me.push.decode.description')}
|
description={t('me.push.decode.description')}
|
||||||
loading={instancePush?.decode}
|
|
||||||
switchDisabled={!pushEnabled || !instancePush?.global}
|
switchDisabled={!pushEnabled || !instancePush?.global}
|
||||||
switchValue={instancePush?.decode}
|
switchValue={instancePush?.decode}
|
||||||
switchOnValueChange={() =>
|
switchOnValueChange={() =>
|
||||||
@@ -176,7 +179,7 @@ const TabMePush: React.FC = () => {
|
|||||||
iconBack='ExternalLink'
|
iconBack='ExternalLink'
|
||||||
onPress={async () =>
|
onPress={async () =>
|
||||||
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works', {
|
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works', {
|
||||||
browserPackage: await browserPackage()
|
...(await browserPackage())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@@ -4,7 +4,11 @@ import { useAppDispatch } from '@root/store'
|
|||||||
import { useAnnouncementQuery } from '@utils/queryHooks/announcement'
|
import { useAnnouncementQuery } from '@utils/queryHooks/announcement'
|
||||||
import { useListsQuery } from '@utils/queryHooks/lists'
|
import { useListsQuery } from '@utils/queryHooks/lists'
|
||||||
import { useFollowedTagsQuery } from '@utils/queryHooks/tags'
|
import { useFollowedTagsQuery } from '@utils/queryHooks/tags'
|
||||||
import { getInstanceMePage, updateInstanceMePage } from '@utils/slices/instancesSlice'
|
import {
|
||||||
|
checkInstanceFeature,
|
||||||
|
getInstanceMePage,
|
||||||
|
updateInstanceMePage
|
||||||
|
} from '@utils/slices/instancesSlice'
|
||||||
import { getInstancePush } from '@utils/slices/instancesSlice'
|
import { getInstancePush } from '@utils/slices/instancesSlice'
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@@ -17,8 +21,10 @@ const Collections: React.FC = () => {
|
|||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const mePage = useSelector(getInstanceMePage)
|
const mePage = useSelector(getInstanceMePage)
|
||||||
|
|
||||||
|
const canFollowTags = useSelector(checkInstanceFeature('follow_tags'))
|
||||||
useFollowedTagsQuery({
|
useFollowedTagsQuery({
|
||||||
options: {
|
options: {
|
||||||
|
enabled: canFollowTags,
|
||||||
onSuccess: data =>
|
onSuccess: data =>
|
||||||
dispatch(
|
dispatch(
|
||||||
updateInstanceMePage({
|
updateInstanceMePage({
|
||||||
|
@@ -31,7 +31,7 @@ const Settings: React.FC = () => {
|
|||||||
`https://${url}/settings/preferences`,
|
`https://${url}/settings/preferences`,
|
||||||
'tooot://tooot',
|
'tooot://tooot',
|
||||||
{
|
{
|
||||||
browserPackage: await browserPackage(),
|
...(await browserPackage()),
|
||||||
dismissButtonStyle: 'done',
|
dismissButtonStyle: 'done',
|
||||||
readerMode: false
|
readerMode: false
|
||||||
}
|
}
|
||||||
|
@@ -64,7 +64,7 @@ const SettingsTooot: React.FC = () => {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
WebBrowser.openBrowserAsync('https://social.xmflsct.com/@tooot', {
|
WebBrowser.openBrowserAsync('https://social.xmflsct.com/@tooot', {
|
||||||
browserPackage: await browserPackage()
|
...(await browserPackage())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
import { MenuRow } from '@components/Menu'
|
||||||
import { LOCALES } from '@root/i18n/locales'
|
import { LOCALES } from '@root/i18n/locales'
|
||||||
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||||
import { setChannels } from '@utils/slices/instances/push/utils'
|
import { setChannels } from '@utils/slices/instances/push/utils'
|
||||||
import { getInstances } from '@utils/slices/instancesSlice'
|
import { getInstances } from '@utils/slices/instancesSlice'
|
||||||
import { changeLanguage } from '@utils/slices/settingsSlice'
|
import { changeLanguage } from '@utils/slices/settingsSlice'
|
||||||
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FlatList, Platform } from 'react-native'
|
import { FlatList, Platform } from 'react-native'
|
||||||
@@ -33,8 +34,8 @@ const TabMeSettingsLanguage: React.FC<TabMeStackScreenProps<'Tab-Me-Settings-Lan
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuContainer>
|
|
||||||
<FlatList
|
<FlatList
|
||||||
|
style={{ flex: 1, paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}
|
||||||
data={languages}
|
data={languages}
|
||||||
renderItem={({ item }) => {
|
renderItem={({ item }) => {
|
||||||
return (
|
return (
|
||||||
@@ -48,7 +49,6 @@ const TabMeSettingsLanguage: React.FC<TabMeStackScreenProps<'Tab-Me-Settings-Lan
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</MenuContainer>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,17 +1,12 @@
|
|||||||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
import { HeaderLeft, HeaderRight } from '@components/Header'
|
||||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||||
import {
|
|
||||||
checkPermission,
|
|
||||||
PERMISSION_MANAGE_REPORTS,
|
|
||||||
PERMISSION_MANAGE_USERS
|
|
||||||
} from '@helpers/permissions'
|
|
||||||
import { useAppDispatch } from '@root/store'
|
import { useAppDispatch } from '@root/store'
|
||||||
import { useQueryClient } from '@tanstack/react-query'
|
import { useQueryClient } from '@tanstack/react-query'
|
||||||
import { TabNotificationsStackScreenProps } from '@utils/navigation/navigators'
|
import { TabNotificationsStackScreenProps } from '@utils/navigation/navigators'
|
||||||
import { useProfileQuery } from '@utils/queryHooks/profile'
|
import { useProfileQuery } from '@utils/queryHooks/profile'
|
||||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||||
|
import { PUSH_ADMIN, PUSH_DEFAULT, usePushFeatures } from '@utils/slices/instances/push/utils'
|
||||||
import {
|
import {
|
||||||
checkInstanceFeature,
|
|
||||||
getInstanceNotificationsFilter,
|
getInstanceNotificationsFilter,
|
||||||
updateInstanceNotificationsFilter
|
updateInstanceNotificationsFilter
|
||||||
} from '@utils/slices/instancesSlice'
|
} from '@utils/slices/instancesSlice'
|
||||||
@@ -22,32 +17,12 @@ import { Alert } from 'react-native'
|
|||||||
import { ScrollView } from 'react-native-gesture-handler'
|
import { ScrollView } from 'react-native-gesture-handler'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
export const NOTIFICATIONS_FILTERS_DEFAULT: [
|
|
||||||
'follow',
|
|
||||||
'follow_request',
|
|
||||||
'favourite',
|
|
||||||
'reblog',
|
|
||||||
'mention',
|
|
||||||
'poll',
|
|
||||||
'status',
|
|
||||||
'update'
|
|
||||||
] = ['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', 'status', 'update']
|
|
||||||
|
|
||||||
export const NOTIFICATIONS_FILTERS_ADMIN: {
|
|
||||||
type: 'admin.sign_up' | 'admin.report'
|
|
||||||
permission: number
|
|
||||||
}[] = [
|
|
||||||
{ type: 'admin.sign_up', permission: PERMISSION_MANAGE_USERS },
|
|
||||||
{ type: 'admin.report', permission: PERMISSION_MANAGE_REPORTS }
|
|
||||||
]
|
|
||||||
|
|
||||||
const TabNotificationsFilters: React.FC<
|
const TabNotificationsFilters: React.FC<
|
||||||
TabNotificationsStackScreenProps<'Tab-Notifications-Filters'>
|
TabNotificationsStackScreenProps<'Tab-Notifications-Filters'>
|
||||||
> = ({ navigation }) => {
|
> = ({ navigation }) => {
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
|
|
||||||
const hasTypeStatus = useSelector(checkInstanceFeature('notification_type_status'))
|
const pushFeatures = usePushFeatures()
|
||||||
const hasTypeUpdate = useSelector(checkInstanceFeature('notification_type_update'))
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
@@ -103,16 +78,7 @@ const TabNotificationsFilters: React.FC<
|
|||||||
return (
|
return (
|
||||||
<ScrollView style={{ flex: 1 }}>
|
<ScrollView style={{ flex: 1 }}>
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
{NOTIFICATIONS_FILTERS_DEFAULT.filter(type => {
|
{PUSH_DEFAULT(pushFeatures).map((type, index) => (
|
||||||
switch (type) {
|
|
||||||
case 'status':
|
|
||||||
return hasTypeStatus
|
|
||||||
case 'update':
|
|
||||||
return hasTypeUpdate
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}).map((type, index) => (
|
|
||||||
<MenuRow
|
<MenuRow
|
||||||
key={index}
|
key={index}
|
||||||
title={t(`notifications.filters.options.${type}`)}
|
title={t(`notifications.filters.options.${type}`)}
|
||||||
@@ -120,9 +86,7 @@ const TabNotificationsFilters: React.FC<
|
|||||||
switchOnValueChange={() => setFilters({ ...filters, [type]: !filters[type] })}
|
switchOnValueChange={() => setFilters({ ...filters, [type]: !filters[type] })}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{NOTIFICATIONS_FILTERS_ADMIN.filter(({ permission }) =>
|
{PUSH_ADMIN(pushFeatures, profileQuery.data?.role?.permissions).map(({ type }) => (
|
||||||
checkPermission(permission, profileQuery.data?.role?.permissions)
|
|
||||||
).map(({ type }) => (
|
|
||||||
<MenuRow
|
<MenuRow
|
||||||
key={type}
|
key={type}
|
||||||
title={t(`notifications.filters.options.${type}`)}
|
title={t(`notifications.filters.options.${type}`)}
|
||||||
|
@@ -11,25 +11,45 @@ import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
|||||||
import { useStatusHistory } from '@utils/queryHooks/statusesHistory'
|
import { useStatusHistory } from '@utils/queryHooks/statusesHistory'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { diffWords } from 'diff'
|
import { diffChars, diffWords } from 'diff'
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FlatList, View } from 'react-native'
|
import { FlatList, View } from 'react-native'
|
||||||
|
|
||||||
|
const SCRIPTS_WITHOUT_BOUNDARIES = [
|
||||||
|
'my',
|
||||||
|
'zh',
|
||||||
|
'ja',
|
||||||
|
'kar',
|
||||||
|
'km',
|
||||||
|
'lp',
|
||||||
|
'phag',
|
||||||
|
'pwo',
|
||||||
|
'kar',
|
||||||
|
'lana',
|
||||||
|
'th',
|
||||||
|
'bo'
|
||||||
|
]
|
||||||
|
|
||||||
const ContentView: React.FC<{
|
const ContentView: React.FC<{
|
||||||
|
withoutBoundary: boolean
|
||||||
item: Mastodon.StatusHistory
|
item: Mastodon.StatusHistory
|
||||||
prevItem?: Mastodon.StatusHistory
|
prevItem?: Mastodon.StatusHistory
|
||||||
}> = ({ item, prevItem }) => {
|
}> = ({ withoutBoundary, item, prevItem }) => {
|
||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
|
|
||||||
const changesSpoiler = diffWords(
|
const changesSpoiler = withoutBoundary
|
||||||
|
? diffChars(
|
||||||
removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''),
|
removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''),
|
||||||
removeHTML(item.spoiler_text || '')
|
removeHTML(item.spoiler_text || '')
|
||||||
)
|
)
|
||||||
const changesContent = diffWords(
|
: diffWords(
|
||||||
removeHTML(prevItem?.content || item.content),
|
removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''),
|
||||||
removeHTML(item.content)
|
removeHTML(item.spoiler_text || '')
|
||||||
)
|
)
|
||||||
|
const changesContent = withoutBoundary
|
||||||
|
? diffChars(removeHTML(prevItem?.content || item.content), removeHTML(item.content))
|
||||||
|
: diffWords(removeHTML(prevItem?.content || item.content), removeHTML(item.content))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -91,7 +111,7 @@ const ContentView: React.FC<{
|
|||||||
const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'>> = ({
|
const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'>> = ({
|
||||||
navigation,
|
navigation,
|
||||||
route: {
|
route: {
|
||||||
params: { id }
|
params: { id, detectedLanguage }
|
||||||
}
|
}
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
@@ -106,12 +126,20 @@ const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'>
|
|||||||
|
|
||||||
const dataReversed = data ? [...data].reverse() : []
|
const dataReversed = data ? [...data].reverse() : []
|
||||||
|
|
||||||
|
const withoutBoundary = !!SCRIPTS_WITHOUT_BOUNDARIES.filter(script =>
|
||||||
|
detectedLanguage?.toLocaleLowerCase().startsWith(script)
|
||||||
|
).length
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<FlatList
|
||||||
style={{ flex: 1, minHeight: '100%' }}
|
style={{ flex: 1, minHeight: '100%' }}
|
||||||
data={dataReversed}
|
data={dataReversed}
|
||||||
renderItem={({ item, index }) => (
|
renderItem={({ item, index }) => (
|
||||||
<ContentView item={item} prevItem={dataReversed[index + 1]} />
|
<ContentView
|
||||||
|
withoutBoundary={withoutBoundary}
|
||||||
|
item={item}
|
||||||
|
prevItem={dataReversed[index + 1]}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
ItemSeparatorComponent={ComponentSeparator}
|
ItemSeparatorComponent={ComponentSeparator}
|
||||||
/>
|
/>
|
||||||
|
@@ -49,7 +49,6 @@ const TabSharedSearch: React.FC<TabSharedStackScreenProps<'Tab-Shared-Search'>>
|
|||||||
<TextInput
|
<TextInput
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
accessibilityRole='search'
|
accessibilityRole='search'
|
||||||
keyboardAppearance={mode}
|
|
||||||
style={{
|
style={{
|
||||||
fontSize: StyleConstants.Font.Size.M,
|
fontSize: StyleConstants.Font.Size.M,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -60,7 +59,6 @@ const TabSharedSearch: React.FC<TabSharedStackScreenProps<'Tab-Shared-Search'>>
|
|||||||
borderBottomColor: colors.border,
|
borderBottomColor: colors.border,
|
||||||
borderBottomWidth: 1
|
borderBottomWidth: 1
|
||||||
}}
|
}}
|
||||||
autoFocus
|
|
||||||
onChangeText={debounce(
|
onChangeText={debounce(
|
||||||
text => {
|
text => {
|
||||||
setSearchTerm(text)
|
setSearchTerm(text)
|
||||||
@@ -82,6 +80,13 @@ const TabSharedSearch: React.FC<TabSharedStackScreenProps<'Tab-Shared-Search'>>
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [mode])
|
}, [mode])
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = navigation.addListener('transitionEnd', e => {
|
||||||
|
inputRef.current?.focus()
|
||||||
|
})
|
||||||
|
|
||||||
|
return unsubscribe
|
||||||
|
}, [navigation])
|
||||||
|
|
||||||
const mapKeyToTranslations = {
|
const mapKeyToTranslations = {
|
||||||
accounts: t('shared.search.sections.accounts'),
|
accounts: t('shared.search.sections.accounts'),
|
||||||
|
@@ -34,6 +34,10 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
queryKey,
|
queryKey,
|
||||||
enabled: false
|
enabled: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const replyLevels = useRef<{ id: string; level: number }[]>([])
|
||||||
|
const data = useRef<Mastodon.Status[]>()
|
||||||
|
const highlightIndex = useRef<number>(0)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return observer.subscribe(result => {
|
return observer.subscribe(result => {
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
@@ -46,6 +50,24 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
navigation.goBack()
|
navigation.goBack()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
data.current = flattenData
|
||||||
|
highlightIndex.current = flattenData.findIndex(({ id }) => id === toot.id)
|
||||||
|
|
||||||
|
for (const [index, status] of flattenData.entries()) {
|
||||||
|
if (status.id === toot.id) continue
|
||||||
|
if (status.in_reply_to_id === toot.id) continue
|
||||||
|
|
||||||
|
if (!replyLevels.current.find(reply => reply.id === status.in_reply_to_id)) {
|
||||||
|
const prevLevel =
|
||||||
|
replyLevels.current.find(reply => reply.id === flattenData[index - 1].in_reply_to_id)
|
||||||
|
?.level || 0
|
||||||
|
replyLevels.current.push({
|
||||||
|
id: status.in_reply_to_id,
|
||||||
|
level: prevLevel + 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setItemsLength(flattenData.length)
|
setItemsLength(flattenData.length)
|
||||||
if (!scrolled.current) {
|
if (!scrolled.current) {
|
||||||
scrolled.current = true
|
scrolled.current = true
|
||||||
@@ -68,7 +90,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [scrolled.current])
|
}, [scrolled.current, replyLevels.current])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Timeline
|
<Timeline
|
||||||
@@ -76,14 +98,94 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
|||||||
queryKey={queryKey}
|
queryKey={queryKey}
|
||||||
queryOptions={{ staleTime: 0, refetchOnMount: true }}
|
queryOptions={{ staleTime: 0, refetchOnMount: true }}
|
||||||
customProps={{
|
customProps={{
|
||||||
renderItem: ({ item }) => (
|
renderItem: ({ item }) => {
|
||||||
|
return (
|
||||||
<TimelineDefault
|
<TimelineDefault
|
||||||
item={item}
|
item={item}
|
||||||
queryKey={queryKey}
|
queryKey={queryKey}
|
||||||
rootQueryKey={rootQueryKey}
|
rootQueryKey={rootQueryKey}
|
||||||
highlighted={toot.id === item.id}
|
highlighted={toot.id === item.id}
|
||||||
/>
|
/>
|
||||||
),
|
)
|
||||||
|
},
|
||||||
|
// renderItem: ({ item, index }) => {
|
||||||
|
// const levels = {
|
||||||
|
// previous:
|
||||||
|
// replyLevels.current.find(
|
||||||
|
// reply => reply.id === data.current?.[index - 1]?.in_reply_to_id
|
||||||
|
// )?.level || 0,
|
||||||
|
// current:
|
||||||
|
// replyLevels.current.find(reply => reply.id === item.in_reply_to_id)?.level || 0,
|
||||||
|
// next:
|
||||||
|
// replyLevels.current.find(
|
||||||
|
// reply => reply.id === data.current?.[index + 1]?.in_reply_to_id
|
||||||
|
// )?.level || 0
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <>
|
||||||
|
// <TimelineDefault
|
||||||
|
// item={item}
|
||||||
|
// queryKey={queryKey}
|
||||||
|
// rootQueryKey={rootQueryKey}
|
||||||
|
// highlighted={toot.id === item.id}
|
||||||
|
// isConversation={toot.id !== item.id}
|
||||||
|
// />
|
||||||
|
// {Array.from(Array(levels.current)).map((_, i) => {
|
||||||
|
// if (index < highlightIndex.current) return null
|
||||||
|
// if (
|
||||||
|
// levels.previous + 1 === levels.current ||
|
||||||
|
// (levels.previous && levels.current && levels.previous === levels.current)
|
||||||
|
// ) {
|
||||||
|
// return (
|
||||||
|
// <View
|
||||||
|
// key={i}
|
||||||
|
// style={{
|
||||||
|
// position: 'absolute',
|
||||||
|
// top: 0,
|
||||||
|
// left: StyleConstants.Spacing.Global.PagePadding / 2 + 8 * i,
|
||||||
|
// height:
|
||||||
|
// levels.current === levels.next
|
||||||
|
// ? StyleConstants.Spacing.Global.PagePadding
|
||||||
|
// : StyleConstants.Spacing.Global.PagePadding + StyleConstants.Avatar.XS,
|
||||||
|
// borderLeftColor: colors.border,
|
||||||
|
// borderLeftWidth: 1
|
||||||
|
// }}
|
||||||
|
// />
|
||||||
|
// )
|
||||||
|
// } else {
|
||||||
|
// return null
|
||||||
|
// }
|
||||||
|
// })}
|
||||||
|
// {Array.from(Array(levels.next)).map((_, i) => {
|
||||||
|
// if (index < highlightIndex.current) return null
|
||||||
|
// if (
|
||||||
|
// levels.current + 1 === levels.next ||
|
||||||
|
// (levels.current && levels.next && levels.current === levels.next)
|
||||||
|
// ) {
|
||||||
|
// return (
|
||||||
|
// <View
|
||||||
|
// key={i}
|
||||||
|
// style={{
|
||||||
|
// position: 'absolute',
|
||||||
|
// top:
|
||||||
|
// levels.current + 1 === levels.next && levels.next > i + 1
|
||||||
|
// ? StyleConstants.Spacing.Global.PagePadding + StyleConstants.Avatar.XS
|
||||||
|
// : StyleConstants.Spacing.Global.PagePadding,
|
||||||
|
// left: StyleConstants.Spacing.Global.PagePadding / 2 + 8 * i,
|
||||||
|
// height: 200,
|
||||||
|
// borderLeftColor: colors.border,
|
||||||
|
// borderLeftWidth: 1
|
||||||
|
// }}
|
||||||
|
// />
|
||||||
|
// )
|
||||||
|
// } else {
|
||||||
|
// return null
|
||||||
|
// }
|
||||||
|
// })}
|
||||||
|
// </>
|
||||||
|
// )
|
||||||
|
// },
|
||||||
onScrollToIndexFailed: error => {
|
onScrollToIndexFailed: error => {
|
||||||
const offset = error.averageItemLength * error.index
|
const offset = error.averageItemLength * error.index
|
||||||
flRef.current?.scrollToOffset({ offset })
|
flRef.current?.scrollToOffset({ offset })
|
||||||
|
@@ -1,15 +1,18 @@
|
|||||||
|
import apiInstance from '@api/instance'
|
||||||
import ComponentAccount from '@components/Account'
|
import ComponentAccount from '@components/Account'
|
||||||
import { HeaderLeft } from '@components/Header'
|
import { HeaderLeft } from '@components/Header'
|
||||||
import Icon from '@components/Icon'
|
import Icon from '@components/Icon'
|
||||||
import ComponentSeparator from '@components/Separator'
|
import ComponentSeparator from '@components/Separator'
|
||||||
import CustomText from '@components/Text'
|
import CustomText from '@components/Text'
|
||||||
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
import { TabSharedStackScreenProps } from '@utils/navigation/navigators'
|
||||||
|
import { SearchResult } from '@utils/queryHooks/search'
|
||||||
import { QueryKeyUsers, useUsersQuery } from '@utils/queryHooks/users'
|
import { QueryKeyUsers, useUsersQuery } from '@utils/queryHooks/users'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useCallback, useEffect } from 'react'
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { View } from 'react-native'
|
import { View } from 'react-native'
|
||||||
|
import { Circle, Flow } from 'react-native-animated-spinkit'
|
||||||
import { FlatList } from 'react-native-gesture-handler'
|
import { FlatList } from 'react-native-gesture-handler'
|
||||||
|
|
||||||
const TabSharedUsers: React.FC<TabSharedStackScreenProps<'Tab-Shared-Users'>> = ({
|
const TabSharedUsers: React.FC<TabSharedStackScreenProps<'Tab-Shared-Users'>> = ({
|
||||||
@@ -26,7 +29,7 @@ const TabSharedUsers: React.FC<TabSharedStackScreenProps<'Tab-Shared-Users'>> =
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const queryKey: QueryKeyUsers = ['Users', params]
|
const queryKey: QueryKeyUsers = ['Users', params]
|
||||||
const { data, hasNextPage, fetchNextPage, isFetchingNextPage } = useUsersQuery({
|
const { data, isFetching, hasNextPage, fetchNextPage, isFetchingNextPage } = useUsersQuery({
|
||||||
...queryKey[1],
|
...queryKey[1],
|
||||||
options: {
|
options: {
|
||||||
getPreviousPageParam: firstPage =>
|
getPreviousPageParam: firstPage =>
|
||||||
@@ -41,17 +44,67 @@ const TabSharedUsers: React.FC<TabSharedStackScreenProps<'Tab-Shared-Users'>> =
|
|||||||
[hasNextPage, isFetchingNextPage]
|
[hasNextPage, isFetchingNextPage]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const [isSearching, setIsSearching] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<FlatList
|
||||||
windowSize={7}
|
windowSize={7}
|
||||||
data={flattenData}
|
data={flattenData}
|
||||||
style={{
|
style={{
|
||||||
minHeight: '100%'
|
minHeight: '100%',
|
||||||
|
paddingVertical: StyleConstants.Spacing.Global.PagePadding
|
||||||
}}
|
}}
|
||||||
renderItem={({ item }) => <ComponentAccount account={item} />}
|
renderItem={({ item }) => (
|
||||||
|
<ComponentAccount
|
||||||
|
account={item}
|
||||||
|
props={{
|
||||||
|
disabled: isSearching,
|
||||||
|
onPress: () => {
|
||||||
|
if (data?.pages[0]?.remoteData) {
|
||||||
|
setIsSearching(true)
|
||||||
|
apiInstance<SearchResult>({
|
||||||
|
version: 'v2',
|
||||||
|
method: 'get',
|
||||||
|
url: 'search',
|
||||||
|
params: {
|
||||||
|
q: `@${item.acct}`,
|
||||||
|
type: 'accounts',
|
||||||
|
limit: 1,
|
||||||
|
resolve: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
setIsSearching(false)
|
||||||
|
if (res.body.accounts[0]) {
|
||||||
|
navigation.push('Tab-Shared-Account', { account: res.body.accounts[0] })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => setIsSearching(false))
|
||||||
|
} else {
|
||||||
|
navigation.push('Tab-Shared-Account', { account: item })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
children={<Flow size={StyleConstants.Font.Size.L} color={colors.secondary} />}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
onEndReachedThreshold={0.75}
|
onEndReachedThreshold={0.75}
|
||||||
ItemSeparatorComponent={ComponentSeparator}
|
ItemSeparatorComponent={ComponentSeparator}
|
||||||
|
ListEmptyComponent={
|
||||||
|
isFetching ? (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
minHeight: '100%',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
|
||||||
|
</View>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
maintainVisibleContentPosition={{
|
maintainVisibleContentPosition={{
|
||||||
minIndexForVisible: 0,
|
minIndexForVisible: 0,
|
||||||
autoscrollToTopThreshold: 2
|
autoscrollToTopThreshold: 2
|
||||||
|
@@ -156,6 +156,7 @@ const instancesMigration = {
|
|||||||
mention: instance.push.alerts.mention.value,
|
mention: instance.push.alerts.mention.value,
|
||||||
poll: instance.push.alerts.poll.value,
|
poll: instance.push.alerts.poll.value,
|
||||||
status: instance.push.alerts.status.value,
|
status: instance.push.alerts.status.value,
|
||||||
|
update: false,
|
||||||
'admin.sign_up': false,
|
'admin.sign_up': false,
|
||||||
'admin.report': false
|
'admin.report': false
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@ export type InstanceV11 = {
|
|||||||
id: Mastodon.Account['id']
|
id: Mastodon.Account['id']
|
||||||
acct: Mastodon.Account['acct']
|
acct: Mastodon.Account['acct']
|
||||||
avatarStatic: Mastodon.Account['avatar_static']
|
avatarStatic: Mastodon.Account['avatar_static']
|
||||||
preferences: Mastodon.Preferences
|
preferences?: Mastodon.Preferences
|
||||||
}
|
}
|
||||||
version: string
|
version: string
|
||||||
configuration?: Mastodon.Instance['configuration']
|
configuration?: Mastodon.Instance['configuration']
|
||||||
|
@@ -103,6 +103,7 @@ export type TabSharedStackParamList = {
|
|||||||
}
|
}
|
||||||
'Tab-Shared-History': {
|
'Tab-Shared-History': {
|
||||||
id: Mastodon.Status['id']
|
id: Mastodon.Status['id']
|
||||||
|
detectedLanguage: string
|
||||||
}
|
}
|
||||||
'Tab-Shared-Search': undefined
|
'Tab-Shared-Search': undefined
|
||||||
'Tab-Shared-Toot': {
|
'Tab-Shared-Toot': {
|
||||||
|
@@ -1,12 +1,13 @@
|
|||||||
import apiGeneral from '@api/general'
|
import apiGeneral from '@api/general'
|
||||||
import { handleError } from '@api/helpers'
|
|
||||||
import apiTooot from '@api/tooot'
|
import apiTooot from '@api/tooot'
|
||||||
import { displayMessage } from '@components/Message'
|
import { displayMessage } from '@components/Message'
|
||||||
import navigationRef from '@helpers/navigationRef'
|
import navigationRef from '@helpers/navigationRef'
|
||||||
import { useAppDispatch } from '@root/store'
|
import { useAppDispatch } from '@root/store'
|
||||||
import * as Sentry from '@sentry/react-native'
|
import * as Sentry from '@sentry/react-native'
|
||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
|
import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
|
||||||
import { disableAllPushes, getInstances } from '@utils/slices/instancesSlice'
|
import { disableAllPushes, getInstances } from '@utils/slices/instancesSlice'
|
||||||
|
import { AxiosError } from 'axios'
|
||||||
import * as Notifications from 'expo-notifications'
|
import * as Notifications from 'expo-notifications'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@@ -25,16 +26,22 @@ const pushUseConnect = () => {
|
|||||||
const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
|
const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
|
||||||
const pushEnabled = instances.filter(instance => instance.push.global)
|
const pushEnabled = instances.filter(instance => instance.push.global)
|
||||||
|
|
||||||
const connect = () => {
|
const connectQuery = useQuery<any, AxiosError>(
|
||||||
apiTooot({
|
['tooot', { endpoint: 'push/connect' }],
|
||||||
|
() =>
|
||||||
|
apiTooot<Mastodon.Status>({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: `/push/connect/${expoToken}`
|
url: `push/connect/${expoToken}`
|
||||||
})
|
}),
|
||||||
.then(() => Notifications.setBadgeCountAsync(0))
|
{
|
||||||
.catch(error => {
|
enabled: false,
|
||||||
handleError({ message: 'Push connect error', captureResponse: true })
|
retry: 10,
|
||||||
|
retryOnMount: false,
|
||||||
Notifications.setBadgeCountAsync(0)
|
refetchOnMount: false,
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
refetchOnReconnect: false,
|
||||||
|
onSettled: () => Notifications.setBadgeCountAsync(0),
|
||||||
|
onError: error => {
|
||||||
if (error?.status == 404) {
|
if (error?.status == 404) {
|
||||||
displayMessage({
|
displayMessage({
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
@@ -72,21 +79,22 @@ const pushUseConnect = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Sentry.setContext('Push', { expoToken, pushEnabledCount: pushEnabled.length })
|
Sentry.setContext('Push', { expoToken, pushEnabledCount: pushEnabled.length })
|
||||||
|
|
||||||
if (expoToken && pushEnabled.length) {
|
if (expoToken && pushEnabled.length) {
|
||||||
connect()
|
connectQuery.refetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
const appStateListener = AppState.addEventListener('change', state => {
|
const appStateListener = AppState.addEventListener('change', state => {
|
||||||
if (expoToken && pushEnabled.length && state === 'active') {
|
if (expoToken && pushEnabled.length && state === 'active') {
|
||||||
Notifications.getBadgeCountAsync().then(count => {
|
Notifications.getBadgeCountAsync().then(count => {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
connect()
|
connectQuery.refetch()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import apiInstance, { InstanceResponse } from '@api/instance'
|
import apiInstance from '@api/instance'
|
||||||
import { AxiosError } from 'axios'
|
import { AxiosError } from 'axios'
|
||||||
import {
|
import {
|
||||||
QueryFunctionContext,
|
QueryFunctionContext,
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
useQuery,
|
useQuery,
|
||||||
UseQueryOptions
|
UseQueryOptions
|
||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
|
import { PagedResponse } from '@api/helpers'
|
||||||
|
|
||||||
export type QueryKeyLists = ['Lists']
|
export type QueryKeyLists = ['Lists']
|
||||||
|
|
||||||
@@ -97,7 +98,7 @@ const useListAccountsQuery = ({
|
|||||||
options,
|
options,
|
||||||
...queryKeyParams
|
...queryKeyParams
|
||||||
}: QueryKeyListAccounts[1] & {
|
}: QueryKeyListAccounts[1] & {
|
||||||
options?: UseInfiniteQueryOptions<InstanceResponse<Mastodon.Account[]>, AxiosError>
|
options?: UseInfiniteQueryOptions<PagedResponse<Mastodon.Account[]>, AxiosError>
|
||||||
}) => {
|
}) => {
|
||||||
const queryKey: QueryKeyListAccounts = ['ListAccounts', queryKeyParams]
|
const queryKey: QueryKeyListAccounts = ['ListAccounts', queryKeyParams]
|
||||||
return useInfiniteQuery(queryKey, accountsQueryFunction, options)
|
return useInfiniteQuery(queryKey, accountsQueryFunction, options)
|
||||||
|
@@ -8,14 +8,9 @@ import {
|
|||||||
UseQueryOptions
|
UseQueryOptions
|
||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
export type QueryKeyRelationship = [
|
export type QueryKeyRelationship = ['Relationship', { id: Mastodon.Account['id'] }]
|
||||||
'Relationship',
|
|
||||||
{ id: Mastodon.Account['id'] }
|
|
||||||
]
|
|
||||||
|
|
||||||
const queryFunction = async ({
|
const queryFunction = async ({ queryKey }: QueryFunctionContext<QueryKeyRelationship>) => {
|
||||||
queryKey
|
|
||||||
}: QueryFunctionContext<QueryKeyRelationship>) => {
|
|
||||||
const { id } = queryKey[1]
|
const { id } = queryKey[1]
|
||||||
|
|
||||||
const res = await apiInstance<Mastodon.Relationship[]>({
|
const res = await apiInstance<Mastodon.Relationship[]>({
|
||||||
@@ -32,11 +27,7 @@ const useRelationshipQuery = ({
|
|||||||
options,
|
options,
|
||||||
...queryKeyParams
|
...queryKeyParams
|
||||||
}: QueryKeyRelationship[1] & {
|
}: QueryKeyRelationship[1] & {
|
||||||
options?: UseQueryOptions<
|
options?: UseQueryOptions<Mastodon.Relationship[], AxiosError, Mastodon.Relationship>
|
||||||
Mastodon.Relationship[],
|
|
||||||
AxiosError,
|
|
||||||
Mastodon.Relationship
|
|
||||||
>
|
|
||||||
}) => {
|
}) => {
|
||||||
const queryKey: QueryKeyRelationship = ['Relationship', { ...queryKeyParams }]
|
const queryKey: QueryKeyRelationship = ['Relationship', { ...queryKeyParams }]
|
||||||
return useQuery(queryKey, queryFunction, {
|
return useQuery(queryKey, queryFunction, {
|
||||||
@@ -54,7 +45,20 @@ type MutationVarsRelationship =
|
|||||||
| {
|
| {
|
||||||
id: Mastodon.Account['id']
|
id: Mastodon.Account['id']
|
||||||
type: 'outgoing'
|
type: 'outgoing'
|
||||||
payload: { action: 'follow' | 'block'; state: boolean }
|
payload: {
|
||||||
|
action: 'block'
|
||||||
|
state: boolean
|
||||||
|
notify?: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: Mastodon.Account['id']
|
||||||
|
type: 'outgoing'
|
||||||
|
payload: {
|
||||||
|
action: 'follow'
|
||||||
|
state: boolean
|
||||||
|
notify?: boolean
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mutationFunction = async (params: MutationVarsRelationship) => {
|
const mutationFunction = async (params: MutationVarsRelationship) => {
|
||||||
@@ -65,21 +69,20 @@ const mutationFunction = async (params: MutationVarsRelationship) => {
|
|||||||
url: `follow_requests/${params.id}/${params.payload.action}`
|
url: `follow_requests/${params.id}/${params.payload.action}`
|
||||||
}).then(res => res.body)
|
}).then(res => res.body)
|
||||||
case 'outgoing':
|
case 'outgoing':
|
||||||
|
const formData = new FormData()
|
||||||
|
typeof params.payload.notify === 'boolean' &&
|
||||||
|
formData.append('notify', params.payload.notify.toString())
|
||||||
|
|
||||||
return apiInstance<Mastodon.Relationship>({
|
return apiInstance<Mastodon.Relationship>({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: `accounts/${params.id}/${params.payload.state ? 'un' : ''}${
|
url: `accounts/${params.id}/${params.payload.state ? 'un' : ''}${params.payload.action}`,
|
||||||
params.payload.action
|
body: formData
|
||||||
}`
|
|
||||||
}).then(res => res.body)
|
}).then(res => res.body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const useRelationshipMutation = (
|
const useRelationshipMutation = (
|
||||||
options: UseMutationOptions<
|
options: UseMutationOptions<Mastodon.Relationship, AxiosError, MutationVarsRelationship>
|
||||||
Mastodon.Relationship,
|
|
||||||
AxiosError,
|
|
||||||
MutationVarsRelationship
|
|
||||||
>
|
|
||||||
) => {
|
) => {
|
||||||
return useMutation(mutationFunction, options)
|
return useMutation(mutationFunction, options)
|
||||||
}
|
}
|
||||||
|
@@ -17,17 +17,18 @@ export type SearchResult = {
|
|||||||
statuses: Mastodon.Status[]
|
statuses: Mastodon.Status[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryFunction = async ({
|
const queryFunction = async ({ queryKey }: QueryFunctionContext<QueryKeySearch>) => {
|
||||||
queryKey
|
|
||||||
}: QueryFunctionContext<QueryKeySearch>) => {
|
|
||||||
const { type, term, limit = 20 } = queryKey[1]
|
const { type, term, limit = 20 } = queryKey[1]
|
||||||
|
if (!term?.length) {
|
||||||
|
return Promise.reject()
|
||||||
|
}
|
||||||
const res = await apiInstance<SearchResult>({
|
const res = await apiInstance<SearchResult>({
|
||||||
version: 'v2',
|
version: 'v2',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: 'search',
|
url: 'search',
|
||||||
params: {
|
params: {
|
||||||
|
q: term,
|
||||||
...(type && { type }),
|
...(type && { type }),
|
||||||
...(term && { q: term }),
|
|
||||||
limit,
|
limit,
|
||||||
resolve: true
|
resolve: true
|
||||||
}
|
}
|
||||||
@@ -35,7 +36,7 @@ const queryFunction = async ({
|
|||||||
return res.body
|
return res.body
|
||||||
}
|
}
|
||||||
|
|
||||||
const useSearchQuery = <T = unknown>({
|
const useSearchQuery = <T = SearchResult>({
|
||||||
options,
|
options,
|
||||||
...queryKeyParams
|
...queryKeyParams
|
||||||
}: QueryKeySearch[1] & {
|
}: QueryKeySearch[1] & {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import apiInstance, { InstanceResponse } from '@api/instance'
|
import apiInstance from '@api/instance'
|
||||||
import { AxiosError } from 'axios'
|
import { AxiosError } from 'axios'
|
||||||
import {
|
import {
|
||||||
QueryFunctionContext,
|
QueryFunctionContext,
|
||||||
@@ -10,12 +10,13 @@ import {
|
|||||||
UseQueryOptions
|
UseQueryOptions
|
||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
import { infinitePageParams } from './utils'
|
import { infinitePageParams } from './utils'
|
||||||
|
import { PagedResponse } from '@api/helpers'
|
||||||
|
|
||||||
export type QueryKeyFollowedTags = ['FollowedTags']
|
export type QueryKeyFollowedTags = ['FollowedTags']
|
||||||
const useFollowedTagsQuery = (
|
const useFollowedTagsQuery = (
|
||||||
params: {
|
params: {
|
||||||
options?: Omit<
|
options?: Omit<
|
||||||
UseInfiniteQueryOptions<InstanceResponse<Mastodon.Tag[]>, AxiosError>,
|
UseInfiniteQueryOptions<PagedResponse<Mastodon.Tag[]>, AxiosError>,
|
||||||
'getPreviousPageParam' | 'getNextPageParam'
|
'getPreviousPageParam' | 'getNextPageParam'
|
||||||
>
|
>
|
||||||
} | void
|
} | void
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import apiInstance, { InstanceResponse } from '@api/instance'
|
import apiInstance from '@api/instance'
|
||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
import queryClient from '@helpers/queryClient'
|
import queryClient from '@helpers/queryClient'
|
||||||
import { store } from '@root/store'
|
import { store } from '@root/store'
|
||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
import deleteItem from './timeline/deleteItem'
|
import deleteItem from './timeline/deleteItem'
|
||||||
import editItem from './timeline/editItem'
|
import editItem from './timeline/editItem'
|
||||||
import updateStatusProperty from './timeline/updateStatusProperty'
|
import updateStatusProperty from './timeline/updateStatusProperty'
|
||||||
|
import { PagedResponse } from '@api/helpers'
|
||||||
|
|
||||||
export type QueryKeyTimeline = [
|
export type QueryKeyTimeline = [
|
||||||
'Timeline',
|
'Timeline',
|
||||||
@@ -240,7 +241,7 @@ const useTimelineQuery = ({
|
|||||||
options,
|
options,
|
||||||
...queryKeyParams
|
...queryKeyParams
|
||||||
}: QueryKeyTimeline[1] & {
|
}: QueryKeyTimeline[1] & {
|
||||||
options?: UseInfiniteQueryOptions<InstanceResponse<Mastodon.Status[]>, AxiosError>
|
options?: UseInfiniteQueryOptions<PagedResponse<Mastodon.Status[]>, AxiosError>
|
||||||
}) => {
|
}) => {
|
||||||
const queryKey: QueryKeyTimeline = ['Timeline', { ...queryKeyParams }]
|
const queryKey: QueryKeyTimeline = ['Timeline', { ...queryKeyParams }]
|
||||||
return useInfiniteQuery(queryKey, queryFunction, {
|
return useInfiniteQuery(queryKey, queryFunction, {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import apiInstance, { InstanceResponse } from '@api/instance'
|
import apiInstance from '@api/instance'
|
||||||
import { TabSharedStackParamList } from '@utils/navigation/navigators'
|
import { TabSharedStackParamList } from '@utils/navigation/navigators'
|
||||||
import { AxiosError } from 'axios'
|
import { AxiosError } from 'axios'
|
||||||
import {
|
import {
|
||||||
@@ -7,10 +7,15 @@ import {
|
|||||||
UseInfiniteQueryOptions
|
UseInfiniteQueryOptions
|
||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
import apiGeneral from '@api/general'
|
import apiGeneral from '@api/general'
|
||||||
|
import { PagedResponse } from '@api/helpers'
|
||||||
|
|
||||||
export type QueryKeyUsers = ['Users', TabSharedStackParamList['Tab-Shared-Users']]
|
export type QueryKeyUsers = ['Users', TabSharedStackParamList['Tab-Shared-Users']]
|
||||||
|
|
||||||
const queryFunction = ({ queryKey, pageParam }: QueryFunctionContext<QueryKeyUsers>) => {
|
const queryFunction = async ({
|
||||||
|
queryKey,
|
||||||
|
pageParam,
|
||||||
|
meta
|
||||||
|
}: QueryFunctionContext<QueryKeyUsers>) => {
|
||||||
const page = queryKey[1]
|
const page = queryKey[1]
|
||||||
let params: { [key: string]: string } = { ...pageParam }
|
let params: { [key: string]: string } = { ...pageParam }
|
||||||
|
|
||||||
@@ -20,7 +25,7 @@ const queryFunction = ({ queryKey, pageParam }: QueryFunctionContext<QueryKeyUse
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
url: `${page.reference}/${page.status.id}/${page.type}`,
|
url: `${page.reference}/${page.status.id}/${page.type}`,
|
||||||
params
|
params
|
||||||
}).then(res => ({ ...res, warnIncomplete: false }))
|
})
|
||||||
case 'accounts':
|
case 'accounts':
|
||||||
const localInstance = page.account.username === page.account.acct
|
const localInstance = page.account.username === page.account.acct
|
||||||
if (localInstance) {
|
if (localInstance) {
|
||||||
@@ -28,59 +33,43 @@ const queryFunction = ({ queryKey, pageParam }: QueryFunctionContext<QueryKeyUse
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
url: `${page.reference}/${page.account.id}/${page.type}`,
|
url: `${page.reference}/${page.account.id}/${page.type}`,
|
||||||
params
|
params
|
||||||
}).then(res => ({ ...res, warnIncomplete: false }))
|
})
|
||||||
} else {
|
} else {
|
||||||
|
let res: PagedResponse<Mastodon.Account[]>
|
||||||
|
|
||||||
|
try {
|
||||||
const domain = page.account.url.match(
|
const domain = page.account.url.match(
|
||||||
/^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/\n]+)/i
|
/^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/\n]+)/i
|
||||||
)?.[1]
|
)?.[1]
|
||||||
if (!domain) {
|
if (!domain?.length) {
|
||||||
return apiInstance<Mastodon.Account[]>({
|
throw new Error()
|
||||||
method: 'get',
|
|
||||||
url: `${page.reference}/${page.account.id}/${page.type}`,
|
|
||||||
params
|
|
||||||
}).then(res => ({ ...res, warnIncomplete: true }))
|
|
||||||
}
|
}
|
||||||
return apiGeneral<{ accounts: Mastodon.Account[] }>({
|
|
||||||
|
const resLookup = await apiGeneral<Mastodon.Account>({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
domain,
|
domain,
|
||||||
url: 'api/v2/search',
|
url: 'api/v1/accounts/lookup',
|
||||||
params: {
|
params: { acct: page.account.acct }
|
||||||
q: `@${page.account.acct}`,
|
|
||||||
type: 'accounts',
|
|
||||||
limit: '1'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.then(res => {
|
if (resLookup?.body) {
|
||||||
if (res?.body?.accounts?.length === 1) {
|
res = await apiGeneral<Mastodon.Account[]>({
|
||||||
return apiGeneral<Mastodon.Account[]>({
|
|
||||||
method: 'get',
|
method: 'get',
|
||||||
domain,
|
domain,
|
||||||
url: `api/v1/${page.reference}/${res.body.accounts[0].id}/${page.type}`,
|
url: `api/v1/${page.reference}/${resLookup.body.id}/${page.type}`,
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
.catch(() => {
|
return { ...res, remoteData: true }
|
||||||
return apiInstance<Mastodon.Account[]>({
|
|
||||||
method: 'get',
|
|
||||||
url: `${page.reference}/${page.account.id}/${page.type}`,
|
|
||||||
params
|
|
||||||
}).then(res => ({ ...res, warnIncomplete: true }))
|
|
||||||
})
|
|
||||||
.then(res => ({ ...res, warnIncomplete: false }))
|
|
||||||
} else {
|
} else {
|
||||||
return apiInstance<Mastodon.Account[]>({
|
throw new Error()
|
||||||
method: 'get',
|
|
||||||
url: `${page.reference}/${page.account.id}/${page.type}`,
|
|
||||||
params
|
|
||||||
}).then(res => ({ ...res, warnIncomplete: true }))
|
|
||||||
}
|
}
|
||||||
})
|
} catch {
|
||||||
.catch(() => {
|
res = await apiInstance<Mastodon.Account[]>({
|
||||||
return apiInstance<Mastodon.Account[]>({
|
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: `${page.reference}/${page.account.id}/${page.type}`,
|
url: `${page.reference}/${page.account.id}/${page.type}`,
|
||||||
params
|
params
|
||||||
}).then(res => ({ ...res, warnIncomplete: true }))
|
|
||||||
})
|
})
|
||||||
|
return { ...res, warnIncomplete: true }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,7 +79,7 @@ const useUsersQuery = ({
|
|||||||
...queryKeyParams
|
...queryKeyParams
|
||||||
}: QueryKeyUsers[1] & {
|
}: QueryKeyUsers[1] & {
|
||||||
options?: UseInfiniteQueryOptions<
|
options?: UseInfiniteQueryOptions<
|
||||||
InstanceResponse<Mastodon.Account[]> & { warnIncomplete: boolean },
|
PagedResponse<Mastodon.Account[]> & { warnIncomplete: boolean; remoteData: boolean },
|
||||||
AxiosError
|
AxiosError
|
||||||
>
|
>
|
||||||
}) => {
|
}) => {
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import { InstanceResponse } from '@api/instance'
|
import { PagedResponse } from '@api/helpers'
|
||||||
|
|
||||||
export const infinitePageParams = {
|
export const infinitePageParams = {
|
||||||
getPreviousPageParam: (firstPage: InstanceResponse<any>) =>
|
getPreviousPageParam: (firstPage: PagedResponse<any>) =>
|
||||||
firstPage.links?.prev && { min_id: firstPage.links.next },
|
firstPage.links?.prev && { min_id: firstPage.links.next },
|
||||||
getNextPageParam: (lastPage: InstanceResponse<any>) =>
|
getNextPageParam: (lastPage: PagedResponse<any>) =>
|
||||||
lastPage.links?.next && { max_id: lastPage.links.next }
|
lastPage.links?.next && { max_id: lastPage.links.next }
|
||||||
}
|
}
|
||||||
|
@@ -102,6 +102,7 @@ const addInstance = createAsyncThunk(
|
|||||||
mention: true,
|
mention: true,
|
||||||
poll: true,
|
poll: true,
|
||||||
status: true,
|
status: true,
|
||||||
|
update: true,
|
||||||
'admin.sign_up': false,
|
'admin.sign_up': false,
|
||||||
'admin.report': false
|
'admin.report': false
|
||||||
},
|
},
|
||||||
|
@@ -62,10 +62,9 @@ const pushRegister = async (
|
|||||||
'BMn2PLpZrMefG981elzG6SB1EY9gU7QZwmtZ/a/J2vUeWG+zXgeskMPwHh4T/bxsD4l7/8QT94F57CbZqYRRfJo='
|
'BMn2PLpZrMefG981elzG6SB1EY9gU7QZwmtZ/a/J2vUeWG+zXgeskMPwHh4T/bxsD4l7/8QT94F57CbZqYRRfJo='
|
||||||
)
|
)
|
||||||
formData.append('subscription[keys][auth]', auth)
|
formData.append('subscription[keys][auth]', auth)
|
||||||
Object.keys(alerts).map(key =>
|
for (const [key, value] of Object.entries(alerts)) {
|
||||||
// @ts-ignore
|
formData.append(`data[alerts][${key}]`, value.toString())
|
||||||
formData.append(`data[alerts][${key}]`, alerts[key].value.toString())
|
}
|
||||||
)
|
|
||||||
|
|
||||||
const res = await apiInstance<Mastodon.PushSubscription>({
|
const res = await apiInstance<Mastodon.PushSubscription>({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import features from '@helpers/features'
|
||||||
import {
|
import {
|
||||||
checkPermission,
|
checkPermission,
|
||||||
PERMISSION_MANAGE_REPORTS,
|
PERMISSION_MANAGE_REPORTS,
|
||||||
@@ -7,22 +8,59 @@ import queryClient from '@helpers/queryClient'
|
|||||||
import i18n from '@root/i18n/i18n'
|
import i18n from '@root/i18n/i18n'
|
||||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||||
import { queryFunctionProfile, QueryKeyProfile } from '@utils/queryHooks/profile'
|
import { queryFunctionProfile, QueryKeyProfile } from '@utils/queryHooks/profile'
|
||||||
|
import { checkInstanceFeature } from '@utils/slices/instancesSlice'
|
||||||
import * as Notifications from 'expo-notifications'
|
import * as Notifications from 'expo-notifications'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
export const PUSH_DEFAULT: [
|
export const usePushFeatures = () => {
|
||||||
'follow',
|
const hasTypeStatus = useSelector(checkInstanceFeature('notification_type_status'))
|
||||||
'follow_request',
|
const hasTypeUpdate = useSelector(checkInstanceFeature('notification_type_update'))
|
||||||
'favourite',
|
const hasTypeAdminSignup = useSelector(checkInstanceFeature('notification_type_admin_signup'))
|
||||||
'reblog',
|
const hasTypeAdminReport = useSelector(checkInstanceFeature('notification_type_admin_report'))
|
||||||
'mention',
|
return { hasTypeStatus, hasTypeUpdate, hasTypeAdminSignup, hasTypeAdminReport }
|
||||||
'poll',
|
}
|
||||||
'status'
|
|
||||||
] = ['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', 'status']
|
|
||||||
|
|
||||||
export const PUSH_ADMIN: { type: 'admin.sign_up' | 'admin.report'; permission: number }[] = [
|
export const PUSH_DEFAULT = ({
|
||||||
|
hasTypeUpdate,
|
||||||
|
hasTypeStatus
|
||||||
|
}: {
|
||||||
|
hasTypeUpdate: boolean
|
||||||
|
hasTypeStatus: boolean
|
||||||
|
}) =>
|
||||||
|
['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', 'update', 'status'].filter(
|
||||||
|
type => {
|
||||||
|
switch (type) {
|
||||||
|
case 'status':
|
||||||
|
return hasTypeStatus
|
||||||
|
case 'update':
|
||||||
|
return hasTypeUpdate
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) as ['follow', 'follow_request', 'favourite', 'reblog', 'mention', 'poll', 'update', 'status']
|
||||||
|
|
||||||
|
export const PUSH_ADMIN = (
|
||||||
|
{
|
||||||
|
hasTypeAdminSignup,
|
||||||
|
hasTypeAdminReport
|
||||||
|
}: {
|
||||||
|
hasTypeAdminSignup: boolean
|
||||||
|
hasTypeAdminReport: boolean
|
||||||
|
},
|
||||||
|
permissions?: string | number | undefined
|
||||||
|
) =>
|
||||||
|
[
|
||||||
{ type: 'admin.sign_up', permission: PERMISSION_MANAGE_USERS },
|
{ type: 'admin.sign_up', permission: PERMISSION_MANAGE_USERS },
|
||||||
{ type: 'admin.report', permission: PERMISSION_MANAGE_REPORTS }
|
{ type: 'admin.report', permission: PERMISSION_MANAGE_REPORTS }
|
||||||
]
|
].filter(({ type, permission }) => {
|
||||||
|
switch (type) {
|
||||||
|
case 'admin.sign_up':
|
||||||
|
return hasTypeAdminSignup && checkPermission(permission, permissions)
|
||||||
|
case 'admin.report':
|
||||||
|
return hasTypeAdminReport && checkPermission(permission, permissions)
|
||||||
|
}
|
||||||
|
}) as { type: 'admin.sign_up' | 'admin.report'; permission: number }[]
|
||||||
|
|
||||||
export const setChannels = async (instance: InstanceLatest) => {
|
export const setChannels = async (instance: InstanceLatest) => {
|
||||||
const account = `@${instance.account.acct}@${instance.uri}`
|
const account = `@${instance.account.acct}@${instance.uri}`
|
||||||
@@ -48,23 +86,32 @@ export const setChannels = async (instance: InstanceLatest) => {
|
|||||||
await Notifications.setNotificationChannelGroupAsync(account, { name: account })
|
await Notifications.setNotificationChannelGroupAsync(account, { name: account })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const checkFeature = (feature: string) =>
|
||||||
|
features
|
||||||
|
.filter(f => f.feature === feature)
|
||||||
|
.filter(f => parseFloat(instance.version) >= f.version)?.length > 0
|
||||||
|
const checkFeatures = {
|
||||||
|
hasTypeStatus: checkFeature('notification_type_status'),
|
||||||
|
hasTypeUpdate: checkFeature('notification_type_update'),
|
||||||
|
hasTypeAdminSignup: checkFeature('notification_type_admin_signup'),
|
||||||
|
hasTypeAdminReport: checkFeature('notification_type_admin_report')
|
||||||
|
}
|
||||||
|
|
||||||
if (!instance.push.decode) {
|
if (!instance.push.decode) {
|
||||||
await setChannel('default')
|
await setChannel('default')
|
||||||
for (const push of PUSH_DEFAULT) {
|
for (const push of PUSH_DEFAULT(checkFeatures)) {
|
||||||
await deleteChannel(push)
|
await deleteChannel(push)
|
||||||
}
|
}
|
||||||
for (const { type } of PUSH_ADMIN) {
|
for (const { type } of PUSH_ADMIN(checkFeatures, profileQuery.role?.permissions)) {
|
||||||
await deleteChannel(type)
|
await deleteChannel(type)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await deleteChannel('default')
|
await deleteChannel('default')
|
||||||
for (const push of PUSH_DEFAULT) {
|
for (const push of PUSH_DEFAULT(checkFeatures)) {
|
||||||
await setChannel(push)
|
await setChannel(push)
|
||||||
}
|
}
|
||||||
for (const { type, permission } of PUSH_ADMIN) {
|
for (const { type } of PUSH_ADMIN(checkFeatures, profileQuery.role?.permissions)) {
|
||||||
if (checkPermission(permission, profileQuery.role?.permissions)) {
|
|
||||||
await setChannel(type)
|
await setChannel(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@@ -10,10 +10,9 @@ export const updateInstancePushAlert = createAsyncThunk(
|
|||||||
alerts: InstanceLatest['push']['alerts']
|
alerts: InstanceLatest['push']['alerts']
|
||||||
}): Promise<InstanceLatest['push']['alerts']> => {
|
}): Promise<InstanceLatest['push']['alerts']> => {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
Object.keys(alerts).map(alert =>
|
for (const [key, value] of Object.entries(alerts)) {
|
||||||
// @ts-ignore
|
formData.append(`data[alerts][${key}]`, value.toString())
|
||||||
formData.append(`data[alerts][${alert}]`, alerts[alert].value.toString())
|
}
|
||||||
)
|
|
||||||
|
|
||||||
await apiInstance<Mastodon.PushSubscription>({
|
await apiInstance<Mastodon.PushSubscription>({
|
||||||
method: 'put',
|
method: 'put',
|
||||||
|
@@ -220,7 +220,8 @@ const instancesSlice = createSlice({
|
|||||||
// Update Instance Configuration
|
// Update Instance Configuration
|
||||||
.addCase(updateConfiguration.fulfilled, (state, action) => {
|
.addCase(updateConfiguration.fulfilled, (state, action) => {
|
||||||
const activeIndex = findInstanceActive(state.instances)
|
const activeIndex = findInstanceActive(state.instances)
|
||||||
state.instances[activeIndex].version = action.payload?.version || '0'
|
state.instances[activeIndex].version =
|
||||||
|
typeof action.payload.version === 'string' ? action.payload.version : '0'
|
||||||
state.instances[activeIndex].configuration = action.payload.configuration
|
state.instances[activeIndex].configuration = action.payload.configuration
|
||||||
})
|
})
|
||||||
.addCase(updateConfiguration.rejected, (_, action) => {
|
.addCase(updateConfiguration.rejected, (_, action) => {
|
||||||
@@ -250,6 +251,9 @@ const instancesSlice = createSlice({
|
|||||||
.addCase(checkEmojis.fulfilled, (state, action) => {
|
.addCase(checkEmojis.fulfilled, (state, action) => {
|
||||||
if (!action.payload || !action.payload.length) return
|
if (!action.payload || !action.payload.length) return
|
||||||
const activeIndex = findInstanceActive(state.instances)
|
const activeIndex = findInstanceActive(state.instances)
|
||||||
|
if (!Array.isArray(state.instances[activeIndex].frequentEmojis)) {
|
||||||
|
state.instances[activeIndex].frequentEmojis = []
|
||||||
|
}
|
||||||
state.instances[activeIndex].frequentEmojis = state.instances[
|
state.instances[activeIndex].frequentEmojis = state.instances[
|
||||||
activeIndex
|
activeIndex
|
||||||
]?.frequentEmojis?.filter(emoji => {
|
]?.frequentEmojis?.filter(emoji => {
|
||||||
|
255
yarn.lock
255
yarn.lock
@@ -2404,63 +2404,63 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa"
|
resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa"
|
||||||
integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==
|
integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==
|
||||||
|
|
||||||
"@react-navigation/bottom-tabs@^6.5.0":
|
"@react-navigation/bottom-tabs@^6.5.1":
|
||||||
version "6.5.0"
|
version "6.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.0.tgz#8bcd98733988ffe3e5124b45920608f22b2576e4"
|
resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.1.tgz#ef146502674e68736cbb47500ba1e3e481456869"
|
||||||
integrity sha512-7jKBHAk/HpIwXEsKKegB0DabPhFWS9PH2Bsmd4HUdvHj103m7H3OsrszuPB9Uxbe3RkGNtcJzeQnYOanVzNR+w==
|
integrity sha512-XhY3rdfI/lxiG/TfdxvYYKSJR6N6K42VEBBQX8yvGBq+7aeCKaX5D7MF6yiI6ViVZ8uPhGyh/MJM3srUW+Yj7w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@react-navigation/elements" "^1.3.10"
|
"@react-navigation/elements" "^1.3.11"
|
||||||
color "^4.2.3"
|
color "^4.2.3"
|
||||||
warn-once "^0.1.0"
|
warn-once "^0.1.0"
|
||||||
|
|
||||||
"@react-navigation/core@^6.4.4":
|
"@react-navigation/core@^6.4.5":
|
||||||
version "6.4.4"
|
version "6.4.5"
|
||||||
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.4.tgz#270ef88d3c3a225f9a58bbe89eb8a8bc96af44a9"
|
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.5.tgz#8254b25c476857d53a649af8e3fded0cbe6e1ded"
|
||||||
integrity sha512-skdTzr6sOceEusEDG+e58zaSpgy1Yz7eZGFtmkmdYAFkZDy5nkIY/0nYuXP0waUYarNXg6lNEVkF995/kZXHZg==
|
integrity sha512-wcde35HeOM5r2P25EwLQZyJ1yhXDGKuWpnKfsSI1xrgYIvWdYi3j/yGnwgNGDelCmtUt1Fyk2pmOv8sEku9KkA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@react-navigation/routers" "^6.1.5"
|
"@react-navigation/routers" "^6.1.6"
|
||||||
escape-string-regexp "^4.0.0"
|
escape-string-regexp "^4.0.0"
|
||||||
nanoid "^3.1.23"
|
nanoid "^3.1.23"
|
||||||
query-string "^7.1.3"
|
query-string "^7.1.3"
|
||||||
react-is "^16.13.0"
|
react-is "^16.13.0"
|
||||||
use-latest-callback "^0.1.5"
|
use-latest-callback "^0.1.5"
|
||||||
|
|
||||||
"@react-navigation/elements@^1.3.10":
|
"@react-navigation/elements@^1.3.11":
|
||||||
version "1.3.10"
|
version "1.3.11"
|
||||||
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.10.tgz#7f4281eddef5ff424169413daaab9a66b27c4949"
|
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.11.tgz#135c2cb3ae4a31bc835bb731110fd1ef9c38e237"
|
||||||
integrity sha512-JFaoZG9S+Zz291CvAMeGw8kNl/g2AaY9Pbo+VcYO+JM6UF/E5Obq9ga2ydxDrn3an7wzdl6flA/4lWhqG82Vqw==
|
integrity sha512-o4J0g4ofJbbn68e4TpuGkuZLtq5mLll7Ndz9C4O4RvD2chchLuGQ5TycIPTKP428cz8JzuTCFqUe/ZhOPSsudw==
|
||||||
|
|
||||||
"@react-navigation/native-stack@^6.9.5":
|
"@react-navigation/native-stack@^6.9.6":
|
||||||
version "6.9.5"
|
version "6.9.6"
|
||||||
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.5.tgz#805adf6699524519ff4bf50ac960a923da1bc223"
|
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.6.tgz#d88cc332f19415fa2c57b8f2b9a6fc2cabf9733e"
|
||||||
integrity sha512-1ZIrla+b4gB8KDC6QewtZ/1yOS23bQctwR4Pf6ECA0stEH8ibbxh70iiI/LluL5CtWxrWfgOrl1jpQsVvtKY+Q==
|
integrity sha512-Puqo5Y7MwYZvGELN73nMzaWTMdJu58stp9M809h4eoi4SzS0u/mFtypquEcW1gXdmRlDMmqXTtR/NBPSc2kLJg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@react-navigation/elements" "^1.3.10"
|
"@react-navigation/elements" "^1.3.11"
|
||||||
warn-once "^0.1.0"
|
warn-once "^0.1.0"
|
||||||
|
|
||||||
"@react-navigation/native@^6.1.0":
|
"@react-navigation/native@^6.1.1":
|
||||||
version "6.1.0"
|
version "6.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.1.0.tgz#ea0c79b6b0f67397305fec54eb4dbc3dd3eb087b"
|
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.1.1.tgz#79d91db04fbad277f355a10405516df4f67cd308"
|
||||||
integrity sha512-CdjOmbE4c/UczczqeP7ZrFXJcjnXOCwY1PDNjX51Ph1b2tHXpQ41/089k3R49dc5i2sFLk6jKaryFU2dcLr8jw==
|
integrity sha512-iIozx9c66EjSFyzKrZPixnk6vBuivYXp0jmbKCJXNIa7MY+8OLx9CXj/+1py/l/OGlXDhI6jiUWWetOfOtMaBQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@react-navigation/core" "^6.4.4"
|
"@react-navigation/core" "^6.4.5"
|
||||||
escape-string-regexp "^4.0.0"
|
escape-string-regexp "^4.0.0"
|
||||||
fast-deep-equal "^3.1.3"
|
fast-deep-equal "^3.1.3"
|
||||||
nanoid "^3.1.23"
|
nanoid "^3.1.23"
|
||||||
|
|
||||||
"@react-navigation/routers@^6.1.5":
|
"@react-navigation/routers@^6.1.6":
|
||||||
version "6.1.5"
|
version "6.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-6.1.5.tgz#b3e06bc09346ad94206bcc71c46538d5b6dc4883"
|
resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-6.1.6.tgz#f57f2a73855d329255aa225fdad75ae8e7700c6d"
|
||||||
integrity sha512-JzMRiRRu8J0yUMC7BV8wOVzevjkHnIPONbpCTL/vH5yceTm+dSH/U3esIObgk8wYYbov+jYlVhwUQNGRb2to6g==
|
integrity sha512-Z5DeCW3pUvMafbU9Cjy1qJYC2Bvl8iy3+PfsB0DsAwQ6zZ3WAXW5FTMX4Gb9H+Jg6qHWGbMFFwlYpS3UJ3tlVQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^3.1.23"
|
nanoid "^3.1.23"
|
||||||
|
|
||||||
"@react-navigation/stack@^6.3.8":
|
"@react-navigation/stack@^6.3.9":
|
||||||
version "6.3.8"
|
version "6.3.9"
|
||||||
resolved "https://registry.yarnpkg.com/@react-navigation/stack/-/stack-6.3.8.tgz#bc36beb4fba1c47a45e01c9dcc501be0f6f10d54"
|
resolved "https://registry.yarnpkg.com/@react-navigation/stack/-/stack-6.3.9.tgz#e4e2b6aa25973b3bc59200b7e3bf980e93cb5b4f"
|
||||||
integrity sha512-tnSmI5wmRLA293tPo43niCOOcWsWFB1XPGeUBVsz/lJnQZIHUUx0h42t53fU22DHGXee7PiZ78Lvr1Q0m/JZJQ==
|
integrity sha512-mTT0ZM/Zvp46s8UnphAspg2MR5Ds0mqZa/bEjzFgaYo+cLfjIXttUZYgsMG2fhvoTHpU7QFcZ/0kVhi4jVlzKQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@react-navigation/elements" "^1.3.10"
|
"@react-navigation/elements" "^1.3.11"
|
||||||
color "^4.2.3"
|
color "^4.2.3"
|
||||||
warn-once "^0.1.0"
|
warn-once "^0.1.0"
|
||||||
|
|
||||||
@@ -2482,14 +2482,14 @@
|
|||||||
component-type "^1.2.1"
|
component-type "^1.2.1"
|
||||||
join-component "^1.1.0"
|
join-component "^1.1.0"
|
||||||
|
|
||||||
"@sentry/browser@7.21.1":
|
"@sentry/browser@7.26.0":
|
||||||
version "7.21.1"
|
version "7.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.21.1.tgz#bffa3ea19050c06400107d2297b9802f9719f98b"
|
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.26.0.tgz#152d0f59df85be3ed8a7161b0ca90a4dca7b382d"
|
||||||
integrity sha512-cS2Jz2+fs9+4pJqLJPtYqGyY97ywJDWAWIR1Yla3hs1QQuH6m0Nz3ojZD1gE2eKH9mHwkGbnNAh+hHcrYrfGzw==
|
integrity sha512-S6uW+Ni2VLGHUV9eAUtTy5QEvqKeOhcnWnv+2yTGDtQCJ0SuHfXRCM7ASAQYBiKffZqIFc9Z2XNU/2cuWcXJmw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/core" "7.21.1"
|
"@sentry/core" "7.26.0"
|
||||||
"@sentry/types" "7.21.1"
|
"@sentry/types" "7.26.0"
|
||||||
"@sentry/utils" "7.21.1"
|
"@sentry/utils" "7.26.0"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
"@sentry/cli@1.74.4":
|
"@sentry/cli@1.74.4":
|
||||||
@@ -2518,83 +2518,83 @@
|
|||||||
proxy-from-env "^1.1.0"
|
proxy-from-env "^1.1.0"
|
||||||
which "^2.0.2"
|
which "^2.0.2"
|
||||||
|
|
||||||
"@sentry/core@7.21.1":
|
"@sentry/core@7.26.0":
|
||||||
version "7.21.1"
|
version "7.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.21.1.tgz#d0423282d90875625802dfe380f9657e9242b72b"
|
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.26.0.tgz#8f9fa439b40560edd09b464292d3084e1f16228f"
|
||||||
integrity sha512-Og5wEEsy24fNvT/T7IKjcV4EvVK5ryY2kxbJzKY6GU2eX+i+aBl+n/vp7U0Es351C/AlTkS+0NOUsp2TQQFxZA==
|
integrity sha512-ydi236ZoP/xpvLdf7B8seKjCcGc5Z+q9c14tHCFusplPZgLSXcYpiiLIDWmF7OAXO89sSbb1NaFt9YB0LkYdLQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/types" "7.21.1"
|
"@sentry/types" "7.26.0"
|
||||||
"@sentry/utils" "7.21.1"
|
"@sentry/utils" "7.26.0"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
"@sentry/hub@7.21.1":
|
"@sentry/hub@7.26.0":
|
||||||
version "7.21.1"
|
version "7.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.21.1.tgz#5c046fd2ca7eaf14cd0bf70617cc8b057f9b88ce"
|
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.26.0.tgz#a8d04c37384263439764f896ea0acbcf790dc521"
|
||||||
integrity sha512-WXQJ5z5iUZO6sOq3f7A3eIwvb/GoVJ3q5DQDTNF7HB/qcm11u5QPlAHTFBCsKJdT39NaE78JcMluiHZUWT+C5A==
|
integrity sha512-djAMuA4/Jy28dOSy9z5ccXBDyYk1N9m0ljle+dKqjfJwv440tCGyoxm2arqJFHbXvqwJTt2Giv8ASR4uGD1UNg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/core" "7.21.1"
|
"@sentry/core" "7.26.0"
|
||||||
"@sentry/types" "7.21.1"
|
"@sentry/types" "7.26.0"
|
||||||
"@sentry/utils" "7.21.1"
|
"@sentry/utils" "7.26.0"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
"@sentry/integrations@7.21.1":
|
"@sentry/integrations@7.26.0":
|
||||||
version "7.21.1"
|
version "7.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.21.1.tgz#8a5d5595521c4891cc2582f98d253a074ba54abc"
|
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.26.0.tgz#958e3ed52a37a14c6f11aebf11b485eca52e56aa"
|
||||||
integrity sha512-DbQZSdsqaD9RTy5WvLzonoJa2CIgeapnGfFOadnQGOD8A8GT9Bre/BgcQ5ksHqGnVfzYwpU26k/ue9gjXnI/Pg==
|
integrity sha512-5tyBA5BnZEuosSIvBP7mJz66xJaZTb/k1EzHEc0hR2Mw8QpLgMneDZBfi4vdbhxtGpJKC/gURoUGZf9hpwW+DA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/types" "7.21.1"
|
"@sentry/types" "7.26.0"
|
||||||
"@sentry/utils" "7.21.1"
|
"@sentry/utils" "7.26.0"
|
||||||
localforage "^1.8.1"
|
localforage "^1.8.1"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
"@sentry/react-native@4.11.0":
|
"@sentry/react-native@4.12.0":
|
||||||
version "4.11.0"
|
version "4.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-4.11.0.tgz#6820aa51ac2ed225daa0c02b58956588ad12dc62"
|
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-4.12.0.tgz#3eff5eb0d03e5abdf24b74a5d5221d4416ef97cf"
|
||||||
integrity sha512-dC8rPOabs/DNAC1Yc2mICo0vkMq+GmLEBxi2l8zIzf8e99Qii0zrGuVng9vc+PRwdBMQrKw7i17SlFEqsaoksA==
|
integrity sha512-KBRXXqqGg67oqhtGzZQ8Ls4rxxUozDyL8tMLmRLk//bkSWBC6XslyjkZkQrB1VZsv2ikEYCUgyAP7fzcj6Bbig==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/browser" "7.21.1"
|
"@sentry/browser" "7.26.0"
|
||||||
"@sentry/cli" "1.74.4"
|
"@sentry/cli" "1.74.4"
|
||||||
"@sentry/core" "7.21.1"
|
"@sentry/core" "7.26.0"
|
||||||
"@sentry/hub" "7.21.1"
|
"@sentry/hub" "7.26.0"
|
||||||
"@sentry/integrations" "7.21.1"
|
"@sentry/integrations" "7.26.0"
|
||||||
"@sentry/react" "7.21.1"
|
"@sentry/react" "7.26.0"
|
||||||
"@sentry/tracing" "7.21.1"
|
"@sentry/tracing" "7.26.0"
|
||||||
"@sentry/types" "7.21.1"
|
"@sentry/types" "7.26.0"
|
||||||
"@sentry/utils" "7.21.1"
|
"@sentry/utils" "7.26.0"
|
||||||
"@sentry/wizard" "1.4.0"
|
"@sentry/wizard" "1.4.0"
|
||||||
|
|
||||||
"@sentry/react@7.21.1":
|
"@sentry/react@7.26.0":
|
||||||
version "7.21.1"
|
version "7.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.21.1.tgz#275e6fd46212f608f382c7dde46d21e748f93491"
|
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.26.0.tgz#548e1d29083d0e4732f2828d8cb8f9d0a150ae4e"
|
||||||
integrity sha512-w91PIUyX07mErKgrBQA+7ID8zFKrYDUYSOrFSHufg5DdPq4EpHiNDe/Yngg3e9ELhtr1AbCnEvx9wlvqLi3nZQ==
|
integrity sha512-v5XKpG1PF4qnWvG8E0N1kcUk74lTp+TDfKx5x996NIja2oOTp/JL9V0Q+lAMlB1EKgJuxLe92IeqD5/DTtzE7A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/browser" "7.21.1"
|
"@sentry/browser" "7.26.0"
|
||||||
"@sentry/types" "7.21.1"
|
"@sentry/types" "7.26.0"
|
||||||
"@sentry/utils" "7.21.1"
|
"@sentry/utils" "7.26.0"
|
||||||
hoist-non-react-statics "^3.3.2"
|
hoist-non-react-statics "^3.3.2"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
"@sentry/tracing@7.21.1":
|
"@sentry/tracing@7.26.0":
|
||||||
version "7.21.1"
|
version "7.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.21.1.tgz#db02643e84960f1ea14b35fe75a93fc0bbca1fcb"
|
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.26.0.tgz#25105f8aec64a0e7113e09674d300190378b1daa"
|
||||||
integrity sha512-b1BTPsRaNQpohzegoz59KGuBl+To651vEq0vMS4tCzSyIdxkYso3JCrjDdEqW/2MliQYANNVrUai2bmwmU9h1g==
|
integrity sha512-UK8EiXxJrDTWD82Oasj2WP/QuQ+wzPlg74vYmxl1ie/LRs6C6wHkilBZwDV9HnDdqAqSjl0al8oBa075lK+U3Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/core" "7.21.1"
|
"@sentry/core" "7.26.0"
|
||||||
"@sentry/types" "7.21.1"
|
"@sentry/types" "7.26.0"
|
||||||
"@sentry/utils" "7.21.1"
|
"@sentry/utils" "7.26.0"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
"@sentry/types@7.21.1":
|
"@sentry/types@7.26.0":
|
||||||
version "7.21.1"
|
version "7.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.21.1.tgz#408a7b95a66ddc30c4359979594e03bee8f9fbdc"
|
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.26.0.tgz#2fe8a38a143797abecbcd53175ebf8bf736e18de"
|
||||||
integrity sha512-3/IKnd52Ol21amQvI+kz+WB76s8/LR5YvFJzMgIoI2S8d82smIr253zGijRXxHPEif8kMLX4Yt+36VzrLxg6+A==
|
integrity sha512-U2s0q3ALwWFdHJBgn8nrG9bCTJZ3hAqL/I2Si4Mf0ZWnJ/KTJKbtyrputHr8wMbHvX0NZTJGTxFVUO46J+GBRA==
|
||||||
|
|
||||||
"@sentry/utils@7.21.1":
|
"@sentry/utils@7.26.0":
|
||||||
version "7.21.1"
|
version "7.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.21.1.tgz#96582345178015fd32fe9159c25c44ccf2f99d2a"
|
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.26.0.tgz#4b501064c5220947f210aa2d59e9b8bf60677502"
|
||||||
integrity sha512-F0W0AAi8tgtTx6ApZRI2S9HbXEA9ENX1phTZgdNNWcMFm1BNbc21XEwLqwXBNjub5nlA6CE8xnjXRgdZKx4kzQ==
|
integrity sha512-nIC1PRyoMBi4QB7XNCWaPDqaQbPayMwAvUm6W3MC5bHPfVZmmFt+3sLZQKUD/E0NeQnJ3vTyPewPF/LfxLOE5A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sentry/types" "7.21.1"
|
"@sentry/types" "7.26.0"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
"@sentry/wizard@1.4.0":
|
"@sentry/wizard@1.4.0":
|
||||||
@@ -2660,17 +2660,17 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
defer-to-connect "^2.0.0"
|
defer-to-connect "^2.0.0"
|
||||||
|
|
||||||
"@tanstack/query-core@4.19.1":
|
"@tanstack/query-core@4.20.4":
|
||||||
version "4.19.1"
|
version "4.20.4"
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.19.1.tgz#2e92d9e8a50884eb231c5beb4386e131ebe34306"
|
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.20.4.tgz#1f7975a2db26a8bc2f382bad8a44cd422c846b17"
|
||||||
integrity sha512-Zp0aIose5C8skBzqbVFGk9HJsPtUhRVDVNWIqVzFbGQQgYSeLZMd3Sdb4+EnA5wl1J7X+bre2PJGnQg9x/zHOA==
|
integrity sha512-lhLtGVNJDsJ/DyZXrLzekDEywQqRVykgBqTmkv0La32a/RleILXy6JMLBb7UmS3QCatg/F/0N9/5b0i5j6IKcA==
|
||||||
|
|
||||||
"@tanstack/react-query@^4.19.1":
|
"@tanstack/react-query@^4.20.4":
|
||||||
version "4.19.1"
|
version "4.20.4"
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.19.1.tgz#43356dd537127e76d75f5a2769eb23dafd9a3690"
|
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.20.4.tgz#562b34fb919adea884eccaba2b5be50e8ba7fb16"
|
||||||
integrity sha512-5dvHvmc0vrWI03AJugzvKfirxCyCLe+qawrWFCXdu8t7dklIhJ7D5ZhgTypv7mMtIpdHPcECtCiT/+V74wCn2A==
|
integrity sha512-SJRxx13k/csb9lXAJfycgVA1N/yU/h3bvRNWP0+aHMfMjmbyX82FdoAcckDBbOdEyAupvb0byelNHNeypCFSyA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@tanstack/query-core" "4.19.1"
|
"@tanstack/query-core" "4.20.4"
|
||||||
use-sync-external-store "^1.2.0"
|
use-sync-external-store "^1.2.0"
|
||||||
|
|
||||||
"@types/cacheable-request@^6.0.1":
|
"@types/cacheable-request@^6.0.1":
|
||||||
@@ -2771,9 +2771,9 @@
|
|||||||
integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
|
integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "18.11.12"
|
version "18.11.15"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.12.tgz#89e7f8aa8c88abf432f9bd594888144d7dba10aa"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.15.tgz#de0e1fbd2b22b962d45971431e2ae696643d3f5d"
|
||||||
integrity sha512-FgD3NtTAKvyMmD44T07zz2fEf+OKwutgBCEVM8GcvMGVGaDktiLNTDvPwC/LUe3PinMW+X6CuLOF2Ui1mAlSXg==
|
integrity sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==
|
||||||
|
|
||||||
"@types/prop-types@*":
|
"@types/prop-types@*":
|
||||||
version "15.7.5"
|
version "15.7.5"
|
||||||
@@ -6369,9 +6369,9 @@ find-yarn-workspace-root@^2.0.0, find-yarn-workspace-root@~2.0.0:
|
|||||||
micromatch "^4.0.2"
|
micromatch "^4.0.2"
|
||||||
|
|
||||||
flow-parser@0.*:
|
flow-parser@0.*:
|
||||||
version "0.195.1"
|
version "0.196.0"
|
||||||
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.195.1.tgz#1f4017afd46c7873ed8dd9505f5fe5f00e08dd6c"
|
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.196.0.tgz#d62f85e02792fe625509a11343a8611ff976facd"
|
||||||
integrity sha512-8U3yQ8dny+CIsAjnH1QqpNw1mxLmqyp+0Mz/uh+YIH7srDkfabebwtFSnGv2m8yB2ZEPBrPwFYHe1kHKr/KQuw==
|
integrity sha512-739keKrDa+/5wpGFirMVK04elYMBjnwX2VH0WneKm3zx4K60ic8acJ6Ya6BekuHKLHIuz36ZUOQuGSUjc8D21A==
|
||||||
|
|
||||||
flow-parser@^0.121.0:
|
flow-parser@^0.121.0:
|
||||||
version "0.121.0"
|
version "0.121.0"
|
||||||
@@ -6604,7 +6604,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5:
|
|||||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||||
|
|
||||||
get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3:
|
get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
|
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
|
||||||
integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
|
integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
|
||||||
@@ -7186,10 +7186,10 @@ https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1:
|
|||||||
agent-base "6"
|
agent-base "6"
|
||||||
debug "4"
|
debug "4"
|
||||||
|
|
||||||
i18next@^22.4.1:
|
i18next@^22.4.5:
|
||||||
version "22.4.1"
|
version "22.4.5"
|
||||||
resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.4.1.tgz#90041c018ab93a59b6e09d6b20b35e5500f32827"
|
resolved "https://registry.yarnpkg.com/i18next/-/i18next-22.4.5.tgz#7324e4946c2facbe743ca25bca8980af05b0a109"
|
||||||
integrity sha512-BZWjrTX+OVaSxV5s94s2M+7wSlevdPgNtjeL/xXHl0CKkPGyjHNlkN6eN+0e0ex+EO8ec57OALRDUpiSSCo54g==
|
integrity sha512-Kc+Ow0guRetUq+kv02tj0Yof9zveROPBAmJ8UxxNODLVBRSwsM4iD0Gw3BEieOmkWemF6clU3K1fbnCuTqiN2Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.20.6"
|
"@babel/runtime" "^7.20.6"
|
||||||
|
|
||||||
@@ -7348,11 +7348,11 @@ internal-ip@4.3.0, internal-ip@^4.3.0:
|
|||||||
ipaddr.js "^1.9.0"
|
ipaddr.js "^1.9.0"
|
||||||
|
|
||||||
internal-slot@^1.0.3:
|
internal-slot@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
|
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3"
|
||||||
integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
|
integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
get-intrinsic "^1.1.0"
|
get-intrinsic "^1.1.3"
|
||||||
has "^1.0.3"
|
has "^1.0.3"
|
||||||
side-channel "^1.0.4"
|
side-channel "^1.0.4"
|
||||||
|
|
||||||
@@ -9167,9 +9167,9 @@ node-releases@^1.1.61:
|
|||||||
integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==
|
integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==
|
||||||
|
|
||||||
node-releases@^2.0.6:
|
node-releases@^2.0.6:
|
||||||
version "2.0.6"
|
version "2.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
|
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.7.tgz#593edbc7c22860ee4d32d3933cfebdfab0c0e0e5"
|
||||||
integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
|
integrity sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ==
|
||||||
|
|
||||||
node-stream-zip@^1.9.1:
|
node-stream-zip@^1.9.1:
|
||||||
version "1.15.0"
|
version "1.15.0"
|
||||||
@@ -10755,11 +10755,6 @@ react-native-language-detection@^0.2.2:
|
|||||||
resolved "https://registry.yarnpkg.com/react-native-language-detection/-/react-native-language-detection-0.2.2.tgz#4cc94177aa1c4575c4656f6d42456fa6c72ed5db"
|
resolved "https://registry.yarnpkg.com/react-native-language-detection/-/react-native-language-detection-0.2.2.tgz#4cc94177aa1c4575c4656f6d42456fa6c72ed5db"
|
||||||
integrity sha512-6u1JBgr+UG/GX/xMmT4K8CaBlSep4XfM91jwUzRA/Y3bMCHDx7bNVxGQvqvzkmOchby9h66XD8F5Eo+kV01CAA==
|
integrity sha512-6u1JBgr+UG/GX/xMmT4K8CaBlSep4XfM91jwUzRA/Y3bMCHDx7bNVxGQvqvzkmOchby9h66XD8F5Eo+kV01CAA==
|
||||||
|
|
||||||
react-native-live-text-image-view@^0.4.0:
|
|
||||||
version "0.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-native-live-text-image-view/-/react-native-live-text-image-view-0.4.0.tgz#d23d5850788609fd1448533213fc6c453c584761"
|
|
||||||
integrity sha512-PhVFE0YogSLrTlnHIxUWL80CrmbDvxk1JvLx4UHiRHRwLda4dV/e/9Q+Pyh7Vq7qwAPE6vGoN6sjbXNaj4WCew==
|
|
||||||
|
|
||||||
react-native-pager-view@^6.1.2:
|
react-native-pager-view@^6.1.2:
|
||||||
version "6.1.2"
|
version "6.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.1.2.tgz#3522079b9a9d6634ca5e8d153bc0b4d660254552"
|
resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.1.2.tgz#3522079b9a9d6634ca5e8d153bc0b4d660254552"
|
||||||
@@ -10814,10 +10809,10 @@ react-native-swipe-list-view@^3.2.9:
|
|||||||
resolved "https://registry.yarnpkg.com/react-native-swipe-list-view/-/react-native-swipe-list-view-3.2.9.tgz#d725c7cdf481dd5df12a00dbfe0120013b5f2e59"
|
resolved "https://registry.yarnpkg.com/react-native-swipe-list-view/-/react-native-swipe-list-view-3.2.9.tgz#d725c7cdf481dd5df12a00dbfe0120013b5f2e59"
|
||||||
integrity sha512-SjAEuHc/D6ovp+RjDUhfNmw6NYOntdT7+GFhfMGfP/BSLMuMWynpzJy9GKQeyB8sI78T6Lzip21TVbongOg1Mw==
|
integrity sha512-SjAEuHc/D6ovp+RjDUhfNmw6NYOntdT7+GFhfMGfP/BSLMuMWynpzJy9GKQeyB8sI78T6Lzip21TVbongOg1Mw==
|
||||||
|
|
||||||
react-native-tab-view@^3.3.3:
|
react-native-tab-view@^3.3.4:
|
||||||
version "3.3.3"
|
version "3.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.3.3.tgz#33a94db2ccbe7fe8fff0c0e3f1da09cbd07edba7"
|
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.3.4.tgz#856d4527f3bbf05e2649302ec80abe9f2f004666"
|
||||||
integrity sha512-hrxGu/Bj/GRXt+6ErqUFMAw2E82tjeTJ97nH1dZ2FSnLYOVnY9FDqju8TkQtT3GpJGL6Ur/ZkRT4eQfYwTZbtg==
|
integrity sha512-rceAYWpHa6knA7tsTnnjlcOxlCErR4F+yXQPpNm125IvYFyv09YRhE5uMU2IzyPIQ1CJvADCHurF3KySzVI+4Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
use-latest-callback "^0.1.5"
|
use-latest-callback "^0.1.5"
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user