Merge remote-tracking branch 'origin/main' into dm-composer
* origin/main: (32 commits) Don't call getProfiles if there are no actors (#10196) Update browserslist (#10195) Fix layout shift when liking a post on Android (#10190) Revert PostThread parent chunk size for native (#10193) Nightly source-language update Bump expo-paste-input (#10187) Add some more clarity to the RQ docs (#10120) [APP-2038] fix feeds not refreshing (#10167) [APP-1999] Fix ReportDialog Android hang by narrowing dependency arrays (#10171) Minor hotkeys nit (#10184) Fixes Hotkeys causing native to crash immediately on start (#10180) Nightly source-language update Fix OOM crash - disable tanstack extension integration (#10169) Create global keyboard shortcut handler (#10145) Warn when useState get/set names mismatch (#10166) Fix bottom bar badge text padding (#10162) Scale profile badge icons with font size (#10161) Add `no-extraneous-dependencies` and `no-nodejs-modules` eslint rules (#10151) Fix `useResolveUriQuery` (#10163) Nightly source-language update ...
This commit is contained in:
@@ -431,16 +431,30 @@ yarn intl:compile # Compile translations for runtime
|
|||||||
// src/state/queries/profile.ts
|
// src/state/queries/profile.ts
|
||||||
import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query'
|
import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
// Query key pattern
|
import {createQueryKey} from '#/state/queries/util'
|
||||||
const RQKEY_ROOT = 'profile'
|
|
||||||
export const RQKEY = (did: string) => [RQKEY_ROOT, did]
|
|
||||||
|
|
||||||
// Query hook
|
/*
|
||||||
|
* Query key name should match the query hook name for consistency
|
||||||
|
*/
|
||||||
|
const profileQueryKeyRoot = 'profile'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use object params and createQueryKey helper for better readability and to
|
||||||
|
* avoid bugs with parameter order or types.
|
||||||
|
*/
|
||||||
|
export const createProfileQueryKey = (args: {did: string}) =>
|
||||||
|
createQueryKey(profileQueryKeyRoot, args)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Query hook should be named use[Name]Query, where [Name] describes the data
|
||||||
|
* being fetched. This is not a strict requirement, but it's a helpful
|
||||||
|
* convention for discoverability
|
||||||
|
*/
|
||||||
export function useProfileQuery({did}: {did: string}) {
|
export function useProfileQuery({did}: {did: string}) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: RQKEY(did),
|
queryKey: createProfileQueryKey({did}),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.getProfile({actor: did})
|
const res = await agent.getProfile({actor: did})
|
||||||
return res.data
|
return res.data
|
||||||
@@ -450,8 +464,12 @@ export function useProfileQuery({did}: {did: string}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutation hook
|
/*
|
||||||
export function useUpdateProfile() {
|
* Mutation hook should match the name of the query hook, but with "Mutation"
|
||||||
|
* suffix. This is not a strict requirement, but it's a helpful convention for
|
||||||
|
* discoverability and consistency.
|
||||||
|
*/
|
||||||
|
export function useProfileMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
@@ -459,7 +477,9 @@ export function useUpdateProfile() {
|
|||||||
// Update logic
|
// Update logic
|
||||||
},
|
},
|
||||||
onSuccess: (_, variables) => {
|
onSuccess: (_, variables) => {
|
||||||
queryClient.invalidateQueries({queryKey: RQKEY(variables.did)})
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: createProfileQueryKey({did: variables.did}),
|
||||||
|
})
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
if (isNetworkError(error)) {
|
if (isNetworkError(error)) {
|
||||||
@@ -473,6 +493,24 @@ export function useUpdateProfile() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If cache mutation is needed, include specific interfaces for the specific
|
||||||
|
* mutations you require adjacent to the source queries. Naming should be
|
||||||
|
* descriptive of the mutation's purpose, e.g. use[Name]CacheMutation. This is
|
||||||
|
* not a strict requirement, but it's a helpful convention for discoverability
|
||||||
|
* and consistency.
|
||||||
|
*/
|
||||||
|
export function useProfileCacheMutation() {
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
return (data: Partial<Profile>) => {
|
||||||
|
queryClient.setQueryData(createProfileQueryKey({did: data.did}), oldData => {
|
||||||
|
if (!oldData) return oldData
|
||||||
|
return {...oldData, ...data}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Stale Time Constants** (from `src/state/queries/index.ts`):
|
**Stale Time Constants** (from `src/state/queries/index.ts`):
|
||||||
@@ -491,7 +529,7 @@ export function useDraftsQuery() {
|
|||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
|
||||||
return useInfiniteQuery({
|
return useInfiniteQuery({
|
||||||
queryKey: ['drafts'],
|
queryKey: createQueryKey('drafts'),
|
||||||
queryFn: async ({pageParam}) => {
|
queryFn: async ({pageParam}) => {
|
||||||
const res = await agent.app.bsky.draft.getDrafts({cursor: pageParam})
|
const res = await agent.app.bsky.draft.getDrafts({cursor: pageParam})
|
||||||
return res.data
|
return res.data
|
||||||
@@ -504,6 +542,19 @@ export function useDraftsQuery() {
|
|||||||
|
|
||||||
To get all items from pages: `data?.pages.flatMap(page => page.items) ?? []`
|
To get all items from pages: `data?.pages.flatMap(page => page.items) ?? []`
|
||||||
|
|
||||||
|
**Persisted Queries**
|
||||||
|
|
||||||
|
To persist query data across app restarts, `createQueryKey` supports a third
|
||||||
|
parameter called `options`, which has a `persistedVersion` property. When this
|
||||||
|
property is set to a number, the query will be persisted.
|
||||||
|
|
||||||
|
When this property is updated (e.g. incremented), the persisted data will be cleared and replaced with the new data from the query function. This is useful for cases where the shape of the data has changed and old persisted data would no longer be valid.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export const createProfileQueryKey = (args: {did: string}) =>
|
||||||
|
createQueryKey(profileQueryKeyRoot, args, {persistedVersion: 1})
|
||||||
|
```
|
||||||
|
|
||||||
### Preferences (React Context)
|
### Preferences (React Context)
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
|
|||||||
+14
-1
@@ -47,7 +47,6 @@ export default defineConfig(
|
|||||||
js.configs.recommended,
|
js.configs.recommended,
|
||||||
tseslint.configs.recommendedTypeChecked,
|
tseslint.configs.recommendedTypeChecked,
|
||||||
reactHooks.configs.flat.recommended,
|
reactHooks.configs.flat.recommended,
|
||||||
// @ts-expect-error https://github.com/un-ts/eslint-plugin-import-x/issues/439
|
|
||||||
importX.flatConfigs.recommended,
|
importX.flatConfigs.recommended,
|
||||||
importX.flatConfigs.typescript,
|
importX.flatConfigs.typescript,
|
||||||
importX.flatConfigs['react-native'],
|
importX.flatConfigs['react-native'],
|
||||||
@@ -62,6 +61,7 @@ export default defineConfig(
|
|||||||
'react-native': reactNative,
|
'react-native': reactNative,
|
||||||
'react-native-a11y': reactNativeA11y,
|
'react-native-a11y': reactNativeA11y,
|
||||||
'simple-import-sort': simpleImportSort,
|
'simple-import-sort': simpleImportSort,
|
||||||
|
// @ts-expect-error - not sure why
|
||||||
lingui,
|
lingui,
|
||||||
'react-compiler': reactCompiler,
|
'react-compiler': reactCompiler,
|
||||||
'bsky-internal': bskyInternal,
|
'bsky-internal': bskyInternal,
|
||||||
@@ -127,6 +127,7 @@ export default defineConfig(
|
|||||||
*/
|
*/
|
||||||
...react.configs.recommended.rules,
|
...react.configs.recommended.rules,
|
||||||
...react.configs['jsx-runtime'].rules,
|
...react.configs['jsx-runtime'].rules,
|
||||||
|
'react/hook-use-state': 'warn',
|
||||||
'react/no-unescaped-entities': 'off',
|
'react/no-unescaped-entities': 'off',
|
||||||
'react/prop-types': 'off',
|
'react/prop-types': 'off',
|
||||||
'react-native/no-inline-styles': 'off',
|
'react-native/no-inline-styles': 'off',
|
||||||
@@ -189,6 +190,18 @@ export default defineConfig(
|
|||||||
*/
|
*/
|
||||||
ignore: ['^#\/locale\/locales\/.+\/messages'],
|
ignore: ['^#\/locale\/locales\/.+\/messages'],
|
||||||
}],
|
}],
|
||||||
|
'import-x/no-extraneous-dependencies': ['error', {
|
||||||
|
'whitelist': [
|
||||||
|
// test files only
|
||||||
|
'@jest/globals',
|
||||||
|
// we only use a really simple util from this, and we know it will be present
|
||||||
|
'expo-modules-core',
|
||||||
|
// this is a dep for @atproto/api, but we absolutely need them in sync, so just
|
||||||
|
// rely on the transient version
|
||||||
|
'@atproto/common-web',
|
||||||
|
]
|
||||||
|
}],
|
||||||
|
'import-x/no-nodejs-modules': 'error',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TypeScript-specific rules
|
* TypeScript-specific rules
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ function getTagName(node) {
|
|||||||
return reversedIdentifiers.reverse().join('.')
|
return reversedIdentifiers.reverse().join('.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {import('eslint').Rule.RuleModule} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
meta: {
|
meta: {
|
||||||
type: 'problem',
|
type: 'problem',
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const BANNED_IMPORTS = [
|
|||||||
'@fortawesome/free-solid-svg-icons',
|
'@fortawesome/free-solid-svg-icons',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/** @type {import('eslint').Rule.RuleModule} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
meta: {
|
meta: {
|
||||||
type: 'suggestion',
|
type: 'suggestion',
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const BANNED_IMPORT_PREFIXES = [
|
|||||||
'view/',
|
'view/',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/** @type {import('eslint').Rule.RuleModule} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
meta: {
|
meta: {
|
||||||
type: 'suggestion',
|
type: 'suggestion',
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ jest.mock('@react-native-async-storage/async-storage', () =>
|
|||||||
require('@react-native-async-storage/async-storage/jest/async-storage-mock'),
|
require('@react-native-async-storage/async-storage/jest/async-storage-mock'),
|
||||||
)
|
)
|
||||||
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter', () => {
|
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter', () => {
|
||||||
|
// eslint-disable-next-line import-x/no-nodejs-modules
|
||||||
const {EventEmitter} = require('events')
|
const {EventEmitter} = require('events')
|
||||||
return {
|
return {
|
||||||
__esModule: true,
|
__esModule: true,
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
import {GestureHandlerRootView} from 'react-native-gesture-handler'
|
|
||||||
import {SafeAreaProvider} from 'react-native-safe-area-context'
|
|
||||||
import {render} from '@testing-library/react-native'
|
|
||||||
|
|
||||||
import {ThemeProvider} from '../src/lib/ThemeContext'
|
|
||||||
import {type RootStoreModel, RootStoreProvider} from '../src/state'
|
|
||||||
|
|
||||||
const customRender = (ui: any, rootStore: RootStoreModel) =>
|
|
||||||
render(
|
|
||||||
<GestureHandlerRootView style={{flex: 1}}>
|
|
||||||
<RootStoreProvider value={rootStore}>
|
|
||||||
<ThemeProvider theme="light">
|
|
||||||
<SafeAreaProvider>{ui}</SafeAreaProvider>
|
|
||||||
</ThemeProvider>
|
|
||||||
</RootStoreProvider>
|
|
||||||
</GestureHandlerRootView>,
|
|
||||||
)
|
|
||||||
|
|
||||||
// re-export everything
|
|
||||||
export * from '@testing-library/react-native'
|
|
||||||
|
|
||||||
// override render method
|
|
||||||
export {customRender as render}
|
|
||||||
+9
-9
@@ -81,7 +81,7 @@
|
|||||||
"icons:optimize": "svgo -f ./assets/icons"
|
"icons:optimize": "svgo -f ./assets/icons"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atproto/api": "^0.19.3",
|
"@atproto/api": "^0.19.5",
|
||||||
"@bitdrift/react-native": "^0.6.8",
|
"@bitdrift/react-native": "^0.6.8",
|
||||||
"@braintree/sanitize-url": "^6.0.2",
|
"@braintree/sanitize-url": "^6.0.2",
|
||||||
"@bsky.app/alf": "^0.1.7",
|
"@bsky.app/alf": "^0.1.7",
|
||||||
@@ -111,7 +111,6 @@
|
|||||||
"@ipld/dag-cbor": "^9.2.0",
|
"@ipld/dag-cbor": "^9.2.0",
|
||||||
"@lingui/core": "^5.9.2",
|
"@lingui/core": "^5.9.2",
|
||||||
"@lingui/react": "^5.9.2",
|
"@lingui/react": "^5.9.2",
|
||||||
"@mattermost/react-native-paste-input": "mattermost/react-native-paste-input",
|
|
||||||
"@miblanchard/react-native-slider": "^2.6.0",
|
"@miblanchard/react-native-slider": "^2.6.0",
|
||||||
"@mozzius/expo-dynamic-app-icon": "^1.8.0",
|
"@mozzius/expo-dynamic-app-icon": "^1.8.0",
|
||||||
"@react-native-async-storage/async-storage": "2.2.0",
|
"@react-native-async-storage/async-storage": "2.2.0",
|
||||||
@@ -119,9 +118,9 @@
|
|||||||
"@react-navigation/native": "^7.1.33",
|
"@react-navigation/native": "^7.1.33",
|
||||||
"@react-navigation/native-stack": "^7.14.4",
|
"@react-navigation/native-stack": "^7.14.4",
|
||||||
"@sentry/react-native": "~6.20.0",
|
"@sentry/react-native": "~6.20.0",
|
||||||
"@tanstack/query-async-storage-persister": "^5.25.0",
|
"@tanstack/query-async-storage-persister": "^5.96.2",
|
||||||
"@tanstack/react-query": "5.25.0",
|
"@tanstack/react-query": "^5.96.2",
|
||||||
"@tanstack/react-query-persist-client": "^5.25.0",
|
"@tanstack/react-query-persist-client": "^5.96.2",
|
||||||
"@tiptap/core": "^2.9.1",
|
"@tiptap/core": "^2.9.1",
|
||||||
"@tiptap/extension-document": "^2.9.1",
|
"@tiptap/extension-document": "^2.9.1",
|
||||||
"@tiptap/extension-hard-break": "^2.9.1",
|
"@tiptap/extension-hard-break": "^2.9.1",
|
||||||
@@ -169,6 +168,7 @@
|
|||||||
"expo-location": "~19.0.8",
|
"expo-location": "~19.0.8",
|
||||||
"expo-media-library": "~18.2.1",
|
"expo-media-library": "~18.2.1",
|
||||||
"expo-notifications": "~0.32.16",
|
"expo-notifications": "~0.32.16",
|
||||||
|
"expo-paste-input": "^0.1.12",
|
||||||
"expo-privacy-sensitive": "^0.1.0",
|
"expo-privacy-sensitive": "^0.1.0",
|
||||||
"expo-screen-orientation": "~9.0.8",
|
"expo-screen-orientation": "~9.0.8",
|
||||||
"expo-sharing": "~14.0.8",
|
"expo-sharing": "~14.0.8",
|
||||||
@@ -202,6 +202,7 @@
|
|||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-compiler-runtime": "^19.1.0-rc.1",
|
"react-compiler-runtime": "^19.1.0-rc.1",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
|
"react-hotkeys-hook": "5.2.4",
|
||||||
"react-image-crop": "^11.0.7",
|
"react-image-crop": "^11.0.7",
|
||||||
"react-is": "19",
|
"react-is": "19",
|
||||||
"react-keyed-flatten-children": "^5.0.0",
|
"react-keyed-flatten-children": "^5.0.0",
|
||||||
@@ -249,7 +250,6 @@
|
|||||||
"@lingui/cli": "^5.9.2",
|
"@lingui/cli": "^5.9.2",
|
||||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
|
||||||
"@react-native/babel-preset": "0.81.5",
|
"@react-native/babel-preset": "0.81.5",
|
||||||
"@react-native/eslint-config": "^0.81.5",
|
|
||||||
"@react-native/typescript-config": "^0.81.5",
|
"@react-native/typescript-config": "^0.81.5",
|
||||||
"@sentry/webpack-plugin": "^3.2.2",
|
"@sentry/webpack-plugin": "^3.2.2",
|
||||||
"@testing-library/react-native": "^13.2.0",
|
"@testing-library/react-native": "^13.2.0",
|
||||||
@@ -267,8 +267,8 @@
|
|||||||
"eslint": "^9.39.2",
|
"eslint": "^9.39.2",
|
||||||
"eslint-import-resolver-typescript": "^4.4.4",
|
"eslint-import-resolver-typescript": "^4.4.4",
|
||||||
"eslint-plugin-bsky-internal": "link:./eslint",
|
"eslint-plugin-bsky-internal": "link:./eslint",
|
||||||
"eslint-plugin-import-x": "^4.16.1",
|
"eslint-plugin-import-x": "^4.16.2",
|
||||||
"eslint-plugin-lingui": "^0.11.0",
|
"eslint-plugin-lingui": "^0.12.0",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"eslint-plugin-react-compiler": "^19.1.0-rc.2",
|
"eslint-plugin-react-compiler": "^19.1.0-rc.2",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
@@ -290,7 +290,7 @@
|
|||||||
"svgo": "^3.3.2",
|
"svgo": "^3.3.2",
|
||||||
"ts-plugin-sort-import-suggestions": "^1.0.4",
|
"ts-plugin-sort-import-suggestions": "^1.0.4",
|
||||||
"typescript": "^6.0.2",
|
"typescript": "^6.0.2",
|
||||||
"typescript-eslint": "^8.57.2",
|
"typescript-eslint": "^8.58.0",
|
||||||
"webpack-bundle-analyzer": "^4.10.1"
|
"webpack-bundle-analyzer": "^4.10.1"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
diff --git a/node_modules/@mattermost/react-native-paste-input/android/src/main/java/com/mattermost/pasteinputtext/PasteTextInputManager.kt b/node_modules/@mattermost/react-native-paste-input/android/src/main/java/com/mattermost/pasteinputtext/PasteTextInputManager.kt
|
|
||||||
index 4ed2307..ede1181 100644
|
|
||||||
--- a/node_modules/@mattermost/react-native-paste-input/android/src/main/java/com/mattermost/pasteinputtext/PasteTextInputManager.kt
|
|
||||||
+++ b/node_modules/@mattermost/react-native-paste-input/android/src/main/java/com/mattermost/pasteinputtext/PasteTextInputManager.kt
|
|
||||||
@@ -54,7 +54,7 @@ class PasteTextInputManager(context: ReactApplicationContext) : ReactTextInputMa
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
|
|
||||||
- val map = super.getExportedCustomBubblingEventTypeConstants()!!
|
|
||||||
+ val map = super.getExportedCustomBubblingEventTypeConstants().toMutableMap()
|
|
||||||
map["onPaste"] = MapBuilder.of(
|
|
||||||
"phasedRegistrationNames",
|
|
||||||
MapBuilder.of("bubbled", "onPaste")
|
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m b/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m
|
|
||||||
index e916023..5049c33 100644
|
|
||||||
--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m
|
|
||||||
+++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteInputView.m
|
|
||||||
@@ -4,6 +4,7 @@
|
|
||||||
//
|
|
||||||
// Created by Elias Nahum on 04-11-20.
|
|
||||||
// Copyright © 2020 Facebook. All rights reserved.
|
|
||||||
+// Updated to remove parent’s default text view
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "PasteInputView.h"
|
|
||||||
@@ -12,49 +13,78 @@
|
|
||||||
|
|
||||||
@implementation PasteInputView
|
|
||||||
{
|
|
||||||
- PasteInputTextView *_backedTextInputView;
|
|
||||||
+ // We'll store the custom text view in this ivar
|
|
||||||
+ PasteInputTextView *_customBackedTextView;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype)initWithBridge:(RCTBridge *)bridge
|
|
||||||
{
|
|
||||||
+ // Must call the super’s designated initializer
|
|
||||||
if (self = [super initWithBridge:bridge]) {
|
|
||||||
- _backedTextInputView = [[PasteInputTextView alloc] initWithFrame:self.bounds];
|
|
||||||
- _backedTextInputView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
||||||
- _backedTextInputView.textInputDelegate = self;
|
|
||||||
+ // 1. The parent (RCTMultilineTextInputView) has already created
|
|
||||||
+ // its own _backedTextInputView = [RCTUITextView new] in super init.
|
|
||||||
+ // We can remove that subview:
|
|
||||||
|
|
||||||
- [self addSubview:_backedTextInputView];
|
|
||||||
- }
|
|
||||||
+ id<RCTBackedTextInputViewProtocol> parentInputView = super.backedTextInputView;
|
|
||||||
+ if ([parentInputView isKindOfClass:[UIView class]]) {
|
|
||||||
+ UIView *parentSubview = (UIView *)parentInputView;
|
|
||||||
+ if (parentSubview.superview == self) {
|
|
||||||
+ [parentSubview removeFromSuperview];
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
|
|
||||||
+ // 2. Now create our custom PasteInputTextView
|
|
||||||
+ _customBackedTextView = [[PasteInputTextView alloc] initWithFrame:self.bounds];
|
|
||||||
+ _customBackedTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
||||||
+ _customBackedTextView.textInputDelegate = self;
|
|
||||||
+
|
|
||||||
+ // Optional: disable inline predictions for iOS 17+
|
|
||||||
+ if (@available(iOS 17.0, *)) {
|
|
||||||
+ _customBackedTextView.inlinePredictionType = UITextInlinePredictionTypeNo;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // 3. Add your custom text view as the only subview
|
|
||||||
+ [self addSubview:_customBackedTextView];
|
|
||||||
+ }
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
+/**
|
|
||||||
+ * Override the parent's accessor so that anywhere in RN that calls
|
|
||||||
+ * `self.backedTextInputView` will get the custom PasteInputTextView.
|
|
||||||
+ */
|
|
||||||
- (id<RCTBackedTextInputViewProtocol>)backedTextInputView
|
|
||||||
{
|
|
||||||
- return _backedTextInputView;
|
|
||||||
+ return _customBackedTextView;
|
|
||||||
}
|
|
||||||
|
|
||||||
-- (void)setDisableCopyPaste:(BOOL)disableCopyPaste {
|
|
||||||
- _backedTextInputView.disableCopyPaste = disableCopyPaste;
|
|
||||||
+#pragma mark - Setters for React Props
|
|
||||||
+
|
|
||||||
+- (void)setDisableCopyPaste:(BOOL)disableCopyPaste
|
|
||||||
+{
|
|
||||||
+ _customBackedTextView.disableCopyPaste = disableCopyPaste;
|
|
||||||
}
|
|
||||||
|
|
||||||
-- (void)setOnPaste:(RCTDirectEventBlock)onPaste {
|
|
||||||
- _backedTextInputView.onPaste = onPaste;
|
|
||||||
+- (void)setOnPaste:(RCTDirectEventBlock)onPaste
|
|
||||||
+{
|
|
||||||
+ _customBackedTextView.onPaste = onPaste;
|
|
||||||
}
|
|
||||||
|
|
||||||
-- (void)setSmartPunctuation:(NSString *)smartPunctuation {
|
|
||||||
- if ([smartPunctuation isEqualToString:@"enable"]) {
|
|
||||||
- [_backedTextInputView setSmartDashesType:UITextSmartDashesTypeYes];
|
|
||||||
- [_backedTextInputView setSmartQuotesType:UITextSmartQuotesTypeYes];
|
|
||||||
- [_backedTextInputView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeYes];
|
|
||||||
- } else if ([smartPunctuation isEqualToString:@"disable"]) {
|
|
||||||
- [_backedTextInputView setSmartDashesType:UITextSmartDashesTypeNo];
|
|
||||||
- [_backedTextInputView setSmartQuotesType:UITextSmartQuotesTypeNo];
|
|
||||||
- [_backedTextInputView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeNo];
|
|
||||||
- } else {
|
|
||||||
- [_backedTextInputView setSmartDashesType:UITextSmartDashesTypeDefault];
|
|
||||||
- [_backedTextInputView setSmartQuotesType:UITextSmartQuotesTypeDefault];
|
|
||||||
- [_backedTextInputView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeDefault];
|
|
||||||
- }
|
|
||||||
+- (void)setSmartPunctuation:(NSString *)smartPunctuation
|
|
||||||
+{
|
|
||||||
+ if ([smartPunctuation isEqualToString:@"enable"]) {
|
|
||||||
+ [_customBackedTextView setSmartDashesType:UITextSmartDashesTypeYes];
|
|
||||||
+ [_customBackedTextView setSmartQuotesType:UITextSmartQuotesTypeYes];
|
|
||||||
+ [_customBackedTextView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeYes];
|
|
||||||
+ } else if ([smartPunctuation isEqualToString:@"disable"]) {
|
|
||||||
+ [_customBackedTextView setSmartDashesType:UITextSmartDashesTypeNo];
|
|
||||||
+ [_customBackedTextView setSmartQuotesType:UITextSmartQuotesTypeNo];
|
|
||||||
+ [_customBackedTextView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeNo];
|
|
||||||
+ } else {
|
|
||||||
+ [_customBackedTextView setSmartDashesType:UITextSmartDashesTypeDefault];
|
|
||||||
+ [_customBackedTextView setSmartQuotesType:UITextSmartQuotesTypeDefault];
|
|
||||||
+ [_customBackedTextView setSmartInsertDeleteType:UITextSmartInsertDeleteTypeDefault];
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - UIScrollViewDelegate
|
|
||||||
@@ -62,7 +92,6 @@ - (void)setSmartPunctuation:(NSString *)smartPunctuation {
|
|
||||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
|
||||||
{
|
|
||||||
RCTDirectEventBlock onScroll = self.onScroll;
|
|
||||||
-
|
|
||||||
if (onScroll) {
|
|
||||||
CGPoint contentOffset = scrollView.contentOffset;
|
|
||||||
CGSize contentSize = scrollView.contentSize;
|
|
||||||
@@ -71,22 +100,22 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
|
||||||
|
|
||||||
onScroll(@{
|
|
||||||
@"contentOffset": @{
|
|
||||||
- @"x": @(contentOffset.x),
|
|
||||||
- @"y": @(contentOffset.y)
|
|
||||||
+ @"x": @(contentOffset.x),
|
|
||||||
+ @"y": @(contentOffset.y)
|
|
||||||
},
|
|
||||||
@"contentInset": @{
|
|
||||||
- @"top": @(contentInset.top),
|
|
||||||
- @"left": @(contentInset.left),
|
|
||||||
- @"bottom": @(contentInset.bottom),
|
|
||||||
- @"right": @(contentInset.right)
|
|
||||||
+ @"top": @(contentInset.top),
|
|
||||||
+ @"left": @(contentInset.left),
|
|
||||||
+ @"bottom": @(contentInset.bottom),
|
|
||||||
+ @"right": @(contentInset.right)
|
|
||||||
},
|
|
||||||
@"contentSize": @{
|
|
||||||
- @"width": @(contentSize.width),
|
|
||||||
- @"height": @(contentSize.height)
|
|
||||||
+ @"width": @(contentSize.width),
|
|
||||||
+ @"height": @(contentSize.height)
|
|
||||||
},
|
|
||||||
@"layoutMeasurement": @{
|
|
||||||
- @"width": @(size.width),
|
|
||||||
- @"height": @(size.height)
|
|
||||||
+ @"width": @(size.width),
|
|
||||||
+ @"height": @(size.height)
|
|
||||||
},
|
|
||||||
@"zoomScale": @(scrollView.zoomScale ?: 1),
|
|
||||||
});
|
|
||||||
diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInput.mm b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInput.mm
|
|
||||||
index dd50053..2ed7017 100644
|
|
||||||
--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInput.mm
|
|
||||||
+++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInput.mm
|
|
||||||
@@ -122,8 +122,8 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
|
|
||||||
const auto &newTextInputProps = static_cast<const PasteTextInputProps &>(*props);
|
|
||||||
|
|
||||||
// Traits:
|
|
||||||
- if (newTextInputProps.traits.multiline != oldTextInputProps.traits.multiline) {
|
|
||||||
- [self _setMultiline:newTextInputProps.traits.multiline];
|
|
||||||
+ if (newTextInputProps.multiline != oldTextInputProps.multiline) {
|
|
||||||
+ [self _setMultiline:newTextInputProps.multiline];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newTextInputProps.traits.autocapitalizationType != oldTextInputProps.traits.autocapitalizationType) {
|
|
||||||
@@ -421,7 +421,7 @@ - (void)textInputDidChangeSelection
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto &props = static_cast<const PasteTextInputProps &>(*_props);
|
|
||||||
- if (props.traits.multiline && ![_lastStringStateWasUpdatedWith isEqual:_backedTextInputView.attributedText]) {
|
|
||||||
+ if (props.multiline && ![_lastStringStateWasUpdatedWith isEqual:_backedTextInputView.attributedText]) {
|
|
||||||
[self textInputDidChange];
|
|
||||||
_ignoreNextTextInputCall = YES;
|
|
||||||
}
|
|
||||||
@@ -708,11 +708,11 @@ - (BOOL)_textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldTe
|
|
||||||
- (SubmitBehavior)getSubmitBehavior
|
|
||||||
{
|
|
||||||
const auto &props = static_cast<const PasteTextInputProps &>(*_props);
|
|
||||||
- const SubmitBehavior submitBehaviorDefaultable = props.traits.submitBehavior;
|
|
||||||
+ const SubmitBehavior submitBehaviorDefaultable = props.submitBehavior;
|
|
||||||
|
|
||||||
// We should always have a non-default `submitBehavior`, but in case we don't, set it based on multiline.
|
|
||||||
if (submitBehaviorDefaultable == SubmitBehavior::Default) {
|
|
||||||
- return props.traits.multiline ? SubmitBehavior::Newline : SubmitBehavior::BlurAndSubmit;
|
|
||||||
+ return props.multiline ? SubmitBehavior::Newline : SubmitBehavior::BlurAndSubmit;
|
|
||||||
}
|
|
||||||
|
|
||||||
return submitBehaviorDefaultable;
|
|
||||||
diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.cpp b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.cpp
|
|
||||||
index 29e094f..7ef519a 100644
|
|
||||||
--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.cpp
|
|
||||||
+++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.cpp
|
|
||||||
@@ -22,8 +22,7 @@ PasteTextInputProps::PasteTextInputProps(
|
|
||||||
const PropsParserContext &context,
|
|
||||||
const PasteTextInputProps &sourceProps,
|
|
||||||
const RawProps& rawProps)
|
|
||||||
- : ViewProps(context, sourceProps, rawProps),
|
|
||||||
- BaseTextProps(context, sourceProps, rawProps),
|
|
||||||
+ : BaseTextInputProps(context, sourceProps, rawProps),
|
|
||||||
traits(convertRawProp(context, rawProps, sourceProps.traits, {})),
|
|
||||||
smartPunctuation(convertRawProp(context, rawProps, "smartPunctuation", sourceProps.smartPunctuation, {})),
|
|
||||||
disableCopyPaste(convertRawProp(context, rawProps, "disableCopyPaste", sourceProps.disableCopyPaste, {false})),
|
|
||||||
@@ -133,7 +132,7 @@ TextAttributes PasteTextInputProps::getEffectiveTextAttributes(Float fontSizeMul
|
|
||||||
ParagraphAttributes PasteTextInputProps::getEffectiveParagraphAttributes() const {
|
|
||||||
auto result = paragraphAttributes;
|
|
||||||
|
|
||||||
- if (!traits.multiline) {
|
|
||||||
+ if (!multiline) {
|
|
||||||
result.maximumNumberOfLines = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.h b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.h
|
|
||||||
index 723d00c..31cfe66 100644
|
|
||||||
--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.h
|
|
||||||
+++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/Props.h
|
|
||||||
@@ -15,6 +15,7 @@
|
|
||||||
#include <react/renderer/components/iostextinput/conversions.h>
|
|
||||||
#include <react/renderer/components/iostextinput/primitives.h>
|
|
||||||
#include <react/renderer/components/text/BaseTextProps.h>
|
|
||||||
+#include <react/renderer/components/textinput/BaseTextInputProps.h>
|
|
||||||
#include <react/renderer/components/view/ViewProps.h>
|
|
||||||
#include <react/renderer/core/Props.h>
|
|
||||||
#include <react/renderer/core/PropsParserContext.h>
|
|
||||||
@@ -25,7 +26,7 @@
|
|
||||||
|
|
||||||
namespace facebook::react {
|
|
||||||
|
|
||||||
-class PasteTextInputProps final : public ViewProps, public BaseTextProps {
|
|
||||||
+class PasteTextInputProps final : public BaseTextInputProps {
|
|
||||||
public:
|
|
||||||
PasteTextInputProps() = default;
|
|
||||||
PasteTextInputProps(const PropsParserContext& context, const PasteTextInputProps& sourceProps, const RawProps& rawProps);
|
|
||||||
diff --git a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/ShadowNodes.cpp b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/ShadowNodes.cpp
|
|
||||||
index 31e07e3..7f0ebfb 100644
|
|
||||||
--- a/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/ShadowNodes.cpp
|
|
||||||
+++ b/node_modules/@mattermost/react-native-paste-input/ios/PasteTextInputSpecs/ShadowNodes.cpp
|
|
||||||
@@ -91,20 +91,11 @@ void PasteTextInputShadowNode::updateStateIfNeeded(
|
|
||||||
const auto& state = getStateData();
|
|
||||||
|
|
||||||
react_native_assert(textLayoutManager_);
|
|
||||||
- react_native_assert(
|
|
||||||
- (!state.layoutManager || state.layoutManager == textLayoutManager_) &&
|
|
||||||
- "`StateData` refers to a different `TextLayoutManager`");
|
|
||||||
-
|
|
||||||
- if (state.reactTreeAttributedString == reactTreeAttributedString &&
|
|
||||||
- state.layoutManager == textLayoutManager_) {
|
|
||||||
- return;
|
|
||||||
- }
|
|
||||||
|
|
||||||
auto newState = TextInputState{};
|
|
||||||
newState.attributedStringBox = AttributedStringBox{reactTreeAttributedString};
|
|
||||||
newState.paragraphAttributes = getConcreteProps().paragraphAttributes;
|
|
||||||
newState.reactTreeAttributedString = reactTreeAttributedString;
|
|
||||||
- newState.layoutManager = textLayoutManager_;
|
|
||||||
newState.mostRecentEventCount = getConcreteProps().mostRecentEventCount;
|
|
||||||
setStateData(std::move(newState));
|
|
||||||
}
|
|
||||||
+15
-17
@@ -11,13 +11,11 @@ import {
|
|||||||
import * as ScreenOrientation from 'expo-screen-orientation'
|
import * as ScreenOrientation from 'expo-screen-orientation'
|
||||||
import * as SplashScreen from 'expo-splash-screen'
|
import * as SplashScreen from 'expo-splash-screen'
|
||||||
import * as SystemUI from 'expo-system-ui'
|
import * as SystemUI from 'expo-system-ui'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {useLingui} from '@lingui/react/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
import * as Sentry from '@sentry/react-native'
|
import * as Sentry from '@sentry/react-native'
|
||||||
|
|
||||||
import {Provider as HideBottomBarBorderProvider} from '#/lib/hooks/useHideBottomBarBorder'
|
import {Provider as HideBottomBarBorderProvider} from '#/lib/hooks/useHideBottomBarBorder'
|
||||||
import {QueryProvider} from '#/lib/react-query'
|
import {QueryProvider} from '#/lib/react-query'
|
||||||
import {s} from '#/lib/styles'
|
|
||||||
import {ThemeProvider} from '#/lib/ThemeContext'
|
import {ThemeProvider} from '#/lib/ThemeContext'
|
||||||
import {Provider as TranslateOnDeviceProvider} from '#/lib/translation'
|
import {Provider as TranslateOnDeviceProvider} from '#/lib/translation'
|
||||||
import I18nProvider from '#/locale/i18nProvider'
|
import I18nProvider from '#/locale/i18nProvider'
|
||||||
@@ -59,7 +57,7 @@ import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
|
|||||||
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
|
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
|
||||||
import {TestCtrls} from '#/view/com/testing/TestCtrls'
|
import {TestCtrls} from '#/view/com/testing/TestCtrls'
|
||||||
import {Shell} from '#/view/shell'
|
import {Shell} from '#/view/shell'
|
||||||
import {ThemeProvider as Alf} from '#/alf'
|
import {atoms as a, ThemeProvider as Alf} from '#/alf'
|
||||||
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
|
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
|
||||||
import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
|
import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
|
||||||
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
|
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
|
||||||
@@ -89,9 +87,9 @@ import {Splash} from '#/Splash'
|
|||||||
import {BottomSheetProvider} from '../modules/bottom-sheet'
|
import {BottomSheetProvider} from '../modules/bottom-sheet'
|
||||||
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
|
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
|
||||||
|
|
||||||
SplashScreen.preventAutoHideAsync()
|
void SplashScreen.preventAutoHideAsync()
|
||||||
if (IS_IOS) {
|
if (IS_IOS) {
|
||||||
SystemUI.setBackgroundColorAsync('black')
|
void SystemUI.setBackgroundColorAsync('black')
|
||||||
}
|
}
|
||||||
if (IS_ANDROID) {
|
if (IS_ANDROID) {
|
||||||
// iOS is handled by the config plugin -sfn
|
// iOS is handled by the config plugin -sfn
|
||||||
@@ -105,17 +103,17 @@ if (IS_ANDROID) {
|
|||||||
/**
|
/**
|
||||||
* Begin geolocation ASAP
|
* Begin geolocation ASAP
|
||||||
*/
|
*/
|
||||||
Geo.resolve()
|
void Geo.resolve()
|
||||||
prefetchAgeAssuranceConfig()
|
void prefetchAgeAssuranceConfig()
|
||||||
prefetchLiveEvents()
|
void prefetchLiveEvents()
|
||||||
prefetchAppConfig()
|
void prefetchAppConfig()
|
||||||
|
|
||||||
function InnerApp() {
|
function InnerApp() {
|
||||||
const [isReady, setIsReady] = useState(false)
|
const [isReady, setIsReady] = useState(false)
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const {resumeSession} = useSessionApi()
|
const {resumeSession} = useSessionApi()
|
||||||
const theme = useColorModeTheme()
|
const theme = useColorModeTheme()
|
||||||
const {_} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const hasCheckedReferrer = useStarterPackEntry()
|
const hasCheckedReferrer = useStarterPackEntry()
|
||||||
|
|
||||||
// init
|
// init
|
||||||
@@ -134,16 +132,16 @@ function InnerApp() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const account = readLastActiveAccount()
|
const account = readLastActiveAccount()
|
||||||
onLaunch(account)
|
void onLaunch(account)
|
||||||
}, [resumeSession])
|
}, [resumeSession])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return listenSessionDropped(() => {
|
return listenSessionDropped(() => {
|
||||||
Toast.show(_(msg`Sorry! Your session expired. Please sign in again.`), {
|
Toast.show(l`Sorry! Your session expired. Please sign in again.`, {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}, [_])
|
}, [l])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Alf theme={theme}>
|
<Alf theme={theme}>
|
||||||
@@ -176,7 +174,7 @@ function InnerApp() {
|
|||||||
<EmailVerificationProvider>
|
<EmailVerificationProvider>
|
||||||
<HideBottomBarBorderProvider>
|
<HideBottomBarBorderProvider>
|
||||||
<GestureHandlerRootView
|
<GestureHandlerRootView
|
||||||
style={s.h100pct}>
|
style={a.h_full}>
|
||||||
<GlobalGestureEventsProvider>
|
<GlobalGestureEventsProvider>
|
||||||
<IntentDialogProvider>
|
<IntentDialogProvider>
|
||||||
<TranslateOnDeviceProvider>
|
<TranslateOnDeviceProvider>
|
||||||
@@ -220,8 +218,8 @@ function App() {
|
|||||||
const [isReady, setReady] = useState(false)
|
const [isReady, setReady] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Promise.all([initPersistedState(), Geo.resolve(), setupDeviceId]).then(() =>
|
void Promise.all([initPersistedState(), Geo.resolve(), setupDeviceId]).then(
|
||||||
setReady(true),
|
() => setReady(true),
|
||||||
)
|
)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|||||||
+15
-13
@@ -5,10 +5,10 @@ import './style.css'
|
|||||||
import {Fragment, useEffect, useState} from 'react'
|
import {Fragment, useEffect, useState} from 'react'
|
||||||
import {KeyboardProvider as KeyboardControllerProvider} from 'react-native-keyboard-controller'
|
import {KeyboardProvider as KeyboardControllerProvider} from 'react-native-keyboard-controller'
|
||||||
import {SafeAreaProvider} from 'react-native-safe-area-context'
|
import {SafeAreaProvider} from 'react-native-safe-area-context'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {useLingui} from '@lingui/react/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
import * as Sentry from '@sentry/react-native'
|
import * as Sentry from '@sentry/react-native'
|
||||||
|
|
||||||
|
import {Provider as HotkeysProvider} from '#/lib/hotkeys'
|
||||||
import {QueryProvider} from '#/lib/react-query'
|
import {QueryProvider} from '#/lib/react-query'
|
||||||
import {ThemeProvider} from '#/lib/ThemeContext'
|
import {ThemeProvider} from '#/lib/ThemeContext'
|
||||||
import {Provider as TranslateOnDeviceProvider} from '#/lib/translation'
|
import {Provider as TranslateOnDeviceProvider} from '#/lib/translation'
|
||||||
@@ -82,17 +82,17 @@ import {Provider as HideBottomBarBorderProvider} from './lib/hooks/useHideBottom
|
|||||||
/**
|
/**
|
||||||
* Begin geolocation ASAP
|
* Begin geolocation ASAP
|
||||||
*/
|
*/
|
||||||
Geo.resolve()
|
void Geo.resolve()
|
||||||
prefetchAgeAssuranceConfig()
|
void prefetchAgeAssuranceConfig()
|
||||||
prefetchLiveEvents()
|
void prefetchLiveEvents()
|
||||||
prefetchAppConfig()
|
void prefetchAppConfig()
|
||||||
|
|
||||||
function InnerApp() {
|
function InnerApp() {
|
||||||
const [isReady, setIsReady] = useState(false)
|
const [isReady, setIsReady] = useState(false)
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const {resumeSession} = useSessionApi()
|
const {resumeSession} = useSessionApi()
|
||||||
const theme = useColorModeTheme()
|
const theme = useColorModeTheme()
|
||||||
const {_} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const hasCheckedReferrer = useStarterPackEntry()
|
const hasCheckedReferrer = useStarterPackEntry()
|
||||||
|
|
||||||
// init
|
// init
|
||||||
@@ -105,22 +105,22 @@ function InnerApp() {
|
|||||||
await features.init
|
await features.init
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`session: resumeSession failed`, {message: e})
|
logger.error('session: resumeSession failed', {message: e})
|
||||||
} finally {
|
} finally {
|
||||||
setIsReady(true)
|
setIsReady(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const account = readLastActiveAccount()
|
const account = readLastActiveAccount()
|
||||||
onLaunch(account)
|
void onLaunch(account)
|
||||||
}, [resumeSession])
|
}, [resumeSession])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return listenSessionDropped(() => {
|
return listenSessionDropped(() => {
|
||||||
Toast.show(_(msg`Sorry! Your session expired. Please sign in again.`), {
|
Toast.show(l`Sorry! Your session expired. Please sign in again.`, {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}, [_])
|
}, [l])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Alf theme={theme}>
|
<Alf theme={theme}>
|
||||||
@@ -156,8 +156,10 @@ function InnerApp() {
|
|||||||
<HideBottomBarBorderProvider>
|
<HideBottomBarBorderProvider>
|
||||||
<IntentDialogProvider>
|
<IntentDialogProvider>
|
||||||
<TranslateOnDeviceProvider>
|
<TranslateOnDeviceProvider>
|
||||||
|
<HotkeysProvider>
|
||||||
<Shell />
|
<Shell />
|
||||||
<ToastOutlet />
|
<ToastOutlet />
|
||||||
|
</HotkeysProvider>
|
||||||
</TranslateOnDeviceProvider>
|
</TranslateOnDeviceProvider>
|
||||||
</IntentDialogProvider>
|
</IntentDialogProvider>
|
||||||
</HideBottomBarBorderProvider>
|
</HideBottomBarBorderProvider>
|
||||||
@@ -195,8 +197,8 @@ function App() {
|
|||||||
const [isReady, setReady] = useState(false)
|
const [isReady, setReady] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Promise.all([initPersistedState(), Geo.resolve(), setupDeviceId]).then(() =>
|
void Promise.all([initPersistedState(), Geo.resolve(), setupDeviceId]).then(
|
||||||
setReady(true),
|
() => setReady(true),
|
||||||
)
|
)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import {Children} from 'react'
|
import {Children} from 'react'
|
||||||
import {type TextProps as RNTextProps} from 'react-native'
|
import {
|
||||||
import {type StyleProp, type TextStyle} from 'react-native'
|
type StyleProp,
|
||||||
|
type TextProps as RNTextProps,
|
||||||
|
type TextStyle,
|
||||||
|
} from 'react-native'
|
||||||
import {UITextView} from 'react-native-uitextview'
|
import {UITextView} from 'react-native-uitextview'
|
||||||
import createEmojiRegex from 'emoji-regex'
|
import createEmojiRegex from 'emoji-regex'
|
||||||
|
|
||||||
import {type Alf, applyFonts, atoms, flatten} from '#/alf'
|
import {type Alf, applyFonts, atoms, flatten} from '#/alf'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_IOS, IS_NATIVE} from '#/env'
|
||||||
import {IS_IOS} from '#/env'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that `lineHeight` defaults to a relative value of `1`, or applies
|
* Ensures that `lineHeight` defaults to a relative value of `1`, or applies
|
||||||
@@ -107,7 +109,8 @@ export function renderChildrenWithEmoji(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const SINGLE_EMOJI_RE = /^[\p{Emoji_Presentation}\p{Extended_Pictographic}]+$/u
|
const SINGLE_EMOJI_RE =
|
||||||
|
/^[\p{Emoji_Presentation}\p{Extended_Pictographic}\uFE0F\u200D]+$/u
|
||||||
export function isOnlyEmoji(text: string) {
|
export function isOnlyEmoji(text: string) {
|
||||||
return text.length <= 15 && SINGLE_EMOJI_RE.test(text)
|
return text.length <= 15 && SINGLE_EMOJI_RE.test(text)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ const Context = createContext<AnalyticsBaseContextType>({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
Context.displayName = 'AnalyticsContext'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that deviceId is set and migrated from legacy storage. Handled on
|
* Ensures that deviceId is set and migrated from legacy storage. Handled on
|
||||||
|
|||||||
@@ -560,7 +560,6 @@ export function ProfileGrid({
|
|||||||
<Text style={[a.text_sm, a.font_semi_bold, t.atoms.text]}>
|
<Text style={[a.text_sm, a.font_semi_bold, t.atoms.text]}>
|
||||||
<Trans>Suggested for you</Trans>
|
<Trans>Suggested for you</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
{!isProfileHeaderContext && (
|
|
||||||
<Button
|
<Button
|
||||||
label={l`See more suggested profiles`}
|
label={l`See more suggested profiles`}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
@@ -585,7 +584,6 @@ export function ProfileGrid({
|
|||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
<FollowDialogWithoutGuide control={followDialogControl} />
|
<FollowDialogWithoutGuide control={followDialogControl} />
|
||||||
<LayoutAnimationConfig skipExiting skipEntering>
|
<LayoutAnimationConfig skipExiting skipEntering>
|
||||||
@@ -605,7 +603,6 @@ export function ProfileGrid({
|
|||||||
decelerationRate="fast">
|
decelerationRate="fast">
|
||||||
{content}
|
{content}
|
||||||
|
|
||||||
{!isProfileHeaderContext && (
|
|
||||||
<SeeMoreSuggestedProfilesCard
|
<SeeMoreSuggestedProfilesCard
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
followDialogControl.open()
|
followDialogControl.open()
|
||||||
@@ -614,7 +611,6 @@ export function ProfileGrid({
|
|||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</BlockDrawerGesture>
|
</BlockDrawerGesture>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
|
|||||||
import {Pause_Filled_Corner0_Rounded as PauseIcon} from '#/components/icons/Pause'
|
import {Pause_Filled_Corner0_Rounded as PauseIcon} from '#/components/icons/Pause'
|
||||||
import {Play_Filled_Corner0_Rounded as PlayIcon} from '#/components/icons/Play'
|
import {Play_Filled_Corner0_Rounded as PlayIcon} from '#/components/icons/Play'
|
||||||
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
|
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
|
||||||
|
import {KeepAwake} from '#/components/KeepAwake'
|
||||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||||
import {useVideoMuteState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
|
import {useVideoMuteState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
|
||||||
import {GifPresentationControls} from '../GifPresentationControls'
|
import {GifPresentationControls} from '../GifPresentationControls'
|
||||||
@@ -112,6 +113,7 @@ export function VideoEmbedInnerNative({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<MediaInsetBorder />
|
<MediaInsetBorder />
|
||||||
|
<KeepAwake enabled={isPlaying} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,6 +136,8 @@ export const BookmarkButton = memo(function BookmarkButton({
|
|||||||
<PostControlButton
|
<PostControlButton
|
||||||
testID="postBookmarkBtn"
|
testID="postBookmarkBtn"
|
||||||
big={big}
|
big={big}
|
||||||
|
active={isBookmarked}
|
||||||
|
activeColor={t.palette.primary_500}
|
||||||
label={
|
label={
|
||||||
isBookmarked
|
isBookmarked
|
||||||
? _(msg`Remove from saved posts`)
|
? _(msg`Remove from saved posts`)
|
||||||
@@ -143,10 +145,7 @@ export const BookmarkButton = memo(function BookmarkButton({
|
|||||||
}
|
}
|
||||||
onPress={onHandlePress}
|
onPress={onHandlePress}
|
||||||
hitSlop={hitSlop}>
|
hitSlop={hitSlop}>
|
||||||
<PostControlButtonIcon
|
<PostControlButtonIcon icon={isBookmarked ? BookmarkFilled : Bookmark} />
|
||||||
fill={isBookmarked ? t.palette.primary_500 : undefined}
|
|
||||||
icon={isBookmarked ? BookmarkFilled : Bookmark}
|
|
||||||
/>
|
|
||||||
</PostControlButton>
|
</PostControlButton>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -130,8 +130,11 @@ export function PostControlButtonText({style, ...props}: TextProps) {
|
|||||||
<Text
|
<Text
|
||||||
style={[
|
style={[
|
||||||
color,
|
color,
|
||||||
|
a.user_select_none,
|
||||||
big ? a.text_md : a.text_sm,
|
big ? a.text_md : a.text_sm,
|
||||||
active && a.font_semi_bold,
|
active && a.font_semi_bold,
|
||||||
|
// prevent layout shift on android
|
||||||
|
{includeFontPadding: false, textAlignVertical: 'center'},
|
||||||
style,
|
style,
|
||||||
]}
|
]}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
ProgressGuideAction,
|
ProgressGuideAction,
|
||||||
useProgressGuideControls,
|
useProgressGuideControls,
|
||||||
} from '#/state/shell/progress-guide'
|
} from '#/state/shell/progress-guide'
|
||||||
import {atoms as a, useBreakpoints} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {Reply as Bubble} from '#/components/icons/Reply'
|
import {Reply as Bubble} from '#/components/icons/Reply'
|
||||||
import {useFormatPostStatCount} from '#/components/PostControls/util'
|
import {useFormatPostStatCount} from '#/components/PostControls/util'
|
||||||
import * as Skele from '#/components/Skeleton'
|
import * as Skele from '#/components/Skeleton'
|
||||||
@@ -74,6 +74,7 @@ let PostControls = ({
|
|||||||
forceGoogleTranslate?: boolean
|
forceGoogleTranslate?: boolean
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
|
const t = useTheme()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const {openComposer} = useOpenComposer()
|
const {openComposer} = useOpenComposer()
|
||||||
const {feedDescriptor} = useFeedFeedbackContext()
|
const {feedDescriptor} = useFeedFeedbackContext()
|
||||||
@@ -270,6 +271,8 @@ let PostControls = ({
|
|||||||
<PostControlButton
|
<PostControlButton
|
||||||
testID="likeBtn"
|
testID="likeBtn"
|
||||||
big={big}
|
big={big}
|
||||||
|
active={Boolean(post.viewer?.like)}
|
||||||
|
activeColor={t.palette.pink}
|
||||||
onPress={() => requireAuth(() => onPressToggleLike())}
|
onPress={() => requireAuth(() => onPressToggleLike())}
|
||||||
label={
|
label={
|
||||||
post.viewer?.like
|
post.viewer?.like
|
||||||
@@ -296,10 +299,14 @@ let PostControls = ({
|
|||||||
hasBeenToggled={hasLikeIconBeenToggled}
|
hasBeenToggled={hasLikeIconBeenToggled}
|
||||||
/>
|
/>
|
||||||
<CountWheel
|
<CountWheel
|
||||||
likeCount={post.likeCount ?? 0}
|
count={post.likeCount ?? 0}
|
||||||
big={big}
|
isToggled={Boolean(post.viewer?.like)}
|
||||||
isLiked={Boolean(post.viewer?.like)}
|
|
||||||
hasBeenToggled={hasLikeIconBeenToggled}
|
hasBeenToggled={hasLikeIconBeenToggled}
|
||||||
|
renderCount={({count}) => (
|
||||||
|
<PostControlButtonText>
|
||||||
|
{formatPostStatCount(count)}
|
||||||
|
</PostControlButtonText>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</PostControlButton>
|
</PostControlButton>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {View} from 'react-native'
|
import {useWindowDimensions, View} from 'react-native'
|
||||||
|
|
||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {atoms as a, type ViewStyleProp} from '#/alf'
|
import {atoms as a, useAlf, type ViewStyleProp} from '#/alf'
|
||||||
import {BotBadge, BotBadgeButton, isBotAccount} from '#/components/BotBadge'
|
import {BotBadge, BotBadgeButton, isBotAccount} from '#/components/BotBadge'
|
||||||
import {useSimpleVerificationState} from '#/components/verification'
|
import {useSimpleVerificationState} from '#/components/verification'
|
||||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||||
@@ -38,12 +38,21 @@ export function ProfileBadges({
|
|||||||
}) {
|
}) {
|
||||||
const shadowed = useProfileShadow(profile)
|
const shadowed = useProfileShadow(profile)
|
||||||
const verification = useSimpleVerificationState({profile})
|
const verification = useSimpleVerificationState({profile})
|
||||||
|
const {fontScale: nativeScaleMultiplier} = useWindowDimensions()
|
||||||
|
const {
|
||||||
|
fonts: {scaleMultiplier: alfScaleMultiplier},
|
||||||
|
} = useAlf()
|
||||||
|
|
||||||
// if nothing to show, don't render the container at all
|
// if nothing to show, don't render the container at all
|
||||||
if (!verification.showBadge && !isBotAccount(shadowed)) return null
|
if (!verification.showBadge && !isBotAccount(shadowed)) return null
|
||||||
|
|
||||||
const isOnTheSmallSide = size === 'xs' || size === 'sm'
|
const isOnTheSmallSide = size === 'xs' || size === 'sm'
|
||||||
|
|
||||||
|
const verificationIconWidth =
|
||||||
|
verificationIconSizes[size] * nativeScaleMultiplier * alfScaleMultiplier
|
||||||
|
const botIconWidth =
|
||||||
|
botIconSizes[size] * nativeScaleMultiplier * alfScaleMultiplier
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
@@ -56,19 +65,19 @@ export function ProfileBadges({
|
|||||||
<>
|
<>
|
||||||
<VerificationCheckButton
|
<VerificationCheckButton
|
||||||
profile={shadowed}
|
profile={shadowed}
|
||||||
width={verificationIconSizes[size]}
|
width={verificationIconWidth}
|
||||||
/>
|
/>
|
||||||
<BotBadgeButton profile={shadowed} width={botIconSizes[size]} />
|
<BotBadgeButton profile={shadowed} width={botIconWidth} />
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{verification.showBadge && (
|
{verification.showBadge && (
|
||||||
<VerificationCheck
|
<VerificationCheck
|
||||||
verifier={verification.role === 'verifier'}
|
verifier={verification.role === 'verifier'}
|
||||||
width={verificationIconSizes[size]}
|
width={verificationIconWidth}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<BotBadge profile={shadowed} width={botIconSizes[size]} />
|
<BotBadge profile={shadowed} width={botIconWidth} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import {View} from 'react-native'
|
|||||||
import {Select as RadixSelect} from 'radix-ui'
|
import {Select as RadixSelect} from 'radix-ui'
|
||||||
|
|
||||||
import {useA11y} from '#/state/a11y'
|
import {useA11y} from '#/state/a11y'
|
||||||
import {flatten, useTheme, web} from '#/alf'
|
import {atoms as a, flatten, useTheme, web} from '#/alf'
|
||||||
import {atoms as a} from '#/alf'
|
|
||||||
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
import {useInteractionState} from '#/components/hooks/useInteractionState'
|
||||||
import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check'
|
import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check'
|
||||||
import {
|
import {
|
||||||
@@ -109,7 +108,7 @@ export function Trigger({children, label}: TriggerProps) {
|
|||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
maxWidth: 400,
|
maxWidth: 400,
|
||||||
outline: 0,
|
outline: 0,
|
||||||
borderWidth: 2,
|
borderWidth: 1,
|
||||||
borderStyle: 'solid',
|
borderStyle: 'solid',
|
||||||
borderColor: focused
|
borderColor: focused
|
||||||
? t.palette.primary_500
|
? t.palette.primary_500
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export const PostsList = forwardRef<SectionRef, ProfilesListProps>(
|
|||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<PostFeed
|
<PostFeed
|
||||||
|
enabled
|
||||||
feed={feed}
|
feed={feed}
|
||||||
pollInterval={60e3}
|
pollInterval={60e3}
|
||||||
scrollElRef={scrollElRef}
|
scrollElRef={scrollElRef}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
|
|
||||||
import {atoms as a, useTheme, type ViewStyleProp} from '#/alf'
|
import {atoms as a, useTheme, type ViewStyleProp, web as webOnly} from '#/alf'
|
||||||
import {IS_NATIVE, IS_WEB, IS_WEB_TOUCH_DEVICE} from '#/env'
|
import {IS_NATIVE, IS_WEB, IS_WEB_TOUCH_DEVICE} from '#/env'
|
||||||
|
|
||||||
export function SubtleHover({
|
export function SubtleHover({
|
||||||
@@ -33,6 +33,10 @@ export function SubtleHover({
|
|||||||
a.transition_opacity,
|
a.transition_opacity,
|
||||||
t.atoms.bg_contrast_50,
|
t.atoms.bg_contrast_50,
|
||||||
style,
|
style,
|
||||||
|
// Force Safari to composite the overlay on its own GPU layer.
|
||||||
|
// This fixes a layout shift that happens due to different subpixel
|
||||||
|
// rounding when the overlay is composited on hover.
|
||||||
|
webOnly({willChange: 'opacity'}),
|
||||||
{opacity: hover ? opacity : 0},
|
{opacity: hover ? opacity : 0},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {useState} from 'react'
|
import {useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {XRPCError} from '@atproto/xrpc'
|
import {XRPCError} from '@atproto/api'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {msg} from '@lingui/core/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {Trans} from '@lingui/react/macro'
|
import {Trans} from '@lingui/react/macro'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {useEffect} from 'react'
|
import {useEffect} from 'react'
|
||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
const events = new EventEmitter<{
|
const events = new EventEmitter<{
|
||||||
emailVerified: void
|
emailVerified: void
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export function DateFieldButton({
|
|||||||
paddingLeft: 14,
|
paddingLeft: 14,
|
||||||
paddingRight: 14,
|
paddingRight: 14,
|
||||||
borderColor: 'transparent',
|
borderColor: 'transparent',
|
||||||
borderWidth: 2,
|
borderWidth: 1,
|
||||||
},
|
},
|
||||||
native({
|
native({
|
||||||
paddingTop: 10,
|
paddingTop: 10,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import {forwardRef} from 'react'
|
import {useEffect, useRef} from 'react'
|
||||||
import {type TextInput, View} from 'react-native'
|
import {type TextInput, View} from 'react-native'
|
||||||
import {useLingui} from '@lingui/react/macro'
|
import {useLingui} from '@lingui/react/macro'
|
||||||
|
|
||||||
import {HITSLOP_10} from '#/lib/constants'
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
|
import {listenFocusSearch} from '#/state/events'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Button, ButtonIcon} from '#/components/Button'
|
import {Button, ButtonIcon} from '#/components/Button'
|
||||||
import * as TextField from '#/components/forms/TextField'
|
import * as TextField from '#/components/forms/TextField'
|
||||||
@@ -10,26 +11,43 @@ import {MagnifyingGlass_Stroke2_Corner0_Rounded as MagnifyingGlassIcon} from '#/
|
|||||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||||
import {IS_NATIVE} from '#/env'
|
import {IS_NATIVE} from '#/env'
|
||||||
|
|
||||||
type SearchInputProps = Omit<TextField.InputProps, 'label'> & {
|
type Props = Omit<TextField.InputProps, 'label'> & {
|
||||||
label?: TextField.InputProps['label']
|
label?: TextField.InputProps['label']
|
||||||
/**
|
/**
|
||||||
* Called when the user presses the (X) button
|
* Called when the user presses the (X) button
|
||||||
*/
|
*/
|
||||||
onClearText?: () => void
|
onClearText?: () => void
|
||||||
|
hotkey?: boolean
|
||||||
|
ref?: React.RefObject<TextInput | null>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SearchInput = forwardRef<TextInput, SearchInputProps>(
|
export function SearchInput({
|
||||||
function SearchInput({value, label, onClearText, ...rest}, ref) {
|
value,
|
||||||
|
label,
|
||||||
|
onClearText,
|
||||||
|
hotkey,
|
||||||
|
ref,
|
||||||
|
...rest
|
||||||
|
}: Props) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const showClear = value && value.length > 0
|
const showClear = value && value.length > 0
|
||||||
|
const internalRef = useRef<TextInput>(null)
|
||||||
|
const inputRef = ref ?? internalRef
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hotkey) return
|
||||||
|
return listenFocusSearch(() => {
|
||||||
|
inputRef.current?.focus()
|
||||||
|
})
|
||||||
|
}, [hotkey, inputRef])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.w_full, a.relative]}>
|
<View style={[a.w_full, a.relative]}>
|
||||||
<TextField.Root>
|
<TextField.Root>
|
||||||
<TextField.Icon icon={MagnifyingGlassIcon} />
|
<TextField.Icon icon={MagnifyingGlassIcon} />
|
||||||
<TextField.Input
|
<TextField.Input
|
||||||
inputRef={ref}
|
inputRef={inputRef}
|
||||||
label={label || l`Search`}
|
label={label || l`Search`}
|
||||||
value={value}
|
value={value}
|
||||||
placeholder={l`Search`}
|
placeholder={l`Search`}
|
||||||
@@ -78,5 +96,4 @@ export const SearchInput = forwardRef<TextInput, SearchInputProps>(
|
|||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {useCallback, useMemo, useState} from 'react'
|
import {useCallback, useMemo, useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {type ComAtprotoLabelDefs, ToolsOzoneReportDefs} from '@atproto/api'
|
import {type ComAtprotoLabelDefs, ToolsOzoneReportDefs} from '@atproto/api'
|
||||||
import {XRPCError} from '@atproto/xrpc'
|
import {XRPCError} from '@atproto/api'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {msg} from '@lingui/core/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {Trans} from '@lingui/react/macro'
|
import {Trans} from '@lingui/react/macro'
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ function Inner(props: ReportDialogProps) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}, [
|
}, [
|
||||||
props,
|
props.subject,
|
||||||
allLabelers,
|
allLabelers,
|
||||||
state.selectedOption,
|
state.selectedOption,
|
||||||
isBskyOnlyReason,
|
isBskyOnlyReason,
|
||||||
@@ -241,7 +241,17 @@ function Inner(props: ReportDialogProps) {
|
|||||||
} finally {
|
} finally {
|
||||||
setPending(false)
|
setPending(false)
|
||||||
}
|
}
|
||||||
}, [_, submitReport, state, dispatch, props, setPending, setSuccess])
|
}, [
|
||||||
|
_,
|
||||||
|
submitReport,
|
||||||
|
state,
|
||||||
|
dispatch,
|
||||||
|
props.subject,
|
||||||
|
props.control,
|
||||||
|
props.onAfterSubmit,
|
||||||
|
setPending,
|
||||||
|
setSuccess,
|
||||||
|
])
|
||||||
|
|
||||||
useCallOnce(() => {
|
useCallOnce(() => {
|
||||||
ax.metric('reportDialog:open', {
|
ax.metric('reportDialog:open', {
|
||||||
|
|||||||
Vendored
+8
@@ -10,6 +10,10 @@ const iOSMajorVersion =
|
|||||||
Platform.OS === 'ios' && typeof Platform.Version === 'string'
|
Platform.OS === 'ios' && typeof Platform.Version === 'string'
|
||||||
? parseInt(Platform.Version.split('.')[0], 10)
|
? parseInt(Platform.Version.split('.')[0], 10)
|
||||||
: 0
|
: 0
|
||||||
|
const androidPlatformVersion =
|
||||||
|
Platform.OS === 'android' && typeof Platform.Version === 'number'
|
||||||
|
? Platform.Version
|
||||||
|
: 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The semver version of the app, specified in our `package.json`.file. On
|
* The semver version of the app, specified in our `package.json`.file. On
|
||||||
@@ -49,3 +53,7 @@ export const IS_WEB_FIREFOX: boolean = false
|
|||||||
export const IS_HIGH_DPI: boolean = true
|
export const IS_HIGH_DPI: boolean = true
|
||||||
// ideally we'd use isLiquidGlassAvailable() from expo-glass-effect but checking iOS version is good enough for now
|
// ideally we'd use isLiquidGlassAvailable() from expo-glass-effect but checking iOS version is good enough for now
|
||||||
export const IS_LIQUID_GLASS: boolean = iOSMajorVersion >= 26
|
export const IS_LIQUID_GLASS: boolean = iOSMajorVersion >= 26
|
||||||
|
// So we can avoid attempting on-device translation when we know it's unsupported.
|
||||||
|
export const IS_TRANSLATION_SUPPORTED: boolean =
|
||||||
|
(IS_IOS && iOSMajorVersion >= 18) ||
|
||||||
|
(IS_ANDROID && androidPlatformVersion > 22)
|
||||||
|
|||||||
Vendored
+1
@@ -48,3 +48,4 @@ export const IS_HIGH_DPI: boolean = window.matchMedia(
|
|||||||
'(min-resolution: 2dppx)',
|
'(min-resolution: 2dppx)',
|
||||||
).matches
|
).matches
|
||||||
export const IS_LIQUID_GLASS: boolean = false
|
export const IS_LIQUID_GLASS: boolean = false
|
||||||
|
export const IS_TRANSLATION_SUPPORTED: boolean = false
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {useEffect, useState} from 'react'
|
import {useEffect, useState} from 'react'
|
||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
import {networkRetry} from '#/lib/async/retry'
|
import {networkRetry} from '#/lib/async/retry'
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ import Animated, {
|
|||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
|
|
||||||
import {decideShouldRoll} from '#/lib/custom-animations/util'
|
import {decideShouldRoll} from '#/lib/custom-animations/util'
|
||||||
import {s} from '#/lib/styles'
|
import {atoms as a} from '#/alf'
|
||||||
import {Text} from '#/view/com/util/text/Text'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
|
||||||
import {useFormatPostStatCount} from '#/components/PostControls/util'
|
|
||||||
|
|
||||||
const animationConfig = {
|
const animationConfig = {
|
||||||
duration: 400,
|
duration: 400,
|
||||||
@@ -87,89 +84,66 @@ function ExitingDown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function CountWheel({
|
export function CountWheel({
|
||||||
likeCount,
|
count,
|
||||||
big,
|
isToggled,
|
||||||
isLiked,
|
|
||||||
hasBeenToggled,
|
hasBeenToggled,
|
||||||
|
renderCount,
|
||||||
}: {
|
}: {
|
||||||
likeCount: number
|
count: number
|
||||||
big?: boolean
|
isToggled: boolean
|
||||||
isLiked: boolean
|
|
||||||
hasBeenToggled: boolean
|
hasBeenToggled: boolean
|
||||||
|
renderCount: (props: {count: number}) => React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
|
||||||
const shouldAnimate = !useReducedMotion() && hasBeenToggled
|
const shouldAnimate = !useReducedMotion() && hasBeenToggled
|
||||||
const shouldRoll = decideShouldRoll(isLiked, likeCount)
|
const shouldRoll = decideShouldRoll(isToggled, count)
|
||||||
|
|
||||||
// Incrementing the key will cause the `Animated.View` to re-render, with the newly selected entering/exiting
|
// Incrementing the key will cause the `Animated.View` to re-render, with the newly selected entering/exiting
|
||||||
// animation
|
// animation
|
||||||
// The initial entering/exiting animations will get skipped, since these will happen on screen mounts and would
|
// The initial entering/exiting animations will get skipped, since these will happen on screen mounts and would
|
||||||
// be unnecessary
|
// be unnecessary
|
||||||
const [key, setKey] = useState(0)
|
const [key, setKey] = useState(0)
|
||||||
const [prevCount, setPrevCount] = useState(likeCount)
|
const [prevCount, setPrevCount] = useState(count)
|
||||||
const prevIsLiked = useRef(isLiked)
|
const prevIsToggled = useRef(isToggled)
|
||||||
const formatPostStatCount = useFormatPostStatCount()
|
|
||||||
const formattedCount = formatPostStatCount(likeCount)
|
|
||||||
const formattedPrevCount = formatPostStatCount(prevCount)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isLiked === prevIsLiked.current) {
|
if (isToggled === prevIsToggled.current) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const newPrevCount = isLiked ? likeCount - 1 : likeCount + 1
|
const newPrevCount = isToggled ? count - 1 : count + 1
|
||||||
setKey(prev => prev + 1)
|
setKey(prev => prev + 1)
|
||||||
setPrevCount(newPrevCount)
|
setPrevCount(newPrevCount)
|
||||||
prevIsLiked.current = isLiked
|
prevIsToggled.current = isToggled
|
||||||
}, [isLiked, likeCount])
|
}, [isToggled, count])
|
||||||
|
|
||||||
const enteringAnimation =
|
const enteringAnimation =
|
||||||
shouldAnimate && shouldRoll
|
shouldAnimate && shouldRoll
|
||||||
? isLiked
|
? isToggled
|
||||||
? EnteringUp
|
? EnteringUp
|
||||||
: EnteringDown
|
: EnteringDown
|
||||||
: undefined
|
: undefined
|
||||||
const exitingAnimation =
|
const exitingAnimation =
|
||||||
shouldAnimate && shouldRoll
|
shouldAnimate && shouldRoll
|
||||||
? isLiked
|
? isToggled
|
||||||
? ExitingUp
|
? ExitingUp
|
||||||
: ExitingDown
|
: ExitingDown
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutAnimationConfig skipEntering skipExiting>
|
<LayoutAnimationConfig skipEntering skipExiting>
|
||||||
{likeCount > 0 ? (
|
{count > 0 ? (
|
||||||
<View style={[a.justify_center]}>
|
<View style={[a.justify_center]}>
|
||||||
<Animated.View entering={enteringAnimation} key={key}>
|
<Animated.View entering={enteringAnimation} key={key}>
|
||||||
<Text
|
{renderCount({count})}
|
||||||
testID="likeCount"
|
|
||||||
style={[
|
|
||||||
big ? a.text_md : a.text_sm,
|
|
||||||
a.user_select_none,
|
|
||||||
isLiked
|
|
||||||
? [a.font_semi_bold, s.likeColor]
|
|
||||||
: {color: t.palette.contrast_500},
|
|
||||||
]}>
|
|
||||||
{formattedCount}
|
|
||||||
</Text>
|
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
{shouldAnimate && (likeCount > 1 || !isLiked) ? (
|
{shouldAnimate && (count > 1 || !isToggled) ? (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
entering={exitingAnimation}
|
entering={exitingAnimation}
|
||||||
// Add 2 to the key so there are never duplicates
|
// Add 2 to the key so there are never duplicates
|
||||||
key={key + 2}
|
key={key + 2}
|
||||||
style={[a.absolute, {width: 50, opacity: 0}]}
|
style={[a.absolute, {width: 50, opacity: 0}]}
|
||||||
aria-disabled={true}>
|
aria-disabled={true}>
|
||||||
<Text
|
{renderCount({count: prevCount})}
|
||||||
style={[
|
|
||||||
big ? a.text_md : a.text_sm,
|
|
||||||
a.user_select_none,
|
|
||||||
isLiked
|
|
||||||
? [a.font_semi_bold, s.likeColor]
|
|
||||||
: {color: t.palette.contrast_500},
|
|
||||||
]}>
|
|
||||||
{formattedPrevCount}
|
|
||||||
</Text>
|
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
) : null}
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -3,10 +3,6 @@ import {View} from 'react-native'
|
|||||||
import {useReducedMotion} from 'react-native-reanimated'
|
import {useReducedMotion} from 'react-native-reanimated'
|
||||||
|
|
||||||
import {decideShouldRoll} from '#/lib/custom-animations/util'
|
import {decideShouldRoll} from '#/lib/custom-animations/util'
|
||||||
import {s} from '#/lib/styles'
|
|
||||||
import {Text} from '#/view/com/util/text/Text'
|
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
|
||||||
import {useFormatPostStatCount} from '#/components/PostControls/util'
|
|
||||||
|
|
||||||
const animationConfig = {
|
const animationConfig = {
|
||||||
duration: 400,
|
duration: 400,
|
||||||
@@ -35,50 +31,46 @@ const exitingDownKeyframe = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export function CountWheel({
|
export function CountWheel({
|
||||||
likeCount,
|
count,
|
||||||
big,
|
isToggled,
|
||||||
isLiked,
|
|
||||||
hasBeenToggled,
|
hasBeenToggled,
|
||||||
|
renderCount,
|
||||||
}: {
|
}: {
|
||||||
likeCount: number
|
count: number
|
||||||
big?: boolean
|
isToggled: boolean
|
||||||
isLiked: boolean
|
|
||||||
hasBeenToggled: boolean
|
hasBeenToggled: boolean
|
||||||
|
renderCount: (props: {count: number}) => React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
|
||||||
const shouldAnimate = !useReducedMotion() && hasBeenToggled
|
const shouldAnimate = !useReducedMotion() && hasBeenToggled
|
||||||
const shouldRoll = decideShouldRoll(isLiked, likeCount)
|
const shouldRoll = decideShouldRoll(isToggled, count)
|
||||||
|
|
||||||
const countView = useRef<HTMLDivElement>(null)
|
const countView = useRef<HTMLDivElement>(null)
|
||||||
const prevCountView = useRef<HTMLDivElement>(null)
|
const prevCountView = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
const [prevCount, setPrevCount] = useState(likeCount)
|
const [prevCount, setPrevCount] = useState(count)
|
||||||
const prevIsLiked = useRef(isLiked)
|
const prevIsToggled = useRef(isToggled)
|
||||||
const formatPostStatCount = useFormatPostStatCount()
|
|
||||||
const formattedCount = formatPostStatCount(likeCount)
|
|
||||||
const formattedPrevCount = formatPostStatCount(prevCount)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isLiked === prevIsLiked.current) {
|
if (isToggled === prevIsToggled.current) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const newPrevCount = isLiked ? likeCount - 1 : likeCount + 1
|
const newPrevCount = isToggled ? count - 1 : count + 1
|
||||||
if (shouldAnimate && shouldRoll) {
|
if (shouldAnimate && shouldRoll) {
|
||||||
countView.current?.animate?.(
|
countView.current?.animate?.(
|
||||||
isLiked ? enteringUpKeyframe : enteringDownKeyframe,
|
isToggled ? enteringUpKeyframe : enteringDownKeyframe,
|
||||||
animationConfig,
|
animationConfig,
|
||||||
)
|
)
|
||||||
prevCountView.current?.animate?.(
|
prevCountView.current?.animate?.(
|
||||||
isLiked ? exitingUpKeyframe : exitingDownKeyframe,
|
isToggled ? exitingUpKeyframe : exitingDownKeyframe,
|
||||||
animationConfig,
|
animationConfig,
|
||||||
)
|
)
|
||||||
setPrevCount(newPrevCount)
|
setPrevCount(newPrevCount)
|
||||||
}
|
}
|
||||||
prevIsLiked.current = isLiked
|
prevIsToggled.current = isToggled
|
||||||
}, [isLiked, likeCount, shouldAnimate, shouldRoll])
|
}, [isToggled, count, shouldAnimate, shouldRoll])
|
||||||
|
|
||||||
if (likeCount < 1) {
|
if (count < 1) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,34 +79,15 @@ export function CountWheel({
|
|||||||
<View
|
<View
|
||||||
// @ts-expect-error is div
|
// @ts-expect-error is div
|
||||||
ref={countView}>
|
ref={countView}>
|
||||||
<Text
|
{renderCount({count})}
|
||||||
testID="likeCount"
|
|
||||||
style={[
|
|
||||||
big ? a.text_md : a.text_sm,
|
|
||||||
a.user_select_none,
|
|
||||||
isLiked
|
|
||||||
? [a.font_semi_bold, s.likeColor]
|
|
||||||
: {color: t.palette.contrast_500},
|
|
||||||
]}>
|
|
||||||
{formattedCount}
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
{shouldAnimate && (likeCount > 1 || !isLiked) ? (
|
{shouldAnimate && (count > 1 || !isToggled) ? (
|
||||||
<View
|
<View
|
||||||
style={{position: 'absolute', opacity: 0}}
|
style={{position: 'absolute', opacity: 0}}
|
||||||
aria-disabled={true}
|
aria-disabled={true}
|
||||||
// @ts-expect-error is div
|
// @ts-expect-error is div
|
||||||
ref={prevCountView}>
|
ref={prevCountView}>
|
||||||
<Text
|
{renderCount({count: prevCount})}
|
||||||
style={[
|
|
||||||
big ? a.text_md : a.text_sm,
|
|
||||||
a.user_select_none,
|
|
||||||
isLiked
|
|
||||||
? [a.font_semi_bold, s.likeColor]
|
|
||||||
: {color: t.palette.contrast_500},
|
|
||||||
]}>
|
|
||||||
{formattedPrevCount}
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import Animated, {
|
|||||||
useReducedMotion,
|
useReducedMotion,
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
|
|
||||||
import {s} from '#/lib/styles'
|
|
||||||
import {useTheme} from '#/alf'
|
import {useTheme} from '#/alf'
|
||||||
import {
|
import {
|
||||||
Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled,
|
Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled,
|
||||||
@@ -86,7 +85,7 @@ export function AnimatedLikeIcon({
|
|||||||
{isLiked ? (
|
{isLiked ? (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
entering={shouldAnimate ? keyframe.duration(300) : undefined}>
|
entering={shouldAnimate ? keyframe.duration(300) : undefined}>
|
||||||
<HeartIconFilled style={s.likeColor} width={size} />
|
<HeartIconFilled style={{color: t.palette.pink}} width={size} />
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
) : (
|
) : (
|
||||||
<HeartIconOutline
|
<HeartIconOutline
|
||||||
@@ -100,7 +99,7 @@ export function AnimatedLikeIcon({
|
|||||||
entering={circle1Keyframe.duration(300)}
|
entering={circle1Keyframe.duration(300)}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
backgroundColor: s.likeColor.color,
|
backgroundColor: t.palette.pink,
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
width: size,
|
width: size,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {useEffect, useRef} from 'react'
|
|||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {useReducedMotion} from 'react-native-reanimated'
|
import {useReducedMotion} from 'react-native-reanimated'
|
||||||
|
|
||||||
import {s} from '#/lib/styles'
|
|
||||||
import {useTheme} from '#/alf'
|
import {useTheme} from '#/alf'
|
||||||
import {
|
import {
|
||||||
Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled,
|
Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled,
|
||||||
@@ -74,7 +73,7 @@ export function AnimatedLikeIcon({
|
|||||||
{isLiked ? (
|
{isLiked ? (
|
||||||
// @ts-expect-error is div
|
// @ts-expect-error is div
|
||||||
<View ref={likeIconRef}>
|
<View ref={likeIconRef}>
|
||||||
<HeartIconFilled style={s.likeColor} width={size} />
|
<HeartIconFilled style={{color: t.palette.pink}} width={size} />
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<HeartIconOutline
|
<HeartIconOutline
|
||||||
@@ -87,7 +86,7 @@ export function AnimatedLikeIcon({
|
|||||||
ref={circle1Ref}
|
ref={circle1Ref}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
backgroundColor: s.likeColor.color,
|
backgroundColor: t.palette.pink,
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
width: size,
|
width: size,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {useMemo} from 'react'
|
import {useMemo} from 'react'
|
||||||
import {useNavigation} from '@react-navigation/core'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {useDedupe} from '#/lib/hooks/useDedupe'
|
import {useDedupe} from '#/lib/hooks/useDedupe'
|
||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {useEffect, useMemo, useState} from 'react'
|
import {useEffect, useMemo, useState} from 'react'
|
||||||
import {type EventArg, useNavigation} from '@react-navigation/core'
|
import {type EventArg, useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
if ('scrollRestoration' in history) {
|
if ('scrollRestoration' in history) {
|
||||||
// Tell the brower not to mess with the scroll.
|
// Tell the brower not to mess with the scroll.
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export function Provider({children}: {children: React.ReactNode}) {
|
||||||
|
return children
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useHotkeysContext() {
|
||||||
|
return {
|
||||||
|
enableScope: () => {},
|
||||||
|
disableScope: () => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import {useLingui} from '@lingui/react/macro'
|
||||||
|
import {
|
||||||
|
HotkeysProvider,
|
||||||
|
useHotkeys,
|
||||||
|
useHotkeysContext,
|
||||||
|
} from 'react-hotkeys-hook'
|
||||||
|
|
||||||
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
|
import {emitFocusSearch} from '#/state/events'
|
||||||
|
import {useSession} from '#/state/session'
|
||||||
|
|
||||||
|
enum Hotkeys {
|
||||||
|
OPEN_COMPOSER = 'n',
|
||||||
|
FOCUS_SEARCH = 'slash',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Provider({children}: React.PropsWithChildren<unknown>) {
|
||||||
|
return (
|
||||||
|
<HotkeysProvider initiallyActiveScopes={['global']}>
|
||||||
|
<KeyboardShortcuts>{children}</KeyboardShortcuts>
|
||||||
|
</HotkeysProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {useHotkeysContext}
|
||||||
|
|
||||||
|
function KeyboardShortcuts({children}: React.PropsWithChildren<unknown>) {
|
||||||
|
useKeyboardShortcuts()
|
||||||
|
return children
|
||||||
|
}
|
||||||
|
|
||||||
|
function useKeyboardShortcuts() {
|
||||||
|
const {openComposer} = useOpenComposer()
|
||||||
|
const {hasSession} = useSession()
|
||||||
|
const {t: l} = useLingui()
|
||||||
|
|
||||||
|
const shouldIgnore = (requiresSession: boolean = false) => {
|
||||||
|
if (requiresSession && !hasSession) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKey = (
|
||||||
|
callback: () => void,
|
||||||
|
options?: {requiresSession?: boolean},
|
||||||
|
) => {
|
||||||
|
if (shouldIgnore(options?.requiresSession)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
Hotkeys.OPEN_COMPOSER,
|
||||||
|
() =>
|
||||||
|
handleKey(
|
||||||
|
() => {
|
||||||
|
openComposer({logContext: 'Other'})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requiresSession: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
{scopes: ['global'], description: l`Compose new post`},
|
||||||
|
[openComposer],
|
||||||
|
)
|
||||||
|
|
||||||
|
useHotkeys(Hotkeys.FOCUS_SEARCH, () => handleKey(emitFocusSearch), {
|
||||||
|
scopes: ['global'],
|
||||||
|
preventDefault: true,
|
||||||
|
description: l`Focus the search field`,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
import {manipulateAsync, SaveFormat} from 'expo-image-manipulator'
|
import {manipulateAsync, SaveFormat} from 'expo-image-manipulator'
|
||||||
import * as MediaLibrary from 'expo-media-library'
|
import * as MediaLibrary from 'expo-media-library'
|
||||||
import * as Sharing from 'expo-sharing'
|
import * as Sharing from 'expo-sharing'
|
||||||
import {Buffer} from 'buffer'
|
|
||||||
|
|
||||||
import {POST_IMG_MAX} from '#/lib/constants'
|
import {POST_IMG_MAX} from '#/lib/constants'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
@@ -322,7 +321,12 @@ export async function saveBytesToDisk(
|
|||||||
bytes: Uint8Array,
|
bytes: Uint8Array,
|
||||||
type: string,
|
type: string,
|
||||||
) {
|
) {
|
||||||
const encoded = Buffer.from(bytes).toString('base64')
|
// ideally we'd use `bytes.toBase64()`, but that's only baseline newly available
|
||||||
|
let binary = ''
|
||||||
|
for (const byte of bytes) {
|
||||||
|
binary += String.fromCharCode(byte)
|
||||||
|
}
|
||||||
|
const encoded = btoa(binary)
|
||||||
return await saveToDevice(filename, encoded, type)
|
return await saveToDevice(filename, encoded, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
|
|
||||||
import {createPersistedQueryStorage} from '#/lib/persisted-query-storage'
|
import {createPersistedQueryStorage} from '#/lib/persisted-query-storage'
|
||||||
import {listenNetworkConfirmed, listenNetworkLost} from '#/state/events'
|
import {listenNetworkConfirmed, listenNetworkLost} from '#/state/events'
|
||||||
import {PERSISTED_QUERY_ROOT} from '#/state/queries'
|
import {isQueryPersisted} from '#/state/queries/util'
|
||||||
import * as env from '#/env'
|
import * as env from '#/env'
|
||||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||||
|
|
||||||
@@ -137,8 +137,7 @@ const dehydrateOptions: PersistQueryClientProviderProps['persistOptions']['dehyd
|
|||||||
{
|
{
|
||||||
shouldDehydrateMutation: (_: any) => false,
|
shouldDehydrateMutation: (_: any) => false,
|
||||||
shouldDehydrateQuery: query => {
|
shouldDehydrateQuery: query => {
|
||||||
const root = String(query.queryKey[0])
|
return isQueryPersisted(query.queryKey)
|
||||||
return root === PERSISTED_QUERY_ROOT
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +189,10 @@ function QueryProviderInner({
|
|||||||
})
|
})
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (IS_WEB) {
|
if (IS_WEB) {
|
||||||
window.__TANSTACK_QUERY_CLIENT__ = queryClient
|
// WARNING, BROKEN
|
||||||
|
// something since v5.32.0 causes OOMs. not important
|
||||||
|
// so disable for now
|
||||||
|
// window.__TANSTACK_QUERY_CLIENT__ = queryClient
|
||||||
}
|
}
|
||||||
}, [queryClient])
|
}, [queryClient])
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {XRPCError} from '@atproto/xrpc'
|
import {XRPCError} from '@atproto/api'
|
||||||
import {t} from '@lingui/core/macro'
|
import {t} from '@lingui/core/macro'
|
||||||
|
|
||||||
export function cleanError(str: any): string {
|
export function cleanError(str: any): string {
|
||||||
|
|||||||
+1
-124
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import {type StyleProp, StyleSheet, type TextStyle} from 'react-native'
|
||||||
Dimensions,
|
|
||||||
type StyleProp,
|
|
||||||
StyleSheet,
|
|
||||||
type TextStyle,
|
|
||||||
} from 'react-native'
|
|
||||||
|
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import {type Theme, type TypographyVariant} from './ThemeContext'
|
import {type Theme, type TypographyVariant} from './ThemeContext'
|
||||||
@@ -61,14 +56,6 @@ export const colors = {
|
|||||||
green5: '#082b03',
|
green5: '#082b03',
|
||||||
|
|
||||||
unreadNotifBg: '#ebf6ff',
|
unreadNotifBg: '#ebf6ff',
|
||||||
brandBlue: '#0066FF',
|
|
||||||
like: '#ec4899',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const gradients = {
|
|
||||||
blueLight: {start: '#5A71FA', end: colors.blue3}, // buttons
|
|
||||||
blue: {start: '#5E55FB', end: colors.blue3}, // fab
|
|
||||||
blueDark: {start: '#5F45E0', end: colors.blue3}, // avis, banner
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,57 +65,6 @@ export const s = StyleSheet.create({
|
|||||||
// helpers
|
// helpers
|
||||||
footerSpacer: {height: 100},
|
footerSpacer: {height: 100},
|
||||||
contentContainer: {paddingBottom: 200},
|
contentContainer: {paddingBottom: 200},
|
||||||
contentContainerExtra: {paddingBottom: 300},
|
|
||||||
border0: {borderWidth: 0},
|
|
||||||
border1: {borderWidth: 1},
|
|
||||||
borderTop1: {borderTopWidth: 1},
|
|
||||||
borderRight1: {borderRightWidth: 1},
|
|
||||||
borderBottom1: {borderBottomWidth: 1},
|
|
||||||
borderLeft1: {borderLeftWidth: 1},
|
|
||||||
hidden: {display: 'none'},
|
|
||||||
dimmed: {opacity: 0.5},
|
|
||||||
|
|
||||||
// font weights
|
|
||||||
fw600: {fontWeight: '600'},
|
|
||||||
bold: {fontWeight: '600'},
|
|
||||||
fw500: {fontWeight: '600'},
|
|
||||||
semiBold: {fontWeight: '600'},
|
|
||||||
fw400: {fontWeight: '400'},
|
|
||||||
normal: {fontWeight: '400'},
|
|
||||||
fw300: {fontWeight: '400'},
|
|
||||||
light: {fontWeight: '400'},
|
|
||||||
|
|
||||||
// text decoration
|
|
||||||
underline: {textDecorationLine: 'underline'},
|
|
||||||
|
|
||||||
// font variants
|
|
||||||
tabularNum: {fontVariant: ['tabular-nums']},
|
|
||||||
|
|
||||||
// font sizes
|
|
||||||
f9: {fontSize: 9},
|
|
||||||
f10: {fontSize: 10},
|
|
||||||
f11: {fontSize: 11},
|
|
||||||
f12: {fontSize: 12},
|
|
||||||
f13: {fontSize: 13},
|
|
||||||
f14: {fontSize: 14},
|
|
||||||
f15: {fontSize: 15},
|
|
||||||
f16: {fontSize: 16},
|
|
||||||
f17: {fontSize: 17},
|
|
||||||
f18: {fontSize: 18},
|
|
||||||
|
|
||||||
// line heights
|
|
||||||
['lh13-1']: {lineHeight: 13},
|
|
||||||
['lh13-1.3']: {lineHeight: 16.9}, // 1.3 of 13px
|
|
||||||
['lh14-1']: {lineHeight: 14},
|
|
||||||
['lh14-1.3']: {lineHeight: 18.2}, // 1.3 of 14px
|
|
||||||
['lh15-1']: {lineHeight: 15},
|
|
||||||
['lh15-1.3']: {lineHeight: 19.5}, // 1.3 of 15px
|
|
||||||
['lh16-1']: {lineHeight: 16},
|
|
||||||
['lh16-1.3']: {lineHeight: 20.8}, // 1.3 of 16px
|
|
||||||
['lh17-1']: {lineHeight: 17},
|
|
||||||
['lh17-1.3']: {lineHeight: 22.1}, // 1.3 of 17px
|
|
||||||
['lh18-1']: {lineHeight: 18},
|
|
||||||
['lh18-1.3']: {lineHeight: 23.4}, // 1.3 of 18px
|
|
||||||
|
|
||||||
// margins
|
// margins
|
||||||
mr2: {marginRight: 2},
|
mr2: {marginRight: 2},
|
||||||
@@ -171,74 +107,15 @@ export const s = StyleSheet.create({
|
|||||||
pb20: {paddingBottom: 20},
|
pb20: {paddingBottom: 20},
|
||||||
px5: {paddingHorizontal: 5},
|
px5: {paddingHorizontal: 5},
|
||||||
|
|
||||||
// flex
|
|
||||||
flexRow: {flexDirection: 'row'},
|
|
||||||
flexCol: {flexDirection: 'column'},
|
|
||||||
flex1: {flex: 1},
|
|
||||||
flexGrow1: {flexGrow: 1},
|
|
||||||
alignCenter: {alignItems: 'center'},
|
|
||||||
alignBaseline: {alignItems: 'baseline'},
|
|
||||||
justifyCenter: {justifyContent: 'center'},
|
|
||||||
|
|
||||||
// position
|
|
||||||
absolute: {position: 'absolute'},
|
|
||||||
|
|
||||||
// dimensions
|
// dimensions
|
||||||
w100pct: {width: '100%'},
|
|
||||||
h100pct: {height: '100%'},
|
|
||||||
hContentRegion: IS_WEB ? {minHeight: '100%'} : {height: '100%'},
|
hContentRegion: IS_WEB ? {minHeight: '100%'} : {height: '100%'},
|
||||||
window: {
|
|
||||||
width: Dimensions.get('window').width,
|
|
||||||
height: Dimensions.get('window').height,
|
|
||||||
},
|
|
||||||
|
|
||||||
// text align
|
// text align
|
||||||
textLeft: {textAlign: 'left'},
|
|
||||||
textCenter: {textAlign: 'center'},
|
textCenter: {textAlign: 'center'},
|
||||||
textRight: {textAlign: 'right'},
|
|
||||||
|
|
||||||
// colors
|
// colors
|
||||||
white: {color: colors.white},
|
white: {color: colors.white},
|
||||||
black: {color: colors.black},
|
black: {color: colors.black},
|
||||||
|
|
||||||
gray1: {color: colors.gray1},
|
|
||||||
gray2: {color: colors.gray2},
|
|
||||||
gray3: {color: colors.gray3},
|
|
||||||
gray4: {color: colors.gray4},
|
|
||||||
gray5: {color: colors.gray5},
|
|
||||||
|
|
||||||
blue1: {color: colors.blue1},
|
|
||||||
blue2: {color: colors.blue2},
|
|
||||||
blue3: {color: colors.blue3},
|
|
||||||
blue4: {color: colors.blue4},
|
|
||||||
blue5: {color: colors.blue5},
|
|
||||||
|
|
||||||
red1: {color: colors.red1},
|
|
||||||
red2: {color: colors.red2},
|
|
||||||
red3: {color: colors.red3},
|
|
||||||
red4: {color: colors.red4},
|
|
||||||
red5: {color: colors.red5},
|
|
||||||
|
|
||||||
pink1: {color: colors.pink1},
|
|
||||||
pink2: {color: colors.pink2},
|
|
||||||
pink3: {color: colors.pink3},
|
|
||||||
pink4: {color: colors.pink4},
|
|
||||||
pink5: {color: colors.pink5},
|
|
||||||
|
|
||||||
purple1: {color: colors.purple1},
|
|
||||||
purple2: {color: colors.purple2},
|
|
||||||
purple3: {color: colors.purple3},
|
|
||||||
purple4: {color: colors.purple4},
|
|
||||||
purple5: {color: colors.purple5},
|
|
||||||
|
|
||||||
green1: {color: colors.green1},
|
|
||||||
green2: {color: colors.green2},
|
|
||||||
green3: {color: colors.green3},
|
|
||||||
green4: {color: colors.green4},
|
|
||||||
green5: {color: colors.green5},
|
|
||||||
|
|
||||||
brandBlue: {color: colors.brandBlue},
|
|
||||||
likeColor: {color: colors.like},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export function lh(
|
export function lh(
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import {useCallback, useContext, useEffect, useMemo, useState} from 'react'
|
import {useCallback, useContext, useEffect, useMemo, useState} from 'react'
|
||||||
import {LayoutAnimation, Platform} from 'react-native'
|
import {LayoutAnimation, Platform} from 'react-native'
|
||||||
import {getLocales} from 'expo-localization'
|
import {getLocales} from 'expo-localization'
|
||||||
import {
|
import {onTranslateTask} from '@bsky.app/expo-translate-text'
|
||||||
isTranslationSupported,
|
|
||||||
onTranslateTask,
|
|
||||||
} from '@bsky.app/expo-translate-text'
|
|
||||||
import {type TranslationTaskResult} from '@bsky.app/expo-translate-text/build/ExpoTranslateText.types'
|
import {type TranslationTaskResult} from '@bsky.app/expo-translate-text/build/ExpoTranslateText.types'
|
||||||
import {useLingui} from '@lingui/react/macro'
|
import {useLingui} from '@lingui/react/macro'
|
||||||
import {useFocusEffect} from '@react-navigation/native'
|
import {useFocusEffect} from '@react-navigation/native'
|
||||||
|
|
||||||
import {useGoogleTranslate} from '#/lib/hooks/useGoogleTranslate'
|
import {useGoogleTranslate} from '#/lib/hooks/useGoogleTranslate'
|
||||||
|
import {codeToLanguageName} from '#/locale/helpers'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_ANDROID, IS_IOS} from '#/env'
|
import {IS_ANDROID, IS_IOS, IS_TRANSLATION_SUPPORTED} from '#/env'
|
||||||
import {Context} from './context'
|
import {Context} from './context'
|
||||||
import {
|
import {
|
||||||
type ContextType,
|
type ContextType,
|
||||||
@@ -25,6 +24,11 @@ import {guessLanguage} from './utils'
|
|||||||
export * from './types'
|
export * from './types'
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
|
|
||||||
|
const E_SAME_AS_SOURCE_LANGUAGE =
|
||||||
|
'Translation result is the same as the source text.'
|
||||||
|
const E_EMPTY_RESULT = 'Translation result is empty.'
|
||||||
|
const E_INVALID_SOURCE_LANGUAGE = 'Invalid source language'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts on-device translation via @bsky.app/expo-translate-text.
|
* Attempts on-device translation via @bsky.app/expo-translate-text.
|
||||||
* Uses a lazy import to avoid crashing if the native module isn't linked into
|
* Uses a lazy import to avoid crashing if the native module isn't linked into
|
||||||
@@ -80,11 +84,11 @@ async function attemptTranslation(
|
|||||||
typeof result.translatedTexts === 'string' ? result.translatedTexts : ''
|
typeof result.translatedTexts === 'string' ? result.translatedTexts : ''
|
||||||
|
|
||||||
if (translatedText === input) {
|
if (translatedText === input) {
|
||||||
throw new Error('Translation result is the same as the source text.')
|
throw new Error(E_SAME_AS_SOURCE_LANGUAGE)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (translatedText === '') {
|
if (translatedText === '') {
|
||||||
throw new Error('Translation result is empty.')
|
throw new Error(E_EMPTY_RESULT)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -159,6 +163,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
>({})
|
>({})
|
||||||
const [refCounts, setRefCounts] = useState<Record<string, number>>({})
|
const [refCounts, setRefCounts] = useState<Record<string, number>>({})
|
||||||
const ax = useAnalytics()
|
const ax = useAnalytics()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
const {t: l} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const googleTranslate = useGoogleTranslate()
|
const googleTranslate = useGoogleTranslate()
|
||||||
|
|
||||||
@@ -235,7 +240,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
googleTranslate: shouldForceGoogleTranslate,
|
googleTranslate: shouldForceGoogleTranslate,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (shouldForceGoogleTranslate || !isTranslationSupported()) {
|
if (shouldForceGoogleTranslate || !IS_TRANSLATION_SUPPORTED) {
|
||||||
await googleTranslate(
|
await googleTranslate(
|
||||||
text,
|
text,
|
||||||
expectedTargetLanguage,
|
expectedTargetLanguage,
|
||||||
@@ -280,7 +285,8 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
postLanguages: possibleSourceLanguages,
|
postLanguages: possibleSourceLanguages,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
} catch (e) {
|
} catch (err) {
|
||||||
|
const e = err as Error
|
||||||
logger.error('Failed to translate text on device', {safeMessage: e})
|
logger.error('Failed to translate text on device', {safeMessage: e})
|
||||||
// On-device translation failed (language pack missing or user
|
// On-device translation failed (language pack missing or user
|
||||||
// dismissed the download prompt).
|
// dismissed the download prompt).
|
||||||
@@ -295,6 +301,21 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
textLength: text.length,
|
textLength: text.length,
|
||||||
})
|
})
|
||||||
let errorMessage = l`Device failed to translate :(`
|
let errorMessage = l`Device failed to translate :(`
|
||||||
|
if (e.message === E_SAME_AS_SOURCE_LANGUAGE) {
|
||||||
|
errorMessage = l`Translation to the same language is unavailable on your device.`
|
||||||
|
}
|
||||||
|
if (e.message === E_EMPTY_RESULT) {
|
||||||
|
errorMessage = l`No translation received from your device.`
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
expectedSourceLanguage &&
|
||||||
|
e.message.includes(E_INVALID_SOURCE_LANGUAGE)
|
||||||
|
) {
|
||||||
|
errorMessage = l`${codeToLanguageName(
|
||||||
|
expectedSourceLanguage,
|
||||||
|
langPrefs.appLanguage,
|
||||||
|
)} is not supported by your device.`
|
||||||
|
}
|
||||||
if (!IS_ANDROID) {
|
if (!IS_ANDROID) {
|
||||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut)
|
||||||
}
|
}
|
||||||
@@ -304,7 +325,7 @@ export function Provider({children}: React.PropsWithChildren<unknown>) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[ax, googleTranslate, l],
|
[ax, googleTranslate, l, langPrefs.appLanguage],
|
||||||
)
|
)
|
||||||
|
|
||||||
const ctx = useMemo(
|
const ctx = useMemo(
|
||||||
|
|||||||
@@ -182,6 +182,11 @@ msgstr ""
|
|||||||
msgid "{0} is not available"
|
msgid "{0} is not available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. placeholder {0}: codeToLanguageName( expectedSourceLanguage, langPrefs.appLanguage, )
|
||||||
|
#: src/lib/translation/index.tsx:314
|
||||||
|
msgid "{0} is not supported by your device."
|
||||||
|
msgstr "{0} is not supported by your device."
|
||||||
|
|
||||||
#. placeholder {0}: formatCount(i18n, JOINED_THIS_WEEK)
|
#. placeholder {0}: formatCount(i18n, JOINED_THIS_WEEK)
|
||||||
#: src/screens/StarterPack/StarterPackLandingScreen.tsx:232
|
#: src/screens/StarterPack/StarterPackLandingScreen.tsx:232
|
||||||
msgid "{0} joined this week"
|
msgid "{0} joined this week"
|
||||||
@@ -852,8 +857,8 @@ msgstr ""
|
|||||||
#: src/view/com/composer/GifAltText.tsx:76
|
#: src/view/com/composer/GifAltText.tsx:76
|
||||||
#: src/view/com/composer/GifAltText.tsx:150
|
#: src/view/com/composer/GifAltText.tsx:150
|
||||||
#: src/view/com/composer/GifAltText.tsx:217
|
#: src/view/com/composer/GifAltText.tsx:217
|
||||||
#: src/view/com/composer/photos/Gallery.tsx:194
|
#: src/view/com/composer/photos/Gallery.tsx:196
|
||||||
#: src/view/com/composer/photos/Gallery.tsx:241
|
#: src/view/com/composer/photos/Gallery.tsx:243
|
||||||
#: src/view/com/composer/photos/ImageAltTextDialog.tsx:95
|
#: src/view/com/composer/photos/ImageAltTextDialog.tsx:95
|
||||||
#: src/view/com/composer/photos/ImageAltTextDialog.tsx:103
|
#: src/view/com/composer/photos/ImageAltTextDialog.tsx:103
|
||||||
msgid "Add alt text"
|
msgid "Add alt text"
|
||||||
@@ -905,8 +910,8 @@ msgstr ""
|
|||||||
msgid "Add media to post"
|
msgid "Add media to post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:522
|
#: src/components/moderation/ReportDialog/index.tsx:532
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:526
|
#: src/components/moderation/ReportDialog/index.tsx:536
|
||||||
msgid "Add more details (optional)"
|
msgid "Add more details (optional)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -997,7 +1002,7 @@ msgstr ""
|
|||||||
msgid "Additional details (limit 1000 characters)"
|
msgid "Additional details (limit 1000 characters)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:540
|
#: src/components/moderation/ReportDialog/index.tsx:550
|
||||||
msgid "Additional details (limit 300 characters)"
|
msgid "Additional details (limit 300 characters)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1157,7 +1162,7 @@ msgstr ""
|
|||||||
#: src/components/images/Gallery.tsx:120
|
#: src/components/images/Gallery.tsx:120
|
||||||
#: src/components/Post/Embed/VideoEmbed/GifPresentationControls.tsx:94
|
#: src/components/Post/Embed/VideoEmbed/GifPresentationControls.tsx:94
|
||||||
#: src/view/com/composer/GifAltText.tsx:100
|
#: src/view/com/composer/GifAltText.tsx:100
|
||||||
#: src/view/com/composer/photos/Gallery.tsx:212
|
#: src/view/com/composer/photos/Gallery.tsx:214
|
||||||
msgid "ALT"
|
msgid "ALT"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1176,7 +1181,7 @@ msgid "Alt Text"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/composer/GifAltText.tsx:105
|
#: src/view/com/composer/GifAltText.tsx:105
|
||||||
#: src/view/com/composer/photos/Gallery.tsx:124
|
#: src/view/com/composer/photos/Gallery.tsx:125
|
||||||
msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone."
|
msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1827,20 +1832,20 @@ msgstr ""
|
|||||||
msgid "Browse custom feeds"
|
msgid "Browse custom feeds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/FeedInterstitials.tsx:631
|
#: src/components/FeedInterstitials.tsx:627
|
||||||
msgid "Browse more accounts"
|
msgid "Browse more accounts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/FeedInterstitials.tsx:761
|
#: src/components/FeedInterstitials.tsx:757
|
||||||
msgid "Browse more feeds on the Explore page"
|
msgid "Browse more feeds on the Explore page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/FeedInterstitials.tsx:742
|
#: src/components/FeedInterstitials.tsx:738
|
||||||
#: src/components/FeedInterstitials.tsx:745
|
#: src/components/FeedInterstitials.tsx:741
|
||||||
msgid "Browse more suggestions"
|
msgid "Browse more suggestions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/FeedInterstitials.tsx:770
|
#: src/components/FeedInterstitials.tsx:766
|
||||||
msgid "Browse more suggestions on the Explore page"
|
msgid "Browse more suggestions on the Explore page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1882,7 +1887,7 @@ msgstr ""
|
|||||||
#. placeholder {0}: sanitizeHandle(item.feed.creator.handle, '@')
|
#. placeholder {0}: sanitizeHandle(item.feed.creator.handle, '@')
|
||||||
#. placeholder {0}: sanitizeHandle(labeler.creator.handle, '@')
|
#. placeholder {0}: sanitizeHandle(labeler.creator.handle, '@')
|
||||||
#: src/components/LabelingServiceCard/index.tsx:62
|
#: src/components/LabelingServiceCard/index.tsx:62
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:843
|
#: src/components/moderation/ReportDialog/index.tsx:853
|
||||||
#: src/screens/Search/components/StarterPackCard.tsx:107
|
#: src/screens/Search/components/StarterPackCard.tsx:107
|
||||||
#: src/screens/Search/Explore.tsx:969
|
#: src/screens/Search/Explore.tsx:969
|
||||||
msgid "By {0}"
|
msgid "By {0}"
|
||||||
@@ -1948,7 +1953,7 @@ msgstr ""
|
|||||||
#: src/screens/Deactivated.tsx:150
|
#: src/screens/Deactivated.tsx:150
|
||||||
#: src/screens/Profile/Header/EditProfileDialog.tsx:215
|
#: src/screens/Profile/Header/EditProfileDialog.tsx:215
|
||||||
#: src/screens/Profile/Header/EditProfileDialog.tsx:223
|
#: src/screens/Profile/Header/EditProfileDialog.tsx:223
|
||||||
#: src/screens/Search/Shell.tsx:396
|
#: src/screens/Search/Shell.tsx:397
|
||||||
#: src/screens/Settings/AppIconSettings/index.tsx:42
|
#: src/screens/Settings/AppIconSettings/index.tsx:42
|
||||||
#: src/screens/Settings/AppIconSettings/index.tsx:228
|
#: src/screens/Settings/AppIconSettings/index.tsx:228
|
||||||
#: src/screens/Settings/components/ChangeHandleDialog.tsx:80
|
#: src/screens/Settings/components/ChangeHandleDialog.tsx:80
|
||||||
@@ -1974,7 +1979,7 @@ msgstr ""
|
|||||||
msgid "Cancel reactivation and sign out"
|
msgid "Cancel reactivation and sign out"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/screens/Search/Shell.tsx:387
|
#: src/screens/Search/Shell.tsx:388
|
||||||
msgid "Cancel search"
|
msgid "Cancel search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2023,7 +2028,7 @@ msgstr ""
|
|||||||
msgid "Change Handle"
|
msgid "Change Handle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:439
|
#: src/components/moderation/ReportDialog/index.tsx:449
|
||||||
msgid "Change moderation service"
|
msgid "Change moderation service"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2036,11 +2041,11 @@ msgstr ""
|
|||||||
msgid "Change password dialog"
|
msgid "Change password dialog"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:304
|
#: src/components/moderation/ReportDialog/index.tsx:314
|
||||||
msgid "Change report category"
|
msgid "Change report category"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:384
|
#: src/components/moderation/ReportDialog/index.tsx:394
|
||||||
msgid "Change report reason"
|
msgid "Change report reason"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2213,7 +2218,7 @@ msgstr ""
|
|||||||
msgid "Clear image cache"
|
msgid "Clear image cache"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/forms/SearchInput.tsx:69
|
#: src/components/forms/SearchInput.tsx:87
|
||||||
msgid "Clear search query"
|
msgid "Clear search query"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2333,7 +2338,7 @@ msgstr ""
|
|||||||
msgid "Close dialog"
|
msgid "Close dialog"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/shell/index.web.tsx:131
|
#: src/view/shell/index.web.tsx:129
|
||||||
msgid "Close drawer menu"
|
msgid "Close drawer menu"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2425,6 +2430,7 @@ msgstr ""
|
|||||||
msgid "Complete the challenge"
|
msgid "Complete the challenge"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/lib/hotkeys/index.tsx:66
|
||||||
#: src/view/com/feeds/ComposerPrompt.tsx:147
|
#: src/view/com/feeds/ComposerPrompt.tsx:147
|
||||||
#: src/view/shell/desktop/LeftNav.tsx:575
|
#: src/view/shell/desktop/LeftNav.tsx:575
|
||||||
msgid "Compose new post"
|
msgid "Compose new post"
|
||||||
@@ -2913,8 +2919,8 @@ msgstr ""
|
|||||||
|
|
||||||
#. Accessibility label for button to create a moderation report for the selected option
|
#. Accessibility label for button to create a moderation report for the selected option
|
||||||
#. placeholder {0}: option.title
|
#. placeholder {0}: option.title
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:703
|
#: src/components/moderation/ReportDialog/index.tsx:713
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:749
|
#: src/components/moderation/ReportDialog/index.tsx:759
|
||||||
msgid "Create report for {0}"
|
msgid "Create report for {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -3159,7 +3165,7 @@ msgstr ""
|
|||||||
msgid "Developer options"
|
msgid "Developer options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/lib/translation/index.tsx:297
|
#: src/lib/translation/index.tsx:303
|
||||||
msgid "Device failed to translate :("
|
msgid "Device failed to translate :("
|
||||||
msgstr "Device failed to translate :("
|
msgstr "Device failed to translate :("
|
||||||
|
|
||||||
@@ -3489,7 +3495,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/view/com/composer/photos/EditImageDialog.web.tsx:86
|
#: src/view/com/composer/photos/EditImageDialog.web.tsx:86
|
||||||
#: src/view/com/composer/photos/EditImageDialog.web.tsx:90
|
#: src/view/com/composer/photos/EditImageDialog.web.tsx:90
|
||||||
#: src/view/com/composer/photos/Gallery.tsx:219
|
#: src/view/com/composer/photos/Gallery.tsx:221
|
||||||
msgid "Edit image"
|
msgid "Edit image"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -3760,7 +3766,7 @@ msgstr ""
|
|||||||
msgid "Enter your username and password"
|
msgid "Enter your username and password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:148
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:150
|
||||||
msgid "Enters full screen"
|
msgid "Enters full screen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -4201,7 +4207,7 @@ msgstr ""
|
|||||||
#. placeholder {0}: sanitizeHandle(feed.creatorHandle, '@')
|
#. placeholder {0}: sanitizeHandle(feed.creatorHandle, '@')
|
||||||
#. placeholder {0}: sanitizeHandle(view.creator.handle, '@')
|
#. placeholder {0}: sanitizeHandle(view.creator.handle, '@')
|
||||||
#: src/components/FeedCard.tsx:170
|
#: src/components/FeedCard.tsx:170
|
||||||
#: src/state/queries/feed.ts:121
|
#: src/state/queries/feed.ts:118
|
||||||
#: src/view/com/feeds/FeedSourceCard.tsx:151
|
#: src/view/com/feeds/FeedSourceCard.tsx:151
|
||||||
msgid "Feed by {0}"
|
msgid "Feed by {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -4344,7 +4350,7 @@ msgstr ""
|
|||||||
msgid "Find people to follow"
|
msgid "Find people to follow"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/screens/Search/Shell.tsx:529
|
#: src/screens/Search/Shell.tsx:530
|
||||||
msgid "Find posts, users, and feeds on Bluesky"
|
msgid "Find posts, users, and feeds on Bluesky"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -4388,6 +4394,10 @@ msgstr ""
|
|||||||
msgid "Focus code input"
|
msgid "Focus code input"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/lib/hotkeys/index.tsx:73
|
||||||
|
msgid "Focus the search field"
|
||||||
|
msgstr "Focus the search field"
|
||||||
|
|
||||||
#. User is not following this account, click to follow
|
#. User is not following this account, click to follow
|
||||||
#: src/components/ProfileCard.tsx:546
|
#: src/components/ProfileCard.tsx:546
|
||||||
#: src/components/ProfileHoverCard/index.web.tsx:495
|
#: src/components/ProfileHoverCard/index.web.tsx:495
|
||||||
@@ -5933,7 +5943,7 @@ msgstr ""
|
|||||||
msgid "Load new notifications"
|
msgid "Load new notifications"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/screens/Profile/ProfileFeed/index.tsx:203
|
#: src/screens/Profile/ProfileFeed/index.tsx:204
|
||||||
#: src/screens/Profile/Sections/Feed.tsx:117
|
#: src/screens/Profile/Sections/Feed.tsx:117
|
||||||
#: src/screens/ProfileList/FeedSection.tsx:113
|
#: src/screens/ProfileList/FeedSection.tsx:113
|
||||||
#: src/view/com/feeds/FeedPage.tsx:170
|
#: src/view/com/feeds/FeedPage.tsx:170
|
||||||
@@ -6236,7 +6246,7 @@ msgstr ""
|
|||||||
msgid "Music"
|
msgid "Music"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:169
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:171
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:97
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:97
|
||||||
msgctxt "video"
|
msgctxt "video"
|
||||||
msgid "Mute"
|
msgid "Mute"
|
||||||
@@ -6383,8 +6393,8 @@ msgstr ""
|
|||||||
msgid "Navigates to your profile"
|
msgid "Navigates to your profile"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:335
|
#: src/components/moderation/ReportDialog/index.tsx:345
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:352
|
#: src/components/moderation/ReportDialog/index.tsx:362
|
||||||
msgid "Need to report a copyright violation, legal request, or regulatory compliance issue?"
|
msgid "Need to report a copyright violation, legal request, or regulatory compliance issue?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -6470,7 +6480,7 @@ msgstr ""
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/screens/Profile/ProfileFeed/index.tsx:220
|
#: src/screens/Profile/ProfileFeed/index.tsx:221
|
||||||
#: src/screens/ProfileList/index.tsx:251
|
#: src/screens/ProfileList/index.tsx:251
|
||||||
#: src/screens/ProfileList/index.tsx:300
|
#: src/screens/ProfileList/index.tsx:300
|
||||||
#: src/view/screens/Feeds.tsx:553
|
#: src/view/screens/Feeds.tsx:553
|
||||||
@@ -6480,13 +6490,9 @@ msgid "New post"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/feeds/FeedPage.tsx:181
|
#: src/view/com/feeds/FeedPage.tsx:181
|
||||||
msgctxt "action"
|
|
||||||
msgid "New post"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/view/shell/desktop/LeftNav.tsx:583
|
#: src/view/shell/desktop/LeftNav.tsx:583
|
||||||
msgctxt "action"
|
msgctxt "action"
|
||||||
msgid "New Post"
|
msgid "New post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/notifications/NotificationFeedItem.tsx:545
|
#: src/view/com/notifications/NotificationFeedItem.tsx:545
|
||||||
@@ -6712,6 +6718,10 @@ msgstr ""
|
|||||||
msgid "No thanks"
|
msgid "No thanks"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/lib/translation/index.tsx:308
|
||||||
|
msgid "No translation received from your device."
|
||||||
|
msgstr "No translation received from your device."
|
||||||
|
|
||||||
#: src/view/screens/Profile.tsx:500
|
#: src/view/screens/Profile.tsx:500
|
||||||
msgid "No video posts yet"
|
msgid "No video posts yet"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -7262,7 +7272,7 @@ msgstr ""
|
|||||||
msgid "Password updated!"
|
msgid "Password updated!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:153
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:155
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:395
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:395
|
||||||
msgid "Pause"
|
msgid "Pause"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -7377,7 +7387,7 @@ msgstr ""
|
|||||||
msgid "Pinned to your feeds"
|
msgid "Pinned to your feeds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:153
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:155
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:396
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VideoControls.tsx:396
|
||||||
msgid "Play"
|
msgid "Play"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -7404,7 +7414,7 @@ msgstr ""
|
|||||||
msgid "Plays or pauses the GIF"
|
msgid "Plays or pauses the GIF"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:154
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:156
|
||||||
msgid "Plays or pauses the video"
|
msgid "Plays or pauses the video"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -8121,7 +8131,7 @@ msgstr ""
|
|||||||
msgid "Remove from your feeds?"
|
msgid "Remove from your feeds?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/composer/photos/Gallery.tsx:228
|
#: src/view/com/composer/photos/Gallery.tsx:230
|
||||||
msgid "Remove image"
|
msgid "Remove image"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -8329,7 +8339,7 @@ msgid "Report conversation"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:98
|
#: src/components/moderation/ReportDialog/index.tsx:98
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:255
|
#: src/components/moderation/ReportDialog/index.tsx:265
|
||||||
msgid "Report dialog"
|
msgid "Report dialog"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -8544,7 +8554,7 @@ msgstr ""
|
|||||||
#: src/components/dms/MessageItem.tsx:322
|
#: src/components/dms/MessageItem.tsx:322
|
||||||
#: src/components/Error.tsx:66
|
#: src/components/Error.tsx:66
|
||||||
#: src/components/Lists.tsx:115
|
#: src/components/Lists.tsx:115
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:289
|
#: src/components/moderation/ReportDialog/index.tsx:299
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:56
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:56
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:59
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:59
|
||||||
#: src/components/StarterPack/ProfileStarterPacks.tsx:377
|
#: src/components/StarterPack/ProfileStarterPacks.tsx:377
|
||||||
@@ -8566,7 +8576,7 @@ msgstr ""
|
|||||||
msgid "Retry"
|
msgid "Retry"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:286
|
#: src/components/moderation/ReportDialog/index.tsx:296
|
||||||
#: src/view/screens/Storybook/Admonitions.tsx:61
|
#: src/view/screens/Storybook/Admonitions.tsx:61
|
||||||
msgid "Retry loading report options"
|
msgid "Retry loading report options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -8722,10 +8732,10 @@ msgid "Scroll to top"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/dialogs/SearchablePeopleList.tsx:515
|
#: src/components/dialogs/SearchablePeopleList.tsx:515
|
||||||
#: src/components/forms/SearchInput.tsx:33
|
#: src/components/forms/SearchInput.tsx:51
|
||||||
#: src/components/forms/SearchInput.tsx:35
|
#: src/components/forms/SearchInput.tsx:53
|
||||||
#: src/screens/Search/Shell.tsx:354
|
#: src/screens/Search/Shell.tsx:354
|
||||||
#: src/screens/Search/Shell.tsx:517
|
#: src/screens/Search/Shell.tsx:518
|
||||||
#: src/view/shell/bottom-bar/BottomBar.tsx:199
|
#: src/view/shell/bottom-bar/BottomBar.tsx:199
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -8759,14 +8769,14 @@ msgstr ""
|
|||||||
msgid "Search for \"{interestsDisplayName}\" (active)"
|
msgid "Search for \"{interestsDisplayName}\" (active)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/shell/desktop/Search.tsx:130
|
|
||||||
msgid "Search for \"{query}\""
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/screens/Search/components/AutocompleteResults.tsx:47
|
#: src/screens/Search/components/AutocompleteResults.tsx:47
|
||||||
msgid "Search for \"{searchText}\""
|
msgid "Search for \"{searchText}\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/view/shell/desktop/Search.tsx:129
|
||||||
|
msgid "Search for “{tQuery}”"
|
||||||
|
msgstr "Search for “{tQuery}”"
|
||||||
|
|
||||||
#: src/screens/StarterPack/Wizard/index.tsx:552
|
#: src/screens/StarterPack/Wizard/index.tsx:552
|
||||||
msgid "Search for feeds that you want to suggest to others."
|
msgid "Search for feeds that you want to suggest to others."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -8864,12 +8874,12 @@ msgstr ""
|
|||||||
msgid "See jobs at Bluesky"
|
msgid "See jobs at Bluesky"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/FeedInterstitials.tsx:584
|
#: src/components/FeedInterstitials.tsx:583
|
||||||
#: src/components/FeedInterstitials.tsx:645
|
#: src/components/FeedInterstitials.tsx:641
|
||||||
msgid "See more"
|
msgid "See more"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/FeedInterstitials.tsx:565
|
#: src/components/FeedInterstitials.tsx:564
|
||||||
msgid "See more suggested profiles"
|
msgid "See more suggested profiles"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -8906,7 +8916,7 @@ msgstr ""
|
|||||||
msgid "Select a color"
|
msgid "Select a color"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:374
|
#: src/components/moderation/ReportDialog/index.tsx:384
|
||||||
msgid "Select a reason"
|
msgid "Select a reason"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -8991,7 +9001,7 @@ msgstr ""
|
|||||||
msgid "Select languages"
|
msgid "Select languages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:424
|
#: src/components/moderation/ReportDialog/index.tsx:434
|
||||||
msgid "Select moderation service"
|
msgid "Select moderation service"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -9090,7 +9100,7 @@ msgstr ""
|
|||||||
msgid "Send post to..."
|
msgid "Send post to..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:814
|
#: src/components/moderation/ReportDialog/index.tsx:824
|
||||||
msgid "Send report to {title}"
|
msgid "Send report to {title}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -9565,7 +9575,7 @@ msgstr ""
|
|||||||
msgid "Some of your verifications are invalid."
|
msgid "Some of your verifications are invalid."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/FeedInterstitials.tsx:724
|
#: src/components/FeedInterstitials.tsx:720
|
||||||
msgid "Some other feeds you might like"
|
msgid "Some other feeds you might like"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -9593,7 +9603,7 @@ msgid "Something went wrong"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/ageAssurance/AgeAssuranceInitDialog.tsx:139
|
#: src/components/ageAssurance/AgeAssuranceInitDialog.tsx:139
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:281
|
#: src/components/moderation/ReportDialog/index.tsx:291
|
||||||
#: src/screens/Deactivated.tsx:86
|
#: src/screens/Deactivated.tsx:86
|
||||||
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:59
|
#: src/screens/Settings/components/DeactivateAccountDialog.tsx:59
|
||||||
#: src/view/screens/Storybook/Admonitions.tsx:56
|
#: src/view/screens/Storybook/Admonitions.tsx:56
|
||||||
@@ -9625,7 +9635,7 @@ msgstr ""
|
|||||||
msgid "Sorry, we're unable to load account suggestions at this time."
|
msgid "Sorry, we're unable to load account suggestions at this time."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/App.native.tsx:142
|
#: src/App.native.tsx:141
|
||||||
#: src/App.web.tsx:119
|
#: src/App.web.tsx:119
|
||||||
msgid "Sorry! Your session expired. Please sign in again."
|
msgid "Sorry! Your session expired. Please sign in again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -9778,9 +9788,9 @@ msgstr ""
|
|||||||
msgid "Submit Appeal"
|
msgid "Submit Appeal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:502
|
#: src/components/moderation/ReportDialog/index.tsx:512
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:563
|
#: src/components/moderation/ReportDialog/index.tsx:573
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:570
|
#: src/components/moderation/ReportDialog/index.tsx:580
|
||||||
msgid "Submit report"
|
msgid "Submit report"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -10175,7 +10185,7 @@ msgid "There was an issue fetching notifications. Tap here to try again."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/screens/Search/Explore.tsx:1025
|
#: src/screens/Search/Explore.tsx:1025
|
||||||
#: src/view/com/posts/PostFeed.tsx:763
|
#: src/view/com/posts/PostFeed.tsx:773
|
||||||
msgid "There was an issue fetching posts. Tap here to try again."
|
msgid "There was an issue fetching posts. Tap here to try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -10609,7 +10619,7 @@ msgstr ""
|
|||||||
msgid "Toggle to enable or disable adult content"
|
msgid "Toggle to enable or disable adult content"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:171
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:173
|
||||||
msgid "Toggles the sound"
|
msgid "Toggles the sound"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -10664,6 +10674,10 @@ msgstr "Translating"
|
|||||||
msgid "Translating…"
|
msgid "Translating…"
|
||||||
msgstr "Translating…"
|
msgstr "Translating…"
|
||||||
|
|
||||||
|
#: src/lib/translation/index.tsx:305
|
||||||
|
msgid "Translation to the same language is unavailable on your device."
|
||||||
|
msgstr "Translation to the same language is unavailable on your device."
|
||||||
|
|
||||||
#: src/screens/Settings/ThreadPreferences.tsx:87
|
#: src/screens/Settings/ThreadPreferences.tsx:87
|
||||||
#: src/screens/Settings/ThreadPreferences.tsx:92
|
#: src/screens/Settings/ThreadPreferences.tsx:92
|
||||||
msgid "Tree view"
|
msgid "Tree view"
|
||||||
@@ -10843,7 +10857,7 @@ msgstr ""
|
|||||||
msgid "Unfollows the user"
|
msgid "Unfollows the user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:486
|
#: src/components/moderation/ReportDialog/index.tsx:496
|
||||||
msgid "Unfortunately, none of your subscribed labelers supports this report type."
|
msgid "Unfortunately, none of your subscribed labelers supports this report type."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -10882,7 +10896,7 @@ msgstr ""
|
|||||||
msgid "Unmute"
|
msgid "Unmute"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:168
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:170
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:96
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/web-controls/VolumeControl.tsx:96
|
||||||
msgctxt "video"
|
msgctxt "video"
|
||||||
msgid "Unmute"
|
msgid "Unmute"
|
||||||
@@ -10981,6 +10995,10 @@ msgstr ""
|
|||||||
msgid "Unsubscribed from list"
|
msgid "Unsubscribed from list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/view/com/composer/text-input/TextInput.tsx:131
|
||||||
|
msgid "Unsupported clipboard content"
|
||||||
|
msgstr "Unsupported clipboard content"
|
||||||
|
|
||||||
#: src/view/com/composer/Composer.tsx:1369
|
#: src/view/com/composer/Composer.tsx:1369
|
||||||
msgid "Unsupported video type: {mimeType}"
|
msgid "Unsupported video type: {mimeType}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -11136,7 +11154,7 @@ msgid "User list by {0}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: sanitizeHandle(view.creator.handle, '@')
|
#. placeholder {0}: sanitizeHandle(view.creator.handle, '@')
|
||||||
#: src/state/queries/feed.ts:162
|
#: src/state/queries/feed.ts:159
|
||||||
msgid "User List by {0}"
|
msgid "User List by {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -11295,8 +11313,8 @@ msgstr ""
|
|||||||
msgid "Version {0}"
|
msgid "Version {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:86
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:87
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:147
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:149
|
||||||
msgid "Video"
|
msgid "Video"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -11344,7 +11362,7 @@ msgid "Video uploaded"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: embed.alt
|
#. placeholder {0}: embed.alt
|
||||||
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:86
|
#: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerNative.tsx:87
|
||||||
msgid "Video: {0}"
|
msgid "Video: {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -12522,7 +12540,7 @@ msgid "Your reply was sent"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: state.selectedLabeler?.creator.displayName
|
#. placeholder {0}: state.selectedLabeler?.creator.displayName
|
||||||
#: src/components/moderation/ReportDialog/index.tsx:513
|
#: src/components/moderation/ReportDialog/index.tsx:523
|
||||||
msgid "Your report will be sent to <0>{0}</0>."
|
msgid "Your report will be sent to <0>{0}</0>."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -52,8 +52,9 @@ import {atoms as a, native, platform, useBreakpoints, web} from '#/alf'
|
|||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
import {ListFooter} from '#/components/Lists'
|
import {ListFooter} from '#/components/Lists'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
import {IS_NATIVE} from '#/env'
|
||||||
|
|
||||||
const PARENT_CHUNK_SIZE = 20
|
const PARENT_CHUNK_SIZE = IS_NATIVE ? 5 : 20
|
||||||
const CHILDREN_CHUNK_SIZE = 50
|
const CHILDREN_CHUNK_SIZE = 50
|
||||||
|
|
||||||
export function PostThread({uri}: {uri: string}) {
|
export function PostThread({uri}: {uri: string}) {
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ export function ProfileFeedScreenInner({
|
|||||||
|
|
||||||
<FeedFeedbackProvider value={feedFeedback}>
|
<FeedFeedbackProvider value={feedFeedback}>
|
||||||
<PostFeed
|
<PostFeed
|
||||||
|
enabled
|
||||||
feed={feed}
|
feed={feed}
|
||||||
feedParams={feedParams}
|
feedParams={feedParams}
|
||||||
pollInterval={60e3}
|
pollInterval={60e3}
|
||||||
|
|||||||
@@ -380,6 +380,7 @@ export function SearchScreenShell({
|
|||||||
inputPlaceholder ?? l`Search for posts, users, or feeds`
|
inputPlaceholder ?? l`Search for posts, users, or feeds`
|
||||||
}
|
}
|
||||||
hitSlop={{...HITSLOP_20, top: 0}}
|
hitSlop={{...HITSLOP_20, top: 0}}
|
||||||
|
hotkey={true}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
{showAutocomplete && (
|
{showAutocomplete && (
|
||||||
|
|||||||
Vendored
+1
-1
@@ -5,7 +5,7 @@ import {
|
|||||||
type AppBskyFeedDefs,
|
type AppBskyFeedDefs,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {type QueryClient} from '@tanstack/react-query'
|
import {type QueryClient} from '@tanstack/react-query'
|
||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
import {batchedUpdates} from '#/lib/batchedUpdates'
|
import {batchedUpdates} from '#/lib/batchedUpdates'
|
||||||
import {findAllPostsInQueryData as findAllPostsInBookmarksQueryData} from '#/state/queries/bookmarks/useBookmarksQuery'
|
import {findAllPostsInQueryData as findAllPostsInBookmarksQueryData} from '#/state/queries/bookmarks/useBookmarksQuery'
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
import {useEffect, useMemo, useState} from 'react'
|
import {useEffect, useMemo, useState} from 'react'
|
||||||
import {type AppBskyActorDefs, type AppBskyNotificationDefs} from '@atproto/api'
|
import {type AppBskyActorDefs, type AppBskyNotificationDefs} from '@atproto/api'
|
||||||
import {type QueryClient} from '@tanstack/react-query'
|
import {type QueryClient} from '@tanstack/react-query'
|
||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
import {batchedUpdates} from '#/lib/batchedUpdates'
|
import {batchedUpdates} from '#/lib/batchedUpdates'
|
||||||
import {findAllProfilesInQueryData as findAllProfilesInActivitySubscriptionsQueryData} from '#/state/queries/activity-subscriptions'
|
import {findAllProfilesInQueryData as findAllProfilesInActivitySubscriptionsQueryData} from '#/state/queries/activity-subscriptions'
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
|
|
||||||
|
import {useHotkeysContext} from '#/lib/hotkeys'
|
||||||
import {type DialogControlRefProps} from '#/components/Dialog'
|
import {type DialogControlRefProps} from '#/components/Dialog'
|
||||||
import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context'
|
import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
@@ -62,6 +63,7 @@ export function useDialogFullyExpandedCountContext() {
|
|||||||
|
|
||||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
const [fullyExpandedCount, setFullyExpandedCount] = useState(0)
|
const [fullyExpandedCount, setFullyExpandedCount] = useState(0)
|
||||||
|
const {disableScope, enableScope} = useHotkeysContext()
|
||||||
|
|
||||||
const activeDialogs = useRef<
|
const activeDialogs = useRef<
|
||||||
Map<string, React.MutableRefObject<DialogControlRefProps>>
|
Map<string, React.MutableRefObject<DialogControlRefProps>>
|
||||||
@@ -77,18 +79,26 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
|
|
||||||
return openDialogs.current.size > 0
|
return openDialogs.current.size > 0
|
||||||
} else {
|
} else {
|
||||||
BottomSheetNativeComponent.dismissAll()
|
void BottomSheetNativeComponent.dismissAll()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const setDialogIsOpen = useCallback((id: string, isOpen: boolean) => {
|
const setDialogIsOpen = useCallback(
|
||||||
|
(id: string, isOpen: boolean) => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
openDialogs.current.add(id)
|
openDialogs.current.add(id)
|
||||||
} else {
|
} else {
|
||||||
openDialogs.current.delete(id)
|
openDialogs.current.delete(id)
|
||||||
}
|
}
|
||||||
}, [])
|
if (openDialogs.current.size > 0) {
|
||||||
|
disableScope('global')
|
||||||
|
} else {
|
||||||
|
enableScope('global')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[disableScope, enableScope],
|
||||||
|
)
|
||||||
|
|
||||||
const context = useMemo<IDialogContext>(
|
const context = useMemo<IDialogContext>(
|
||||||
() => ({
|
() => ({
|
||||||
|
|||||||
+9
-1
@@ -1,4 +1,4 @@
|
|||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
type UnlistenFn = () => void
|
type UnlistenFn = () => void
|
||||||
|
|
||||||
@@ -45,3 +45,11 @@ export function listenPostCreated(fn: () => void): UnlistenFn {
|
|||||||
emitter.on('post-created', fn)
|
emitter.on('post-created', fn)
|
||||||
return () => emitter.off('post-created', fn)
|
return () => emitter.off('post-created', fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function emitFocusSearch() {
|
||||||
|
emitter.emit('focus-search')
|
||||||
|
}
|
||||||
|
export function listenFocusSearch(fn: () => void): UnlistenFn {
|
||||||
|
emitter.on('focus-search', fn)
|
||||||
|
return () => emitter.off('focus-search', fn)
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
type GestureUpdateEvent,
|
type GestureUpdateEvent,
|
||||||
type PanGestureHandlerEventPayload,
|
type PanGestureHandlerEventPayload,
|
||||||
} from 'react-native-gesture-handler'
|
} from 'react-native-gesture-handler'
|
||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
export type GlobalGestureEvents = {
|
export type GlobalGestureEvents = {
|
||||||
begin: GestureStateChangeEvent<PanGestureHandlerEventPayload>
|
begin: GestureStateChangeEvent<PanGestureHandlerEventPayload>
|
||||||
|
|||||||
+11
-1
@@ -1,7 +1,8 @@
|
|||||||
import {createContext, useContext, useMemo, useState} from 'react'
|
import {createContext, useContext, useEffect, useMemo, useState} from 'react'
|
||||||
import {nanoid} from 'nanoid/non-secure'
|
import {nanoid} from 'nanoid/non-secure'
|
||||||
|
|
||||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||||
|
import {useHotkeysContext} from '#/lib/hotkeys'
|
||||||
import {type ImageSource} from '#/view/com/lightbox/ImageViewing/@types'
|
import {type ImageSource} from '#/view/com/lightbox/ImageViewing/@types'
|
||||||
|
|
||||||
export type Lightbox = {
|
export type Lightbox = {
|
||||||
@@ -28,6 +29,15 @@ LightboxControlContext.displayName = 'LightboxControlContext'
|
|||||||
|
|
||||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
const [activeLightbox, setActiveLightbox] = useState<Lightbox | null>(null)
|
const [activeLightbox, setActiveLightbox] = useState<Lightbox | null>(null)
|
||||||
|
const {disableScope, enableScope} = useHotkeysContext()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeLightbox) {
|
||||||
|
disableScope('global')
|
||||||
|
} else {
|
||||||
|
enableScope('global')
|
||||||
|
}
|
||||||
|
}, [activeLightbox, disableScope, enableScope])
|
||||||
|
|
||||||
const openLightbox = useNonReactiveCallback(
|
const openLightbox = useNonReactiveCallback(
|
||||||
(lightbox: Omit<Lightbox, 'id'>) => {
|
(lightbox: Omit<Lightbox, 'id'>) => {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import {
|
|||||||
type ChatBskyConvoGetLog,
|
type ChatBskyConvoGetLog,
|
||||||
type ChatBskyConvoSendMessage,
|
type ChatBskyConvoSendMessage,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {XRPCError} from '@atproto/xrpc'
|
import {XRPCError} from '@atproto/api'
|
||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
import {nanoid} from 'nanoid/non-secure'
|
import {nanoid} from 'nanoid/non-secure'
|
||||||
|
|
||||||
import {networkRetry} from '#/lib/async/retry'
|
import {networkRetry} from '#/lib/async/retry'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {type BskyAgent, type ChatBskyConvoGetLog} from '@atproto/api'
|
import {type BskyAgent, type ChatBskyConvoGetLog} from '@atproto/api'
|
||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
import {nanoid} from 'nanoid/non-secure'
|
import {nanoid} from 'nanoid/non-secure'
|
||||||
|
|
||||||
import {networkRetry} from '#/lib/async/retry'
|
import {networkRetry} from '#/lib/async/retry'
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {createContext, useContext, useMemo, useState} from 'react'
|
import {createContext, useContext, useEffect, useMemo, useState} from 'react'
|
||||||
|
|
||||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||||
|
import {useHotkeysContext} from '#/lib/hotkeys'
|
||||||
|
|
||||||
export interface UserAddRemoveListsModal {
|
export interface UserAddRemoveListsModal {
|
||||||
name: 'user-add-remove-lists'
|
name: 'user-add-remove-lists'
|
||||||
@@ -47,6 +48,15 @@ ModalControlContext.displayName = 'ModalControlContext'
|
|||||||
|
|
||||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
const [activeModals, setActiveModals] = useState<Modal[]>([])
|
const [activeModals, setActiveModals] = useState<Modal[]>([])
|
||||||
|
const {disableScope, enableScope} = useHotkeysContext()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (activeModals.length > 0) {
|
||||||
|
disableScope('global')
|
||||||
|
} else {
|
||||||
|
enableScope('global')
|
||||||
|
}
|
||||||
|
}, [activeModals.length, disableScope, enableScope])
|
||||||
|
|
||||||
const openModal = useNonReactiveCallback((modal: Modal) => {
|
const openModal = useNonReactiveCallback((modal: Modal) => {
|
||||||
setActiveModals(modals => [...modals, modal])
|
setActiveModals(modals => [...modals, modal])
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
import BroadcastChannel from '#/lib/broadcast'
|
import BroadcastChannel from '#/lib/broadcast'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
|
|||||||
+18
-11
@@ -22,13 +22,10 @@ import {
|
|||||||
import {DISCOVER_FEED_URI, DISCOVER_SAVED_FEED} from '#/lib/constants'
|
import {DISCOVER_FEED_URI, DISCOVER_SAVED_FEED} from '#/lib/constants'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {
|
import {GCTIME, STALE} from '#/state/queries'
|
||||||
PERSISTED_QUERY_GCTIME,
|
|
||||||
PERSISTED_QUERY_ROOT,
|
|
||||||
STALE,
|
|
||||||
} from '#/state/queries'
|
|
||||||
import {RQKEY as listQueryKey} from '#/state/queries/list'
|
import {RQKEY as listQueryKey} from '#/state/queries/list'
|
||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
|
import {createQueryKey} from '#/state/queries/util'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
import {router} from '#/routes'
|
import {router} from '#/routes'
|
||||||
import {useModerationOpts} from '../preferences/moderation-opts'
|
import {useModerationOpts} from '../preferences/moderation-opts'
|
||||||
@@ -416,10 +413,20 @@ const PWI_DISCOVER_FEED_STUB: SavedFeedSourceInfo = {
|
|||||||
contentMode: undefined,
|
contentMode: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
const createPinnedFeedInfosQueryKeyRoot = (
|
const createPinnedFeedInfosQueryKey = (
|
||||||
kind: 'pinned' | 'saved',
|
kind: 'pinned' | 'saved',
|
||||||
feedUris: string[],
|
feedUris: string[],
|
||||||
) => [PERSISTED_QUERY_ROOT, 'feed-info', kind, feedUris]
|
) =>
|
||||||
|
createQueryKey(
|
||||||
|
'feed-info',
|
||||||
|
{
|
||||||
|
kind,
|
||||||
|
feedUris,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
persistedVersion: 1,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
export function usePinnedFeedsInfos() {
|
export function usePinnedFeedsInfos() {
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
@@ -428,11 +435,11 @@ export function usePinnedFeedsInfos() {
|
|||||||
const pinnedItems = preferences?.savedFeeds.filter(feed => feed.pinned) ?? []
|
const pinnedItems = preferences?.savedFeeds.filter(feed => feed.pinned) ?? []
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: createPinnedFeedInfosQueryKeyRoot(
|
queryKey: createPinnedFeedInfosQueryKey(
|
||||||
'pinned',
|
'pinned',
|
||||||
pinnedItems.map(f => f.value),
|
pinnedItems.map(f => f.value),
|
||||||
),
|
),
|
||||||
gcTime: PERSISTED_QUERY_GCTIME,
|
gcTime: GCTIME.INFINITY,
|
||||||
staleTime: STALE.INFINITY,
|
staleTime: STALE.INFINITY,
|
||||||
enabled: !isLoadingPrefs,
|
enabled: !isLoadingPrefs,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@@ -536,11 +543,11 @@ export function useSavedFeeds() {
|
|||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: createPinnedFeedInfosQueryKeyRoot(
|
queryKey: createPinnedFeedInfosQueryKey(
|
||||||
'saved',
|
'saved',
|
||||||
savedItems.map(f => f.value),
|
savedItems.map(f => f.value),
|
||||||
),
|
),
|
||||||
gcTime: PERSISTED_QUERY_GCTIME,
|
gcTime: GCTIME.INFINITY,
|
||||||
staleTime: STALE.INFINITY,
|
staleTime: STALE.INFINITY,
|
||||||
enabled: !isLoadingPrefs,
|
enabled: !isLoadingPrefs,
|
||||||
placeholderData: previousData => {
|
placeholderData: previousData => {
|
||||||
|
|||||||
@@ -19,22 +19,6 @@ export const STALE = {
|
|||||||
INFINITY: Infinity,
|
INFINITY: Infinity,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export const GCTIME = {
|
||||||
* Root key for persisted queries.
|
INFINITY: Infinity,
|
||||||
*
|
}
|
||||||
* If the `querykey` of your query uses this at index 0, it will be
|
|
||||||
* persisted automatically by the `PersistQueryClientProvider` in
|
|
||||||
* `#/lib/react-query.tsx`.
|
|
||||||
*
|
|
||||||
* Be careful when using this, since it will change the query key and may
|
|
||||||
* break any cases where we call `invalidateQueries` or `refetchQueries`
|
|
||||||
* with the old key.
|
|
||||||
*
|
|
||||||
* Also, only use this for queries that are safe to persist between
|
|
||||||
* app launches (like user preferences).
|
|
||||||
*
|
|
||||||
* Note that for queries that are persisted, it is recommended to extend
|
|
||||||
* the `gcTime` to a longer duration, otherwise it'll get busted
|
|
||||||
*/
|
|
||||||
export const PERSISTED_QUERY_ROOT = 'PERSISTED'
|
|
||||||
export const PERSISTED_QUERY_GCTIME = Infinity
|
|
||||||
|
|||||||
@@ -3,15 +3,12 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
|||||||
import {z} from 'zod'
|
import {z} from 'zod'
|
||||||
|
|
||||||
import {MAX_LABELERS} from '#/lib/constants'
|
import {MAX_LABELERS} from '#/lib/constants'
|
||||||
import {
|
import {GCTIME, STALE} from '#/state/queries'
|
||||||
PERSISTED_QUERY_GCTIME,
|
|
||||||
PERSISTED_QUERY_ROOT,
|
|
||||||
STALE,
|
|
||||||
} from '#/state/queries'
|
|
||||||
import {
|
import {
|
||||||
preferencesQueryKey,
|
preferencesQueryKey,
|
||||||
usePreferencesQuery,
|
usePreferencesQuery,
|
||||||
} from '#/state/queries/preferences'
|
} from '#/state/queries/preferences'
|
||||||
|
import {createQueryKey} from '#/state/queries/util'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
|
|
||||||
const labelerInfoQueryKeyRoot = 'labeler-info'
|
const labelerInfoQueryKeyRoot = 'labeler-info'
|
||||||
@@ -26,11 +23,8 @@ export const labelersInfoQueryKey = (dids: string[]) => [
|
|||||||
dids.slice().sort(),
|
dids.slice().sort(),
|
||||||
]
|
]
|
||||||
|
|
||||||
const persistedLabelersDetailedInfoQueryKey = (dids: string[]) => [
|
const createLabelersDetailedInfoQueryKey = (dids: string[]) =>
|
||||||
PERSISTED_QUERY_ROOT,
|
createQueryKey('labelers-detailed-info', {dids}, {persistedVersion: 1})
|
||||||
'labelers-detailed-info',
|
|
||||||
dids,
|
|
||||||
]
|
|
||||||
|
|
||||||
export function useLabelerInfoQuery({
|
export function useLabelerInfoQuery({
|
||||||
did,
|
did,
|
||||||
@@ -69,8 +63,8 @@ export function useLabelersDetailedInfoQuery({dids}: {dids: string[]}) {
|
|||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
return useQuery({
|
return useQuery({
|
||||||
enabled: !!dids.length,
|
enabled: !!dids.length,
|
||||||
queryKey: persistedLabelersDetailedInfoQueryKey(dids),
|
queryKey: createLabelersDetailedInfoQueryKey(dids),
|
||||||
gcTime: PERSISTED_QUERY_GCTIME,
|
gcTime: GCTIME.INFINITY,
|
||||||
staleTime: STALE.MINUTES.ONE,
|
staleTime: STALE.MINUTES.ONE,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.app.bsky.labeler.getServices({
|
const res = await agent.app.bsky.labeler.getServices({
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
} from 'react'
|
} from 'react'
|
||||||
import {AppState} from 'react-native'
|
import {AppState} from 'react-native'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
import BroadcastChannel from '#/lib/broadcast'
|
import BroadcastChannel from '#/lib/broadcast'
|
||||||
import {resetBadgeCount} from '#/lib/notifications/notifications'
|
import {resetBadgeCount} from '#/lib/notifications/notifications'
|
||||||
|
|||||||
@@ -9,11 +9,7 @@ import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
|||||||
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
||||||
import {replaceEqualDeep} from '#/lib/functions'
|
import {replaceEqualDeep} from '#/lib/functions'
|
||||||
import {getAge} from '#/lib/strings/time'
|
import {getAge} from '#/lib/strings/time'
|
||||||
import {
|
import {GCTIME, STALE} from '#/state/queries'
|
||||||
PERSISTED_QUERY_GCTIME,
|
|
||||||
PERSISTED_QUERY_ROOT,
|
|
||||||
STALE,
|
|
||||||
} from '#/state/queries'
|
|
||||||
import {
|
import {
|
||||||
DEFAULT_HOME_FEED_PREFS,
|
DEFAULT_HOME_FEED_PREFS,
|
||||||
DEFAULT_LOGGED_OUT_PREFERENCES,
|
DEFAULT_LOGGED_OUT_PREFERENCES,
|
||||||
@@ -23,6 +19,7 @@ import {
|
|||||||
type ThreadViewPreferences,
|
type ThreadViewPreferences,
|
||||||
type UsePreferencesQueryResponse,
|
type UsePreferencesQueryResponse,
|
||||||
} from '#/state/queries/preferences/types'
|
} from '#/state/queries/preferences/types'
|
||||||
|
import {createQueryKey} from '#/state/queries/util'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
import {saveLabelers} from '#/state/session/agent-config'
|
import {saveLabelers} from '#/state/session/agent-config'
|
||||||
import {useAgeAssurance} from '#/ageAssurance'
|
import {useAgeAssurance} from '#/ageAssurance'
|
||||||
@@ -33,7 +30,11 @@ export * from '#/state/queries/preferences/const'
|
|||||||
export * from '#/state/queries/preferences/moderation'
|
export * from '#/state/queries/preferences/moderation'
|
||||||
export * from '#/state/queries/preferences/types'
|
export * from '#/state/queries/preferences/types'
|
||||||
|
|
||||||
export const preferencesQueryKey = [PERSISTED_QUERY_ROOT, 'getPreferences']
|
export const preferencesQueryKey = createQueryKey(
|
||||||
|
'getPreferences',
|
||||||
|
{},
|
||||||
|
{persistedVersion: 1},
|
||||||
|
)
|
||||||
|
|
||||||
export function usePreferencesQuery() {
|
export function usePreferencesQuery() {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
@@ -44,7 +45,7 @@ export function usePreferencesQuery() {
|
|||||||
structuralSharing: replaceEqualDeep,
|
structuralSharing: replaceEqualDeep,
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
gcTime: PERSISTED_QUERY_GCTIME,
|
gcTime: GCTIME.INFINITY,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (!agent.did) {
|
if (!agent.did) {
|
||||||
return DEFAULT_LOGGED_OUT_PREFERENCES
|
return DEFAULT_LOGGED_OUT_PREFERENCES
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ export function useProfilesQuery({
|
|||||||
}) {
|
}) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
return useQuery({
|
return useQuery({
|
||||||
|
enabled: handles.length > 0,
|
||||||
staleTime: STALE.MINUTES.FIVE,
|
staleTime: STALE.MINUTES.FIVE,
|
||||||
queryKey: profilesQueryKey(handles),
|
queryKey: profilesQueryKey(handles),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import {AtUri} from '@atproto/api'
|
import {AtUri, type BskyAgent} from '@atproto/api'
|
||||||
import {
|
import {type QueryClient, queryOptions, useQuery} from '@tanstack/react-query'
|
||||||
type QueryClient,
|
|
||||||
useQuery,
|
|
||||||
type UseQueryResult,
|
|
||||||
} from '@tanstack/react-query'
|
|
||||||
|
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
@@ -12,26 +8,12 @@ import {useUnstableProfileViewCache} from './profile'
|
|||||||
const RQKEY_ROOT = 'resolved-did'
|
const RQKEY_ROOT = 'resolved-did'
|
||||||
export const RQKEY = (didOrHandle: string) => [RQKEY_ROOT, didOrHandle]
|
export const RQKEY = (didOrHandle: string) => [RQKEY_ROOT, didOrHandle]
|
||||||
|
|
||||||
type UriUseQueryResult = UseQueryResult<{did: string; uri: string}, Error>
|
const resolvedDidQueryOptions = (
|
||||||
export function useResolveUriQuery(uri: string | undefined): UriUseQueryResult {
|
agent: BskyAgent,
|
||||||
const urip = new AtUri(uri || '')
|
getUnstableProfile: (did: string) => {did: string} | undefined,
|
||||||
const res = useResolveDidQuery(urip.host)
|
didOrHandle: string | undefined,
|
||||||
if (res.data) {
|
) =>
|
||||||
// @ts-expect-error TODO new-sdk-migration
|
queryOptions({
|
||||||
urip.host = res.data
|
|
||||||
return {
|
|
||||||
...res,
|
|
||||||
data: {did: urip.host, uri: urip.toString()},
|
|
||||||
} as UriUseQueryResult
|
|
||||||
}
|
|
||||||
return res as UriUseQueryResult
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useResolveDidQuery(didOrHandle: string | undefined) {
|
|
||||||
const agent = useAgent()
|
|
||||||
const {getUnstableProfile} = useUnstableProfileViewCache()
|
|
||||||
|
|
||||||
return useQuery<string, Error>({
|
|
||||||
staleTime: STALE.HOURS.ONE,
|
staleTime: STALE.HOURS.ONE,
|
||||||
queryKey: RQKEY(didOrHandle ?? ''),
|
queryKey: RQKEY(didOrHandle ?? ''),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@@ -50,6 +32,30 @@ export function useResolveDidQuery(didOrHandle: string | undefined) {
|
|||||||
},
|
},
|
||||||
enabled: !!didOrHandle,
|
enabled: !!didOrHandle,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export function useResolveUriQuery(uri: string | undefined) {
|
||||||
|
const urip = new AtUri(uri || '')
|
||||||
|
const host = urip.host
|
||||||
|
|
||||||
|
const agent = useAgent()
|
||||||
|
const {getUnstableProfile} = useUnstableProfileViewCache()
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
...resolvedDidQueryOptions(agent, getUnstableProfile, host),
|
||||||
|
select: did => ({
|
||||||
|
did,
|
||||||
|
uri: AtUri.make(did, urip.collection, urip.rkey).toString(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useResolveDidQuery(didOrHandle: string | undefined) {
|
||||||
|
const agent = useAgent()
|
||||||
|
const {getUnstableProfile} = useUnstableProfileViewCache()
|
||||||
|
|
||||||
|
return useQuery(
|
||||||
|
resolvedDidQueryOptions(agent, getUnstableProfile, didOrHandle),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function precacheResolvedUri(
|
export function precacheResolvedUri(
|
||||||
|
|||||||
@@ -14,6 +14,61 @@ import {
|
|||||||
|
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
|
export type StructuredQueryKey<T extends Record<string, unknown>> = readonly [
|
||||||
|
string,
|
||||||
|
T,
|
||||||
|
{
|
||||||
|
persistedVersion?: number
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to ensure consistent query keys and key ordering
|
||||||
|
*/
|
||||||
|
export function createQueryKey<T extends Record<string, unknown>>(
|
||||||
|
/**
|
||||||
|
* The query key root. All queries must have a root.
|
||||||
|
*/
|
||||||
|
root: string,
|
||||||
|
/**
|
||||||
|
* Any arguments the query depends on, and if changed, should result in the query being refetched.
|
||||||
|
*/
|
||||||
|
args: T,
|
||||||
|
options: {
|
||||||
|
/**
|
||||||
|
* If provided, this indicates that the query is persisted and the version
|
||||||
|
* of the persisted query format.
|
||||||
|
*
|
||||||
|
* This is used to ensure that when we make breaking changes to the
|
||||||
|
* persisted query format, we can increment the version and avoid trying to
|
||||||
|
* read old persisted queries with the new format.
|
||||||
|
*
|
||||||
|
* If you're persisting your queries, you probably want to set `gcTime:
|
||||||
|
* GCTIME.INFINITY` for this query, otherwise it'll get busted immediately
|
||||||
|
* after being persisted.
|
||||||
|
*/
|
||||||
|
persistedVersion?: number
|
||||||
|
} = {},
|
||||||
|
): StructuredQueryKey<T> {
|
||||||
|
return [root, args, options] as const
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isQueryPersisted(
|
||||||
|
queryKey: QueryKey,
|
||||||
|
): queryKey is StructuredQueryKey<Record<string, unknown>> {
|
||||||
|
return (
|
||||||
|
Array.isArray(queryKey) &&
|
||||||
|
queryKey.length === 3 &&
|
||||||
|
typeof queryKey[0] === 'string' &&
|
||||||
|
typeof queryKey[1] === 'object' &&
|
||||||
|
queryKey[1] !== null &&
|
||||||
|
typeof queryKey[2] === 'object' &&
|
||||||
|
queryKey[2] !== null &&
|
||||||
|
'persistedVersion' in queryKey[2] &&
|
||||||
|
typeof queryKey[2].persistedVersion === 'number'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export async function truncateAndInvalidate<T = any>(
|
export async function truncateAndInvalidate<T = any>(
|
||||||
queryClient: QueryClient,
|
queryClient: QueryClient,
|
||||||
queryKey: QueryKey,
|
queryKey: QueryKey,
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
import {useEffect} from 'react'
|
|
||||||
|
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
|
||||||
import {useDialogStateContext} from '#/state/dialogs'
|
|
||||||
import {useLightbox} from '#/state/lightbox'
|
|
||||||
import {useModals} from '#/state/modals'
|
|
||||||
import {useSession} from '#/state/session'
|
|
||||||
import {useIsDrawerOpen} from '#/state/shell/drawer-open'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Based on {@link https://github.com/jaywcjlove/hotkeys-js/blob/b0038773f3b902574f22af747f3bb003a850f1da/src/index.js#L51C1-L64C2}
|
|
||||||
*/
|
|
||||||
function shouldIgnore(event: KeyboardEvent) {
|
|
||||||
const target: any = event.target || event.srcElement
|
|
||||||
if (!target) return false
|
|
||||||
const {tagName} = target
|
|
||||||
if (!tagName) return false
|
|
||||||
const isInput =
|
|
||||||
tagName === 'INPUT' &&
|
|
||||||
![
|
|
||||||
'checkbox',
|
|
||||||
'radio',
|
|
||||||
'range',
|
|
||||||
'button',
|
|
||||||
'file',
|
|
||||||
'reset',
|
|
||||||
'submit',
|
|
||||||
'color',
|
|
||||||
].includes(target.type)
|
|
||||||
// ignore: isContentEditable === 'true', <input> and <textarea> when readOnly state is false, <select>
|
|
||||||
if (
|
|
||||||
target.isContentEditable ||
|
|
||||||
((isInput || tagName === 'TEXTAREA' || tagName === 'SELECT') &&
|
|
||||||
!target.readOnly)
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useComposerKeyboardShortcut() {
|
|
||||||
const {openComposer} = useOpenComposer()
|
|
||||||
const {openDialogs} = useDialogStateContext()
|
|
||||||
const {isModalActive} = useModals()
|
|
||||||
const {activeLightbox} = useLightbox()
|
|
||||||
const isDrawerOpen = useIsDrawerOpen()
|
|
||||||
const {hasSession} = useSession()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!hasSession) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
function handler(event: KeyboardEvent) {
|
|
||||||
if (shouldIgnore(event)) return
|
|
||||||
if (
|
|
||||||
openDialogs?.current.size > 0 ||
|
|
||||||
isModalActive ||
|
|
||||||
activeLightbox ||
|
|
||||||
isDrawerOpen
|
|
||||||
)
|
|
||||||
return
|
|
||||||
if (event.key === 'n' || event.key === 'N') {
|
|
||||||
openComposer({logContext: 'Other'})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
document.addEventListener('keydown', handler)
|
|
||||||
return () => document.removeEventListener('keydown', handler)
|
|
||||||
}, [
|
|
||||||
openComposer,
|
|
||||||
isModalActive,
|
|
||||||
openDialogs,
|
|
||||||
activeLightbox,
|
|
||||||
isDrawerOpen,
|
|
||||||
hasSession,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import {createContext, useContext, useState} from 'react'
|
import {createContext, useContext, useState} from 'react'
|
||||||
|
|
||||||
|
import {useHotkeysContext} from '#/lib/hotkeys'
|
||||||
|
|
||||||
type StateContext = boolean
|
type StateContext = boolean
|
||||||
type SetContext = (v: boolean) => void
|
type SetContext = (v: boolean) => void
|
||||||
|
|
||||||
@@ -10,10 +12,22 @@ setContext.displayName = 'DrawerOpenSetContext'
|
|||||||
|
|
||||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
const [state, setState] = useState(false)
|
const [state, setState] = useState(false)
|
||||||
|
const {disableScope, enableScope} = useHotkeysContext()
|
||||||
|
|
||||||
|
const setDrawerOpen = (open: boolean) => {
|
||||||
|
if (open) {
|
||||||
|
disableScope('global')
|
||||||
|
} else {
|
||||||
|
enableScope('global')
|
||||||
|
}
|
||||||
|
setState(open)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<stateContext.Provider value={state}>
|
<stateContext.Provider value={state}>
|
||||||
<setContext.Provider value={setState}>{children}</setContext.Provider>
|
<setContext.Provider value={setDrawerOpen}>
|
||||||
|
{children}
|
||||||
|
</setContext.Provider>
|
||||||
</stateContext.Provider>
|
</stateContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export function GifAltTextDialogLoaded({
|
|||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
<Admonition type="tip" style={[a.mt_sm]}>
|
<Admonition type="info" style={[a.mt_sm]}>
|
||||||
<Trans>
|
<Trans>
|
||||||
Alt text describes images for blind and low-vision users, and helps
|
Alt text describes images for blind and low-vision users, and helps
|
||||||
give context to everyone.
|
give context to everyone.
|
||||||
|
|||||||
@@ -120,12 +120,14 @@ const GalleryInner = ({images, containerInfo, dispatch}: GalleryInnerProps) => {
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</View>
|
</View>
|
||||||
<Admonition type="tip" style={[a.mt_sm]}>
|
{images.some(image => !image.alt) && (
|
||||||
|
<Admonition type="info" style={[a.mt_sm]}>
|
||||||
<Trans>
|
<Trans>
|
||||||
Alt text describes images for blind and low-vision users, and helps
|
Alt text describes images for blind and low-vision users, and helps
|
||||||
give context to everyone.
|
give context to everyone.
|
||||||
</Trans>
|
</Trans>
|
||||||
</Admonition>
|
</Admonition>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,21 +8,17 @@ import {
|
|||||||
import {
|
import {
|
||||||
type NativeSyntheticEvent,
|
type NativeSyntheticEvent,
|
||||||
Text as RNText,
|
Text as RNText,
|
||||||
|
TextInput as RNTextInput,
|
||||||
type TextInputSelectionChangeEventData,
|
type TextInputSelectionChangeEventData,
|
||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
|
import {type PasteEventPayload, TextInputWrapper} from 'expo-paste-input'
|
||||||
import {AppBskyRichtextFacet, RichText} from '@atproto/api'
|
import {AppBskyRichtextFacet, RichText} from '@atproto/api'
|
||||||
import PasteInput, {
|
import {useLingui} from '@lingui/react/macro'
|
||||||
type PastedFile,
|
|
||||||
type PasteInputRef,
|
|
||||||
// @ts-expect-error no types when installing from github
|
|
||||||
// eslint-disable-next-line import-x/no-unresolved
|
|
||||||
} from '@mattermost/react-native-paste-input'
|
|
||||||
|
|
||||||
import {POST_IMG_MAX} from '#/lib/constants'
|
import {POST_IMG_MAX} from '#/lib/constants'
|
||||||
import {downloadAndResize} from '#/lib/media/manip'
|
import {downloadAndResize} from '#/lib/media/manip'
|
||||||
import {isUriImage} from '#/lib/media/util'
|
import {isUriImage} from '#/lib/media/util'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
|
||||||
import {getMentionAt, insertMentionAt} from '#/lib/strings/mention-manip'
|
import {getMentionAt, insertMentionAt} from '#/lib/strings/mention-manip'
|
||||||
import {useTheme} from '#/lib/ThemeContext'
|
import {useTheme} from '#/lib/ThemeContext'
|
||||||
import {
|
import {
|
||||||
@@ -51,8 +47,9 @@ export function TextInput({
|
|||||||
onError,
|
onError,
|
||||||
...props
|
...props
|
||||||
}: TextInputProps) {
|
}: TextInputProps) {
|
||||||
|
const {t: l} = useLingui()
|
||||||
const {theme: t, fonts} = useAlf()
|
const {theme: t, fonts} = useAlf()
|
||||||
const textInput = useRef<PasteInputRef>(null)
|
const textInput = useRef<RNTextInput>(null)
|
||||||
const textInputSelection = useRef<Selection>({start: 0, end: 0})
|
const textInputSelection = useRef<Selection>({start: 0, end: 0})
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const [autocompletePrefix, setAutocompletePrefix] = useState('')
|
const [autocompletePrefix, setAutocompletePrefix] = useState('')
|
||||||
@@ -129,19 +126,21 @@ export function TextInput({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const onPaste = useCallback(
|
const onPaste = useCallback(
|
||||||
async (err: string | undefined, files: PastedFile[]) => {
|
(payload: PasteEventPayload) => {
|
||||||
if (err) {
|
if (payload.type === 'unsupported') {
|
||||||
return onError(cleanError(err))
|
onError(l`Unsupported clipboard content`)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const uris = files.map(f => f.uri)
|
if (payload.type === 'images') {
|
||||||
const uri = uris.find(isUriImage)
|
for (const uri of payload.uris) {
|
||||||
|
if (isUriImage(uri)) {
|
||||||
if (uri) {
|
|
||||||
onPhotoPasted(uri)
|
onPhotoPasted(uri)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[onError, onPhotoPasted],
|
[l, onError, onPhotoPasted],
|
||||||
)
|
)
|
||||||
|
|
||||||
const onSelectionChange = useCallback(
|
const onSelectionChange = useCallback(
|
||||||
@@ -217,11 +216,11 @@ export function TextInput({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.flex_1, a.pl_md, hasRightPadding && a.pr_4xl]}>
|
<View style={[a.flex_1, a.pl_md, hasRightPadding && a.pr_4xl]}>
|
||||||
<PasteInput
|
<TextInputWrapper onPaste={onPaste}>
|
||||||
|
<RNTextInput
|
||||||
testID="composerTextInput"
|
testID="composerTextInput"
|
||||||
ref={textInput}
|
ref={textInput}
|
||||||
onChangeText={onChangeText}
|
onChangeText={onChangeText}
|
||||||
onPaste={onPaste}
|
|
||||||
onSelectionChange={onSelectionChange}
|
onSelectionChange={onSelectionChange}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
placeholderTextColor={t.atoms.text_contrast_low.color}
|
placeholderTextColor={t.atoms.text_contrast_low.color}
|
||||||
@@ -251,7 +250,8 @@ export function TextInput({
|
|||||||
props.style,
|
props.style,
|
||||||
]}>
|
]}>
|
||||||
{textDecorated}
|
{textDecorated}
|
||||||
</PasteInput>
|
</RNTextInput>
|
||||||
|
</TextInputWrapper>
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
prefix={autocompletePrefix}
|
prefix={autocompletePrefix}
|
||||||
onSelect={onSelectAutocompleteItem}
|
onSelect={onSelectAutocompleteItem}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
export const textInputWebEmitter = new EventEmitter()
|
export const textInputWebEmitter = new EventEmitter()
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ function LightboxFooter({
|
|||||||
{altText ? (
|
{altText ? (
|
||||||
<View accessibilityRole="button" style={styles.footerText}>
|
<View accessibilityRole="button" style={styles.footerText}>
|
||||||
<Text
|
<Text
|
||||||
style={[s.gray3]}
|
style={{color: colors.gray3}}
|
||||||
numberOfLines={isAltExpanded ? undefined : 3}
|
numberOfLines={isAltExpanded ? undefined : 3}
|
||||||
selectable
|
selectable
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ function ListItem({
|
|||||||
<View style={styles.listItemContent}>
|
<View style={styles.listItemContent}>
|
||||||
<Text
|
<Text
|
||||||
type="lg"
|
type="lg"
|
||||||
style={[s.bold, pal.text]}
|
style={[{fontWeight: '600'}, pal.text]}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
lineHeight={1.2}>
|
lineHeight={1.2}>
|
||||||
{sanitizeDisplayName(list.name)}
|
{sanitizeDisplayName(list.name)}
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ let NotificationFeedItem = ({
|
|||||||
<HeartIconFilled
|
<HeartIconFilled
|
||||||
size="xl"
|
size="xl"
|
||||||
style={[
|
style={[
|
||||||
s.likeColor,
|
{color: t.palette.pink},
|
||||||
// {position: 'relative', top: -4}
|
// {position: 'relative', top: -4}
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import {
|
|||||||
RQKEY,
|
RQKEY,
|
||||||
usePostFeedQuery,
|
usePostFeedQuery,
|
||||||
} from '#/state/queries/post-feed'
|
} from '#/state/queries/post-feed'
|
||||||
|
import {truncateAndInvalidate} from '#/state/queries/util'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useProgressGuide} from '#/state/shell/progress-guide'
|
import {useProgressGuide} from '#/state/shell/progress-guide'
|
||||||
import {useSelectedFeed} from '#/state/shell/selected-feed'
|
import {useSelectedFeed} from '#/state/shell/selected-feed'
|
||||||
@@ -700,13 +701,22 @@ let PostFeed = ({
|
|||||||
})
|
})
|
||||||
setIsPTRing(true)
|
setIsPTRing(true)
|
||||||
try {
|
try {
|
||||||
await refetch()
|
await truncateAndInvalidate(queryClient, RQKEY(feed, feedParams))
|
||||||
onHasNew?.(false)
|
onHasNew?.(false)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Failed to refresh posts feed', {message: err})
|
logger.error('Failed to refresh posts feed', {message: err})
|
||||||
}
|
}
|
||||||
setIsPTRing(false)
|
setIsPTRing(false)
|
||||||
}, [ax, refetch, setIsPTRing, onHasNew, feed, feedType, enabled])
|
}, [
|
||||||
|
ax,
|
||||||
|
queryClient,
|
||||||
|
setIsPTRing,
|
||||||
|
onHasNew,
|
||||||
|
feed,
|
||||||
|
feedParams,
|
||||||
|
feedType,
|
||||||
|
enabled,
|
||||||
|
])
|
||||||
|
|
||||||
const onEndReached = useCallback(async () => {
|
const onEndReached = useCallback(async () => {
|
||||||
if (isFetching || !hasNextPage || isError) return
|
if (isFetching || !hasNextPage || isError) return
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export function PostLoadingPlaceholder({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<View style={[s.flex1]}>
|
<View style={[a.flex_1]}>
|
||||||
<LoadingPlaceholder width={100} height={6} style={{marginBottom: 10}} />
|
<LoadingPlaceholder width={100} height={6} style={{marginBottom: 10}} />
|
||||||
<LoadingPlaceholder width="95%" height={6} style={{marginBottom: 8}} />
|
<LoadingPlaceholder width="95%" height={6} style={{marginBottom: 8}} />
|
||||||
<LoadingPlaceholder width="95%" height={6} style={{marginBottom: 8}} />
|
<LoadingPlaceholder width="95%" height={6} style={{marginBottom: 8}} />
|
||||||
@@ -238,7 +238,7 @@ export function FeedLoadingPlaceholder({
|
|||||||
height={36}
|
height={36}
|
||||||
style={[styles.avatar, {borderRadius: 8}]}
|
style={[styles.avatar, {borderRadius: 8}]}
|
||||||
/>
|
/>
|
||||||
<View style={[s.flex1]}>
|
<View style={[a.flex_1]}>
|
||||||
<LoadingPlaceholder width={100} height={8} style={[s.mt5, s.mb10]} />
|
<LoadingPlaceholder width={100} height={8} style={[s.mt5, s.mb10]} />
|
||||||
<LoadingPlaceholder width={120} height={8} />
|
<LoadingPlaceholder width={120} height={8} />
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
withSpring,
|
withSpring,
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
import EventEmitter from 'eventemitter3'
|
import {EventEmitter} from 'eventemitter3'
|
||||||
|
|
||||||
import {ScrollProvider} from '#/lib/ScrollContext'
|
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||||
import {useMinimalShellMode} from '#/state/shell'
|
import {useMinimalShellMode} from '#/state/shell'
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ function NotifsView() {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View style={s.p10}>
|
<View style={s.p10}>
|
||||||
<View style={s.flexRow}>
|
<View style={{flexDirection: 'row'}}>
|
||||||
<Button onPress={triggerPush} label="Trigger Push" />
|
<Button onPress={triggerPush} label="Trigger Push" />
|
||||||
<Button onPress={triggerToast} label="Trigger Toast" />
|
<Button onPress={triggerToast} label="Trigger Toast" />
|
||||||
<Button onPress={triggerToast2} label="Trigger Toast 2" />
|
<Button onPress={triggerToast2} label="Trigger Toast 2" />
|
||||||
@@ -187,7 +187,7 @@ function PaletteView({palette}: {palette: PaletteColorName}) {
|
|||||||
const defaultPal = usePalette('default')
|
const defaultPal = usePalette('default')
|
||||||
const pal = usePalette(palette)
|
const pal = usePalette(palette)
|
||||||
return (
|
return (
|
||||||
<View style={[pal.view, pal.border, s.p10, s.mb5, s.border1]}>
|
<View style={[pal.view, pal.border, s.p10, s.mb5, {borderWidth: 1}]}>
|
||||||
<Text style={[pal.text]}>{palette} colors</Text>
|
<Text style={[pal.text]}>{palette} colors</Text>
|
||||||
<Text style={[pal.textLight]}>Light text</Text>
|
<Text style={[pal.textLight]}>Light text</Text>
|
||||||
<Text style={[pal.link]}>Link text</Text>
|
<Text style={[pal.link]}>Link text</Text>
|
||||||
@@ -343,15 +343,15 @@ function ButtonsView() {
|
|||||||
const buttonStyles = {marginRight: 5}
|
const buttonStyles = {marginRight: 5}
|
||||||
return (
|
return (
|
||||||
<View style={[defaultPal.view]}>
|
<View style={[defaultPal.view]}>
|
||||||
<View style={[s.flexRow, s.mb5]}>
|
<View style={[{flexDirection: 'row'}, s.mb5]}>
|
||||||
<Button type="primary" label="Primary solid" style={buttonStyles} />
|
<Button type="primary" label="Primary solid" style={buttonStyles} />
|
||||||
<Button type="secondary" label="Secondary solid" style={buttonStyles} />
|
<Button type="secondary" label="Secondary solid" style={buttonStyles} />
|
||||||
</View>
|
</View>
|
||||||
<View style={[s.flexRow, s.mb5]}>
|
<View style={[{flexDirection: 'row'}, s.mb5]}>
|
||||||
<Button type="default" label="Default solid" style={buttonStyles} />
|
<Button type="default" label="Default solid" style={buttonStyles} />
|
||||||
<Button type="inverted" label="Inverted solid" style={buttonStyles} />
|
<Button type="inverted" label="Inverted solid" style={buttonStyles} />
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flexRow}>
|
<View style={{flexDirection: 'row'}}>
|
||||||
<Button
|
<Button
|
||||||
type="primary-outline"
|
type="primary-outline"
|
||||||
label="Primary outline"
|
label="Primary outline"
|
||||||
@@ -363,7 +363,7 @@ function ButtonsView() {
|
|||||||
style={buttonStyles}
|
style={buttonStyles}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flexRow}>
|
<View style={{flexDirection: 'row'}}>
|
||||||
<Button
|
<Button
|
||||||
type="primary-light"
|
type="primary-light"
|
||||||
label="Primary light"
|
label="Primary light"
|
||||||
@@ -375,7 +375,7 @@ function ButtonsView() {
|
|||||||
style={buttonStyles}
|
style={buttonStyles}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={s.flexRow}>
|
<View style={{flexDirection: 'row'}}>
|
||||||
<Button
|
<Button
|
||||||
type="default-light"
|
type="default-light"
|
||||||
label="Default light"
|
label="Default light"
|
||||||
|
|||||||
@@ -400,10 +400,16 @@ function Btn({
|
|||||||
a.rounded_full,
|
a.rounded_full,
|
||||||
{backgroundColor: t.palette.primary_500},
|
{backgroundColor: t.palette.primary_500},
|
||||||
]}>
|
]}>
|
||||||
<Text style={styles.notificationCountLabel}>{notificationCount}</Text>
|
<Text
|
||||||
|
style={styles.notificationCountLabel}
|
||||||
|
maxFontSizeMultiplier={1.5}>
|
||||||
|
{notificationCount}
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
) : hasNew ? (
|
) : hasNew ? (
|
||||||
<View style={[styles.hasNewBadge, a.rounded_full]} />
|
<View
|
||||||
|
style={[styles.hasNewBadge, {backgroundColor: t.palette.primary_500}]}
|
||||||
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</PressableScale>
|
</PressableScale>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {StyleSheet} from 'react-native'
|
import {StyleSheet} from 'react-native'
|
||||||
|
|
||||||
import {colors} from '#/lib/styles'
|
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
@@ -24,8 +23,9 @@ export const styles = StyleSheet.create({
|
|||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: '52%',
|
left: '52%',
|
||||||
top: 8,
|
top: 8,
|
||||||
paddingHorizontal: 4,
|
paddingHorizontal: 5,
|
||||||
paddingBottom: 1,
|
paddingTop: 1,
|
||||||
|
paddingBottom: 2,
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
},
|
},
|
||||||
@@ -37,8 +37,9 @@ export const styles = StyleSheet.create({
|
|||||||
notificationCountLabel: {
|
notificationCountLabel: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: colors.white,
|
color: 'white',
|
||||||
fontVariant: ['tabular-nums'],
|
fontVariant: ['tabular-nums'],
|
||||||
|
includeFontPadding: false,
|
||||||
},
|
},
|
||||||
hasNewBadge: {
|
hasNewBadge: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -47,8 +48,7 @@ export const styles = StyleSheet.create({
|
|||||||
top: 10,
|
top: 10,
|
||||||
width: 8,
|
width: 8,
|
||||||
height: 8,
|
height: 8,
|
||||||
backgroundColor: colors.blue3,
|
borderRadius: 4,
|
||||||
borderRadius: 6,
|
|
||||||
zIndex: 1,
|
zIndex: 1,
|
||||||
},
|
},
|
||||||
ctrlIcon: {
|
ctrlIcon: {
|
||||||
|
|||||||
@@ -313,7 +313,9 @@ const NavItem: React.FC<{
|
|||||||
<Text style={styles.notificationCountLabel}>{notificationCount}</Text>
|
<Text style={styles.notificationCountLabel}>{notificationCount}</Text>
|
||||||
</View>
|
</View>
|
||||||
) : hasNew ? (
|
) : hasNew ? (
|
||||||
<View style={styles.hasNewBadge} />
|
<View
|
||||||
|
style={[styles.hasNewBadge, {backgroundColor: t.palette.primary_500}]}
|
||||||
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -580,7 +580,7 @@ function ComposeBtn() {
|
|||||||
style={[a.rounded_full]}>
|
style={[a.rounded_full]}>
|
||||||
<ButtonIcon icon={EditBig} position="left" />
|
<ButtonIcon icon={EditBig} position="left" />
|
||||||
<ButtonText>
|
<ButtonText>
|
||||||
<Trans context="action">New Post</Trans>
|
<Trans context="action">New post</Trans>
|
||||||
</ButtonText>
|
</ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {View} from 'react-native'
|
|||||||
import {msg} from '@lingui/core/macro'
|
import {msg} from '@lingui/core/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {Trans} from '@lingui/react/macro'
|
import {Trans} from '@lingui/react/macro'
|
||||||
import {useNavigation} from '@react-navigation/core'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from '#/lib/constants'
|
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from '#/lib/constants'
|
||||||
import {useKawaiiMode} from '#/state/preferences/kawaii'
|
import {useKawaiiMode} from '#/state/preferences/kawaii'
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {useIntentHandler} from '#/lib/hooks/useIntentHandler'
|
|||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
|
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
|
||||||
import {useComposerKeyboardShortcut} from '#/state/shell/composer/useComposerKeyboardShortcut'
|
|
||||||
import {useCloseAllActiveElements} from '#/state/util'
|
import {useCloseAllActiveElements} from '#/state/util'
|
||||||
import {Lightbox} from '#/view/com/lightbox/Lightbox'
|
import {Lightbox} from '#/view/com/lightbox/Lightbox'
|
||||||
import {ModalsContainer} from '#/view/com/modals/Modal'
|
import {ModalsContainer} from '#/view/com/modals/Modal'
|
||||||
@@ -36,7 +35,7 @@ import {NoAccessScreen} from '#/ageAssurance/components/NoAccessScreen'
|
|||||||
import {RedirectOverlay} from '#/ageAssurance/components/RedirectOverlay'
|
import {RedirectOverlay} from '#/ageAssurance/components/RedirectOverlay'
|
||||||
import {PassiveAnalytics} from '#/analytics/PassiveAnalytics'
|
import {PassiveAnalytics} from '#/analytics/PassiveAnalytics'
|
||||||
import {FlatNavigator, RoutesContainer} from '#/Navigation'
|
import {FlatNavigator, RoutesContainer} from '#/Navigation'
|
||||||
import {Composer} from './Composer.web'
|
import {Composer} from './Composer'
|
||||||
import {DrawerContent} from './Drawer'
|
import {DrawerContent} from './Drawer'
|
||||||
|
|
||||||
function ShellInner() {
|
function ShellInner() {
|
||||||
@@ -45,7 +44,6 @@ function ShellInner() {
|
|||||||
const {state: policyUpdateState} = usePolicyUpdateContext()
|
const {state: policyUpdateState} = usePolicyUpdateContext()
|
||||||
const welcomeModalControl = useWelcomeModal()
|
const welcomeModalControl = useWelcomeModal()
|
||||||
|
|
||||||
useComposerKeyboardShortcut()
|
|
||||||
useIntentHandler()
|
useIntentHandler()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -20,14 +20,14 @@
|
|||||||
"@jridgewell/gen-mapping" "^0.3.0"
|
"@jridgewell/gen-mapping" "^0.3.0"
|
||||||
"@jridgewell/trace-mapping" "^0.3.9"
|
"@jridgewell/trace-mapping" "^0.3.9"
|
||||||
|
|
||||||
"@atproto/api@^0.19.3":
|
"@atproto/api@^0.19.5":
|
||||||
version "0.19.6"
|
version "0.19.5"
|
||||||
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.19.6.tgz#c8fae3d792fe429c900ac0ba2609d60b9a89e28b"
|
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.19.5.tgz#6388e5d6d3a1693fe04b5f37c705682bac8601d3"
|
||||||
integrity sha512-8L5dZvGaclB52b8msjtgDNx3uLWUY4PELA7KbFyAWBFVasCceE1txdrscCqDCLN+Fff9+Sm07OIjnjHYJXdETA==
|
integrity sha512-u6R5TecYJDO8l8QFN09AMuJASYnUkJ4HhYE5hg4/dha/z14a+OAil2/dli/208uM5AHPFLtlnB8kIK9XU5GgQQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@atproto/common-web" "^0.4.19"
|
"@atproto/common-web" "^0.4.19"
|
||||||
"@atproto/lexicon" "^0.6.2"
|
"@atproto/lexicon" "^0.6.2"
|
||||||
"@atproto/syntax" "^0.5.3"
|
"@atproto/syntax" "^0.5.2"
|
||||||
"@atproto/xrpc" "^0.7.7"
|
"@atproto/xrpc" "^0.7.7"
|
||||||
await-lock "^2.2.2"
|
await-lock "^2.2.2"
|
||||||
multiformats "^9.9.0"
|
multiformats "^9.9.0"
|
||||||
@@ -73,20 +73,13 @@
|
|||||||
multiformats "^9.9.0"
|
multiformats "^9.9.0"
|
||||||
zod "^3.23.8"
|
zod "^3.23.8"
|
||||||
|
|
||||||
"@atproto/syntax@^0.5.0", "@atproto/syntax@^0.5.1":
|
"@atproto/syntax@^0.5.0", "@atproto/syntax@^0.5.1", "@atproto/syntax@^0.5.2":
|
||||||
version "0.5.2"
|
version "0.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/@atproto/syntax/-/syntax-0.5.2.tgz#d4b32c9feb421ceeb5ade1fa80bc42764d51e52e"
|
resolved "https://registry.yarnpkg.com/@atproto/syntax/-/syntax-0.5.2.tgz#d4b32c9feb421ceeb5ade1fa80bc42764d51e52e"
|
||||||
integrity sha512-W41szOnkppoHr0iCUrzL8gy3OD6qmDyp1UvUgmTx2oFQfgbudpz51T/gznesiCcqiUT5obfHdx4PJ+WdlEOE7Q==
|
integrity sha512-W41szOnkppoHr0iCUrzL8gy3OD6qmDyp1UvUgmTx2oFQfgbudpz51T/gznesiCcqiUT5obfHdx4PJ+WdlEOE7Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.8.1"
|
tslib "^2.8.1"
|
||||||
|
|
||||||
"@atproto/syntax@^0.5.3":
|
|
||||||
version "0.5.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/@atproto/syntax/-/syntax-0.5.3.tgz#4331d01f63fe56c374dcf95d4432a22b62271a17"
|
|
||||||
integrity sha512-gzhlHOJHm5KXdCc17fXi1fXM81ccs5jJfNgCui84ay9JGvczxegpYHNqdMlv+iBuhtBzFIjgx6ChjRxN/kO8kQ==
|
|
||||||
dependencies:
|
|
||||||
tslib "^2.8.1"
|
|
||||||
|
|
||||||
"@atproto/xrpc@^0.7.7":
|
"@atproto/xrpc@^0.7.7":
|
||||||
version "0.7.7"
|
version "0.7.7"
|
||||||
resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.7.7.tgz#c0e3106c854cb9bc7d3129de2f31b8256eb0ed11"
|
resolved "https://registry.yarnpkg.com/@atproto/xrpc/-/xrpc-0.7.7.tgz#c0e3106c854cb9bc7d3129de2f31b8256eb0ed11"
|
||||||
@@ -304,15 +297,6 @@
|
|||||||
json5 "^2.2.3"
|
json5 "^2.2.3"
|
||||||
semver "^6.3.1"
|
semver "^6.3.1"
|
||||||
|
|
||||||
"@babel/eslint-parser@^7.25.1":
|
|
||||||
version "7.28.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.28.6.tgz#6a294a4add732ebe7ded8a8d2792dd03dd81dc3f"
|
|
||||||
integrity sha512-QGmsKi2PBO/MHSQk+AAgA9R6OHQr+VqnniFE0eMWZcVcfBZoA2dKn2hUsl3Csg/Plt9opRUWdY7//VXsrIlEiA==
|
|
||||||
dependencies:
|
|
||||||
"@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1"
|
|
||||||
eslint-visitor-keys "^2.1.0"
|
|
||||||
semver "^6.3.1"
|
|
||||||
|
|
||||||
"@babel/generator@^7.20.5":
|
"@babel/generator@^7.20.5":
|
||||||
version "7.23.6"
|
version "7.23.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e"
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e"
|
||||||
@@ -2622,14 +2606,14 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5"
|
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5"
|
||||||
integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==
|
integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==
|
||||||
|
|
||||||
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0", "@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1":
|
"@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1":
|
||||||
version "4.9.1"
|
version "4.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595"
|
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595"
|
||||||
integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==
|
integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint-visitor-keys "^3.4.3"
|
eslint-visitor-keys "^3.4.3"
|
||||||
|
|
||||||
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.12.2":
|
"@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.12.2":
|
||||||
version "4.12.2"
|
version "4.12.2"
|
||||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b"
|
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b"
|
||||||
integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==
|
integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==
|
||||||
@@ -3920,12 +3904,6 @@
|
|||||||
"@babel/runtime" "^7.20.13"
|
"@babel/runtime" "^7.20.13"
|
||||||
"@lingui/core" "5.9.2"
|
"@lingui/core" "5.9.2"
|
||||||
|
|
||||||
"@mattermost/react-native-paste-input@mattermost/react-native-paste-input":
|
|
||||||
version "0.8.1"
|
|
||||||
resolved "https://codeload.github.com/mattermost/react-native-paste-input/tar.gz/f260447edc645a817ab1ba7b46d8341d84dba8e9"
|
|
||||||
dependencies:
|
|
||||||
semver "7.6.3"
|
|
||||||
|
|
||||||
"@messageformat/parser@^5.0.0":
|
"@messageformat/parser@^5.0.0":
|
||||||
version "5.1.0"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@messageformat/parser/-/parser-5.1.0.tgz#05e4851c782d633ad735791dd0a68ee65d2a7201"
|
resolved "https://registry.yarnpkg.com/@messageformat/parser/-/parser-5.1.0.tgz#05e4851c782d633ad735791dd0a68ee65d2a7201"
|
||||||
@@ -3955,13 +3933,6 @@
|
|||||||
"@emnapi/runtime" "^1.4.3"
|
"@emnapi/runtime" "^1.4.3"
|
||||||
"@tybys/wasm-util" "^0.10.0"
|
"@tybys/wasm-util" "^0.10.0"
|
||||||
|
|
||||||
"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1":
|
|
||||||
version "5.1.1-v1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129"
|
|
||||||
integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==
|
|
||||||
dependencies:
|
|
||||||
eslint-scope "5.1.1"
|
|
||||||
|
|
||||||
"@nodelib/fs.scandir@2.1.5":
|
"@nodelib/fs.scandir@2.1.5":
|
||||||
version "2.1.5"
|
version "2.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||||
@@ -4800,29 +4771,6 @@
|
|||||||
serve-static "^1.16.2"
|
serve-static "^1.16.2"
|
||||||
ws "^6.2.3"
|
ws "^6.2.3"
|
||||||
|
|
||||||
"@react-native/eslint-config@^0.81.5":
|
|
||||||
version "0.81.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@react-native/eslint-config/-/eslint-config-0.81.6.tgz#6911df60f250f6462b3b7361190d276bb09c0432"
|
|
||||||
integrity sha512-Uur91Ss9L8W7omBAqnNe80GNUNn5qQXYuP0xmiKmytGk0ttG9QkcOma4aS4nR3m8O7v0kFA7U3+AD5an526Jsg==
|
|
||||||
dependencies:
|
|
||||||
"@babel/core" "^7.25.2"
|
|
||||||
"@babel/eslint-parser" "^7.25.1"
|
|
||||||
"@react-native/eslint-plugin" "0.81.6"
|
|
||||||
"@typescript-eslint/eslint-plugin" "^7.1.1"
|
|
||||||
"@typescript-eslint/parser" "^7.1.1"
|
|
||||||
eslint-config-prettier "^8.5.0"
|
|
||||||
eslint-plugin-eslint-comments "^3.2.0"
|
|
||||||
eslint-plugin-ft-flow "^2.0.1"
|
|
||||||
eslint-plugin-jest "^27.9.0"
|
|
||||||
eslint-plugin-react "^7.30.1"
|
|
||||||
eslint-plugin-react-hooks "^5.2.0"
|
|
||||||
eslint-plugin-react-native "^4.0.0"
|
|
||||||
|
|
||||||
"@react-native/eslint-plugin@0.81.6":
|
|
||||||
version "0.81.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/@react-native/eslint-plugin/-/eslint-plugin-0.81.6.tgz#9c3831a1a3a1204f016ce53b68e99e9269c0115f"
|
|
||||||
integrity sha512-2wLmnq6l2dualDoAj42P4miwReXt5i7rad31zenhYFBSUNt849y2sroP2I6Yjh0r+UqBdDlf6QN2W+Pdmi6pJw==
|
|
||||||
|
|
||||||
"@react-native/gradle-plugin@0.81.5":
|
"@react-native/gradle-plugin@0.81.5":
|
||||||
version "0.81.5"
|
version "0.81.5"
|
||||||
resolved "https://registry.yarnpkg.com/@react-native/gradle-plugin/-/gradle-plugin-0.81.5.tgz#a58830f38789f6254b64449a17fe57455b589d00"
|
resolved "https://registry.yarnpkg.com/@react-native/gradle-plugin/-/gradle-plugin-0.81.5.tgz#a58830f38789f6254b64449a17fe57455b589d00"
|
||||||
@@ -5164,7 +5112,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@sinonjs/commons" "^3.0.0"
|
"@sinonjs/commons" "^3.0.0"
|
||||||
|
|
||||||
"@tanstack/query-async-storage-persister@^5.25.0":
|
"@tanstack/query-async-storage-persister@^5.96.2":
|
||||||
version "5.96.2"
|
version "5.96.2"
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/query-async-storage-persister/-/query-async-storage-persister-5.96.2.tgz#29423b35f2d8c5f63afbf72475baa7799ffaf022"
|
resolved "https://registry.yarnpkg.com/@tanstack/query-async-storage-persister/-/query-async-storage-persister-5.96.2.tgz#29423b35f2d8c5f63afbf72475baa7799ffaf022"
|
||||||
integrity sha512-lYJm+TwzOEUVkxCJapLSzRXPzmPpv7Vy3zSB1RXYQ6+vznEgXBqLjn+ZwBRvHpkRda9VXis64wv44rPIi9nCwg==
|
integrity sha512-lYJm+TwzOEUVkxCJapLSzRXPzmPpv7Vy3zSB1RXYQ6+vznEgXBqLjn+ZwBRvHpkRda9VXis64wv44rPIi9nCwg==
|
||||||
@@ -5172,11 +5120,6 @@
|
|||||||
"@tanstack/query-core" "5.96.2"
|
"@tanstack/query-core" "5.96.2"
|
||||||
"@tanstack/query-persist-client-core" "5.96.2"
|
"@tanstack/query-persist-client-core" "5.96.2"
|
||||||
|
|
||||||
"@tanstack/query-core@5.25.0":
|
|
||||||
version "5.25.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.25.0.tgz#e08ed0a9fad34c8005d1a282e57280031ac50cdc"
|
|
||||||
integrity sha512-vlobHP64HTuSE68lWF1mEhwSRC5Q7gaT+a/m9S+ItuN+ruSOxe1rFnR9j0ACWQ314BPhBEVKfBQ6mHL0OWfdbQ==
|
|
||||||
|
|
||||||
"@tanstack/query-core@5.96.2":
|
"@tanstack/query-core@5.96.2":
|
||||||
version "5.96.2"
|
version "5.96.2"
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.96.2.tgz#766dab253476afd0b27959b66abb606d8d2dd9f5"
|
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.96.2.tgz#766dab253476afd0b27959b66abb606d8d2dd9f5"
|
||||||
@@ -5189,19 +5132,19 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@tanstack/query-core" "5.96.2"
|
"@tanstack/query-core" "5.96.2"
|
||||||
|
|
||||||
"@tanstack/react-query-persist-client@^5.25.0":
|
"@tanstack/react-query-persist-client@^5.96.2":
|
||||||
version "5.96.2"
|
version "5.96.2"
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query-persist-client/-/react-query-persist-client-5.96.2.tgz#b47d62fc990a9fd38ddcf4a080d1300ae887e5a0"
|
resolved "https://registry.yarnpkg.com/@tanstack/react-query-persist-client/-/react-query-persist-client-5.96.2.tgz#b47d62fc990a9fd38ddcf4a080d1300ae887e5a0"
|
||||||
integrity sha512-smQ38oVPlnvkG+G7R60IAD9X6azJLRjHEd7twml9XBLYM31ncPDP0tUKy/Gv/4ItVmKTtjZ5VabXpVZxnaWSww==
|
integrity sha512-smQ38oVPlnvkG+G7R60IAD9X6azJLRjHEd7twml9XBLYM31ncPDP0tUKy/Gv/4ItVmKTtjZ5VabXpVZxnaWSww==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@tanstack/query-persist-client-core" "5.96.2"
|
"@tanstack/query-persist-client-core" "5.96.2"
|
||||||
|
|
||||||
"@tanstack/react-query@5.25.0":
|
"@tanstack/react-query@^5.96.2":
|
||||||
version "5.25.0"
|
version "5.96.2"
|
||||||
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.25.0.tgz#f4dac794cf10dd956aa56dbbdf67049a5ba2669d"
|
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.96.2.tgz#a164abfb80eb5e7772bbcddfa7240f3fd8d0d7be"
|
||||||
integrity sha512-u+n5R7mLO7RmeiIonpaCRVXNRWtZEef/aVZ/XGWRPa7trBIvGtzlfo0Ah7ZtnTYfrKEVwnZ/tzRCBcoiqJ/tFw==
|
integrity sha512-sYyzzJT4G0g02azzJ8o55VFFV31XvFpdUpG+unxS0vSaYsJnSPKGoI6WdPwUucJL1wpgGfwfmntNX/Ub1uOViA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@tanstack/query-core" "5.25.0"
|
"@tanstack/query-core" "5.96.2"
|
||||||
|
|
||||||
"@testing-library/react-native@^13.2.0":
|
"@testing-library/react-native@^13.2.0":
|
||||||
version "13.2.0"
|
version "13.2.0"
|
||||||
@@ -5615,11 +5558,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
|
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
|
||||||
integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==
|
integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==
|
||||||
|
|
||||||
"@types/semver@^7.3.12":
|
|
||||||
version "7.7.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.7.1.tgz#3ce3af1a5524ef327d2da9e4fd8b6d95c8d70528"
|
|
||||||
integrity sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==
|
|
||||||
|
|
||||||
"@types/send@*":
|
"@types/send@*":
|
||||||
version "0.17.1"
|
version "0.17.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301"
|
resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.1.tgz#ed4932b8a2a805f1fe362a70f4e62d0ac994e301"
|
||||||
@@ -5699,21 +5637,6 @@
|
|||||||
natural-compare "^1.4.0"
|
natural-compare "^1.4.0"
|
||||||
ts-api-utils "^2.5.0"
|
ts-api-utils "^2.5.0"
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^7.1.1":
|
|
||||||
version "7.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3"
|
|
||||||
integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==
|
|
||||||
dependencies:
|
|
||||||
"@eslint-community/regexpp" "^4.10.0"
|
|
||||||
"@typescript-eslint/scope-manager" "7.18.0"
|
|
||||||
"@typescript-eslint/type-utils" "7.18.0"
|
|
||||||
"@typescript-eslint/utils" "7.18.0"
|
|
||||||
"@typescript-eslint/visitor-keys" "7.18.0"
|
|
||||||
graphemer "^1.4.0"
|
|
||||||
ignore "^5.3.1"
|
|
||||||
natural-compare "^1.4.0"
|
|
||||||
ts-api-utils "^1.3.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/parser@8.58.0":
|
"@typescript-eslint/parser@8.58.0":
|
||||||
version "8.58.0"
|
version "8.58.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.58.0.tgz#da04ece1967b6c2fe8f10c3473dabf3825795ef7"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.58.0.tgz#da04ece1967b6c2fe8f10c3473dabf3825795ef7"
|
||||||
@@ -5725,17 +5648,6 @@
|
|||||||
"@typescript-eslint/visitor-keys" "8.58.0"
|
"@typescript-eslint/visitor-keys" "8.58.0"
|
||||||
debug "^4.4.3"
|
debug "^4.4.3"
|
||||||
|
|
||||||
"@typescript-eslint/parser@^7.1.1":
|
|
||||||
version "7.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.18.0.tgz#83928d0f1b7f4afa974098c64b5ce6f9051f96a0"
|
|
||||||
integrity sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/scope-manager" "7.18.0"
|
|
||||||
"@typescript-eslint/types" "7.18.0"
|
|
||||||
"@typescript-eslint/typescript-estree" "7.18.0"
|
|
||||||
"@typescript-eslint/visitor-keys" "7.18.0"
|
|
||||||
debug "^4.3.4"
|
|
||||||
|
|
||||||
"@typescript-eslint/project-service@8.58.0":
|
"@typescript-eslint/project-service@8.58.0":
|
||||||
version "8.58.0"
|
version "8.58.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.58.0.tgz#66ceda0aabf7427aec3e2713fa43eb278dead2aa"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.58.0.tgz#66ceda0aabf7427aec3e2713fa43eb278dead2aa"
|
||||||
@@ -5745,22 +5657,6 @@
|
|||||||
"@typescript-eslint/types" "^8.58.0"
|
"@typescript-eslint/types" "^8.58.0"
|
||||||
debug "^4.4.3"
|
debug "^4.4.3"
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@5.62.0":
|
|
||||||
version "5.62.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c"
|
|
||||||
integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types" "5.62.0"
|
|
||||||
"@typescript-eslint/visitor-keys" "5.62.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@7.18.0":
|
|
||||||
version "7.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83"
|
|
||||||
integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types" "7.18.0"
|
|
||||||
"@typescript-eslint/visitor-keys" "7.18.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@8.58.0":
|
"@typescript-eslint/scope-manager@8.58.0":
|
||||||
version "8.58.0"
|
version "8.58.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz#e304142775e49a1b7ac3c8bf2536714447c72cab"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz#e304142775e49a1b7ac3c8bf2536714447c72cab"
|
||||||
@@ -5774,16 +5670,6 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz#c5a8edb21f31e0fdee565724e1b984171c559482"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz#c5a8edb21f31e0fdee565724e1b984171c559482"
|
||||||
integrity sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==
|
integrity sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@7.18.0":
|
|
||||||
version "7.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b"
|
|
||||||
integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/typescript-estree" "7.18.0"
|
|
||||||
"@typescript-eslint/utils" "7.18.0"
|
|
||||||
debug "^4.3.4"
|
|
||||||
ts-api-utils "^1.3.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@8.58.0":
|
"@typescript-eslint/type-utils@8.58.0":
|
||||||
version "8.58.0"
|
version "8.58.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz#ce0e72cd967ffbbe8de322db6089bd4374be352f"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz#ce0e72cd967ffbbe8de322db6089bd4374be352f"
|
||||||
@@ -5795,48 +5681,11 @@
|
|||||||
debug "^4.4.3"
|
debug "^4.4.3"
|
||||||
ts-api-utils "^2.5.0"
|
ts-api-utils "^2.5.0"
|
||||||
|
|
||||||
"@typescript-eslint/types@5.62.0":
|
|
||||||
version "5.62.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
|
|
||||||
integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
|
|
||||||
|
|
||||||
"@typescript-eslint/types@7.18.0":
|
|
||||||
version "7.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9"
|
|
||||||
integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==
|
|
||||||
|
|
||||||
"@typescript-eslint/types@8.58.0", "@typescript-eslint/types@^8.56.0", "@typescript-eslint/types@^8.58.0":
|
"@typescript-eslint/types@8.58.0", "@typescript-eslint/types@^8.56.0", "@typescript-eslint/types@^8.58.0":
|
||||||
version "8.58.0"
|
version "8.58.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.58.0.tgz#e94ae7abdc1c6530e71183c1007b61fa93112a5a"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.58.0.tgz#e94ae7abdc1c6530e71183c1007b61fa93112a5a"
|
||||||
integrity sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==
|
integrity sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@5.62.0":
|
|
||||||
version "5.62.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
|
|
||||||
integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types" "5.62.0"
|
|
||||||
"@typescript-eslint/visitor-keys" "5.62.0"
|
|
||||||
debug "^4.3.4"
|
|
||||||
globby "^11.1.0"
|
|
||||||
is-glob "^4.0.3"
|
|
||||||
semver "^7.3.7"
|
|
||||||
tsutils "^3.21.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@7.18.0":
|
|
||||||
version "7.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931"
|
|
||||||
integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types" "7.18.0"
|
|
||||||
"@typescript-eslint/visitor-keys" "7.18.0"
|
|
||||||
debug "^4.3.4"
|
|
||||||
globby "^11.1.0"
|
|
||||||
is-glob "^4.0.3"
|
|
||||||
minimatch "^9.0.4"
|
|
||||||
semver "^7.6.0"
|
|
||||||
ts-api-utils "^1.3.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@8.58.0":
|
"@typescript-eslint/typescript-estree@8.58.0":
|
||||||
version "8.58.0"
|
version "8.58.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz#ed233faa8e2f2a2e1357c3e7d553d6465a0ee59a"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz#ed233faa8e2f2a2e1357c3e7d553d6465a0ee59a"
|
||||||
@@ -5852,17 +5701,7 @@
|
|||||||
tinyglobby "^0.2.15"
|
tinyglobby "^0.2.15"
|
||||||
ts-api-utils "^2.5.0"
|
ts-api-utils "^2.5.0"
|
||||||
|
|
||||||
"@typescript-eslint/utils@7.18.0":
|
"@typescript-eslint/utils@8.58.0", "@typescript-eslint/utils@^8.57.2":
|
||||||
version "7.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f"
|
|
||||||
integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==
|
|
||||||
dependencies:
|
|
||||||
"@eslint-community/eslint-utils" "^4.4.0"
|
|
||||||
"@typescript-eslint/scope-manager" "7.18.0"
|
|
||||||
"@typescript-eslint/types" "7.18.0"
|
|
||||||
"@typescript-eslint/typescript-estree" "7.18.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/utils@8.58.0", "@typescript-eslint/utils@^8.0.0":
|
|
||||||
version "8.58.0"
|
version "8.58.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.58.0.tgz#21a74a7963b0d288b719a4121c7dd555adaab3c3"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.58.0.tgz#21a74a7963b0d288b719a4121c7dd555adaab3c3"
|
||||||
integrity sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==
|
integrity sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==
|
||||||
@@ -5872,36 +5711,6 @@
|
|||||||
"@typescript-eslint/types" "8.58.0"
|
"@typescript-eslint/types" "8.58.0"
|
||||||
"@typescript-eslint/typescript-estree" "8.58.0"
|
"@typescript-eslint/typescript-estree" "8.58.0"
|
||||||
|
|
||||||
"@typescript-eslint/utils@^5.10.0":
|
|
||||||
version "5.62.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86"
|
|
||||||
integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==
|
|
||||||
dependencies:
|
|
||||||
"@eslint-community/eslint-utils" "^4.2.0"
|
|
||||||
"@types/json-schema" "^7.0.9"
|
|
||||||
"@types/semver" "^7.3.12"
|
|
||||||
"@typescript-eslint/scope-manager" "5.62.0"
|
|
||||||
"@typescript-eslint/types" "5.62.0"
|
|
||||||
"@typescript-eslint/typescript-estree" "5.62.0"
|
|
||||||
eslint-scope "^5.1.1"
|
|
||||||
semver "^7.3.7"
|
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@5.62.0":
|
|
||||||
version "5.62.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e"
|
|
||||||
integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types" "5.62.0"
|
|
||||||
eslint-visitor-keys "^3.3.0"
|
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@7.18.0":
|
|
||||||
version "7.18.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7"
|
|
||||||
integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/types" "7.18.0"
|
|
||||||
eslint-visitor-keys "^3.4.3"
|
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@8.58.0":
|
"@typescript-eslint/visitor-keys@8.58.0":
|
||||||
version "8.58.0"
|
version "8.58.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz#2abd55a4be70fd55967aceaba4330b9ba9f45189"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz#2abd55a4be70fd55967aceaba4330b9ba9f45189"
|
||||||
@@ -6486,11 +6295,6 @@ array-union@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
array-uniq "^1.0.1"
|
array-uniq "^1.0.1"
|
||||||
|
|
||||||
array-union@^2.1.0:
|
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
|
|
||||||
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
|
|
||||||
|
|
||||||
array-union@^3.0.1:
|
array-union@^3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-3.0.1.tgz#da52630d327f8b88cfbfb57728e2af5cd9b6b975"
|
resolved "https://registry.yarnpkg.com/array-union/-/array-union-3.0.1.tgz#da52630d327f8b88cfbfb57728e2af5cd9b6b975"
|
||||||
@@ -8739,11 +8543,6 @@ escodegen@^2.0.0:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
source-map "~0.6.1"
|
source-map "~0.6.1"
|
||||||
|
|
||||||
eslint-config-prettier@^8.5.0:
|
|
||||||
version "8.10.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.2.tgz#0642e53625ebc62c31c24726b0f050df6bd97a2e"
|
|
||||||
integrity sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==
|
|
||||||
|
|
||||||
eslint-import-context@^0.1.8, eslint-import-context@^0.1.9:
|
eslint-import-context@^0.1.8, eslint-import-context@^0.1.9:
|
||||||
version "0.1.9"
|
version "0.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-import-context/-/eslint-import-context-0.1.9.tgz#967b0b2f0a90ef4b689125e088f790f0b7756dbe"
|
resolved "https://registry.yarnpkg.com/eslint-import-context/-/eslint-import-context-0.1.9.tgz#967b0b2f0a90ef4b689125e088f790f0b7756dbe"
|
||||||
@@ -8769,23 +8568,7 @@ eslint-import-resolver-typescript@^4.4.4:
|
|||||||
version "0.0.0"
|
version "0.0.0"
|
||||||
uid ""
|
uid ""
|
||||||
|
|
||||||
eslint-plugin-eslint-comments@^3.2.0:
|
eslint-plugin-import-x@^4.16.2:
|
||||||
version "3.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa"
|
|
||||||
integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==
|
|
||||||
dependencies:
|
|
||||||
escape-string-regexp "^1.0.5"
|
|
||||||
ignore "^5.0.5"
|
|
||||||
|
|
||||||
eslint-plugin-ft-flow@^2.0.1:
|
|
||||||
version "2.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-ft-flow/-/eslint-plugin-ft-flow-2.0.3.tgz#3b3c113c41902bcbacf0e22b536debcfc3c819e8"
|
|
||||||
integrity sha512-Vbsd/b+LYA99jUbsL6viEUWShFaYQt2YQs3QN3f+aeszOhh2sgdcU0mjzDyD4yyBvMc8qy2uwvBBWfMzEX06tg==
|
|
||||||
dependencies:
|
|
||||||
lodash "^4.17.21"
|
|
||||||
string-natural-compare "^3.0.1"
|
|
||||||
|
|
||||||
eslint-plugin-import-x@^4.16.1:
|
|
||||||
version "4.16.2"
|
version "4.16.2"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import-x/-/eslint-plugin-import-x-4.16.2.tgz#95d1f798795566712c87897317ef8433d101db29"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-import-x/-/eslint-plugin-import-x-4.16.2.tgz#95d1f798795566712c87897317ef8433d101db29"
|
||||||
integrity sha512-rM9K8UBHcWKpzQzStn1YRN2T5NvdeIfSVoKu/lKF41znQXHAUcBbYXe5wd6GNjZjTrP7viQ49n1D83x/2gYgIw==
|
integrity sha512-rM9K8UBHcWKpzQzStn1YRN2T5NvdeIfSVoKu/lKF41znQXHAUcBbYXe5wd6GNjZjTrP7viQ49n1D83x/2gYgIw==
|
||||||
@@ -8801,20 +8584,13 @@ eslint-plugin-import-x@^4.16.1:
|
|||||||
stable-hash-x "^0.2.0"
|
stable-hash-x "^0.2.0"
|
||||||
unrs-resolver "^1.9.2"
|
unrs-resolver "^1.9.2"
|
||||||
|
|
||||||
eslint-plugin-jest@^27.9.0:
|
eslint-plugin-lingui@^0.12.0:
|
||||||
version "27.9.0"
|
version "0.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz#7c98a33605e1d8b8442ace092b60e9919730000b"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-lingui/-/eslint-plugin-lingui-0.12.0.tgz#fca175ad3ed40538483bfcd50c091851fefc3e8b"
|
||||||
integrity sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==
|
integrity sha512-2+9P3thudGIBI10sDWYUIrGs3HIP09gv0XF98RDzZs34GAsAsGTUoSgrttKS1knAU5dwbrFKhNKu2LMrjRECag==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/utils" "^5.10.0"
|
"@typescript-eslint/utils" "^8.57.2"
|
||||||
|
micromatch "^4.0.8"
|
||||||
eslint-plugin-lingui@^0.11.0:
|
|
||||||
version "0.11.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-lingui/-/eslint-plugin-lingui-0.11.0.tgz#e33a4fe83698bb4cdfbfa816391fb79b68e6c026"
|
|
||||||
integrity sha512-O2Ixoapt5fa4VKZJgXhVwb6BHnzByIUDNMfZOhHWGMYk40GfGCho4MUfspLVrHAFLimgBPKXtCcJ8GC4YNZmfg==
|
|
||||||
dependencies:
|
|
||||||
"@typescript-eslint/utils" "^8.0.0"
|
|
||||||
micromatch "^4.0.0"
|
|
||||||
|
|
||||||
eslint-plugin-react-compiler@^19.1.0-rc.2:
|
eslint-plugin-react-compiler@^19.1.0-rc.2:
|
||||||
version "19.1.0-rc.2"
|
version "19.1.0-rc.2"
|
||||||
@@ -8828,11 +8604,6 @@ eslint-plugin-react-compiler@^19.1.0-rc.2:
|
|||||||
zod "^3.22.4"
|
zod "^3.22.4"
|
||||||
zod-validation-error "^3.0.3"
|
zod-validation-error "^3.0.3"
|
||||||
|
|
||||||
eslint-plugin-react-hooks@^5.2.0:
|
|
||||||
version "5.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3"
|
|
||||||
integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==
|
|
||||||
|
|
||||||
eslint-plugin-react-hooks@^7.0.1:
|
eslint-plugin-react-hooks@^7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz#66e258db58ece50723ef20cc159f8aa908219169"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz#66e258db58ece50723ef20cc159f8aa908219169"
|
||||||
@@ -8858,13 +8629,6 @@ eslint-plugin-react-native-globals@^0.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2"
|
||||||
integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==
|
integrity sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==
|
||||||
|
|
||||||
eslint-plugin-react-native@^4.0.0:
|
|
||||||
version "4.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-4.1.0.tgz#5343acd3b2246bc1b857ac38be708f070d18809f"
|
|
||||||
integrity sha512-QLo7rzTBOl43FvVqDdq5Ql9IoElIuTdjrz9SKAXCvULvBoRZ44JGSkx9z4999ZusCsb4rK3gjS8gOGyeYqZv2Q==
|
|
||||||
dependencies:
|
|
||||||
eslint-plugin-react-native-globals "^0.1.1"
|
|
||||||
|
|
||||||
eslint-plugin-react-native@^5.0.0:
|
eslint-plugin-react-native@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-5.0.0.tgz#2ee990ba4967c557183b31121578547fb5c02d5d"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-native/-/eslint-plugin-react-native-5.0.0.tgz#2ee990ba4967c557183b31121578547fb5c02d5d"
|
||||||
@@ -8872,7 +8636,7 @@ eslint-plugin-react-native@^5.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
eslint-plugin-react-native-globals "^0.1.1"
|
eslint-plugin-react-native-globals "^0.1.1"
|
||||||
|
|
||||||
eslint-plugin-react@^7.30.1, eslint-plugin-react@^7.37.5:
|
eslint-plugin-react@^7.37.5:
|
||||||
version "7.37.5"
|
version "7.37.5"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065"
|
||||||
integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==
|
integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==
|
||||||
@@ -8901,7 +8665,7 @@ eslint-plugin-simple-import-sort@^12.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz#e64bfdaf91c5b98a298619aa634a9f7aa43b709e"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.1.tgz#e64bfdaf91c5b98a298619aa634a9f7aa43b709e"
|
||||||
integrity sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==
|
integrity sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==
|
||||||
|
|
||||||
eslint-scope@5.1.1, eslint-scope@^5.1.1:
|
eslint-scope@5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
||||||
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
|
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
|
||||||
@@ -8917,12 +8681,7 @@ eslint-scope@^8.4.0:
|
|||||||
esrecurse "^4.3.0"
|
esrecurse "^4.3.0"
|
||||||
estraverse "^5.2.0"
|
estraverse "^5.2.0"
|
||||||
|
|
||||||
eslint-visitor-keys@^2.1.0:
|
eslint-visitor-keys@^3.4.3:
|
||||||
version "2.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
|
|
||||||
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
|
|
||||||
|
|
||||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3:
|
|
||||||
version "3.4.3"
|
version "3.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
||||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||||
@@ -9332,6 +9091,11 @@ expo-notifications@~0.32.16:
|
|||||||
expo-application "~7.0.8"
|
expo-application "~7.0.8"
|
||||||
expo-constants "~18.0.13"
|
expo-constants "~18.0.13"
|
||||||
|
|
||||||
|
expo-paste-input@^0.1.12:
|
||||||
|
version "0.1.12"
|
||||||
|
resolved "https://registry.yarnpkg.com/expo-paste-input/-/expo-paste-input-0.1.12.tgz#0295eb26caf738fc39019f4ecae48c22b126b67e"
|
||||||
|
integrity sha512-iaOCgygmCYVbSj+gJOxr8P28y8Tf0X4UHtVVXRjEsARKf5gQUoVaRX63uzB+8h+g6vN710fSmu5vdxNP28bw8g==
|
||||||
|
|
||||||
expo-privacy-sensitive@^0.1.0:
|
expo-privacy-sensitive@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/expo-privacy-sensitive/-/expo-privacy-sensitive-0.1.0.tgz#2177d7a3cb8ed352df94c5806d012dfb7b48bc84"
|
resolved "https://registry.yarnpkg.com/expo-privacy-sensitive/-/expo-privacy-sensitive-0.1.0.tgz#2177d7a3cb8ed352df94c5806d012dfb7b48bc84"
|
||||||
@@ -9512,17 +9276,6 @@ fast-glob@^3.2.7:
|
|||||||
merge2 "^1.3.0"
|
merge2 "^1.3.0"
|
||||||
micromatch "^4.0.4"
|
micromatch "^4.0.4"
|
||||||
|
|
||||||
fast-glob@^3.2.9:
|
|
||||||
version "3.3.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
|
|
||||||
integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
|
|
||||||
dependencies:
|
|
||||||
"@nodelib/fs.stat" "^2.0.2"
|
|
||||||
"@nodelib/fs.walk" "^1.2.3"
|
|
||||||
glob-parent "^5.1.2"
|
|
||||||
merge2 "^1.3.0"
|
|
||||||
micromatch "^4.0.8"
|
|
||||||
|
|
||||||
fast-glob@^3.3.2:
|
fast-glob@^3.3.2:
|
||||||
version "3.3.2"
|
version "3.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
|
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
|
||||||
@@ -10080,18 +9833,6 @@ globalthis@^1.0.4:
|
|||||||
define-properties "^1.2.1"
|
define-properties "^1.2.1"
|
||||||
gopd "^1.0.1"
|
gopd "^1.0.1"
|
||||||
|
|
||||||
globby@^11.1.0:
|
|
||||||
version "11.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
|
|
||||||
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
|
|
||||||
dependencies:
|
|
||||||
array-union "^2.1.0"
|
|
||||||
dir-glob "^3.0.1"
|
|
||||||
fast-glob "^3.2.9"
|
|
||||||
ignore "^5.2.0"
|
|
||||||
merge2 "^1.4.1"
|
|
||||||
slash "^3.0.0"
|
|
||||||
|
|
||||||
globby@^12.0.2:
|
globby@^12.0.2:
|
||||||
version "12.2.0"
|
version "12.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/globby/-/globby-12.2.0.tgz#2ab8046b4fba4ff6eede835b29f678f90e3d3c22"
|
resolved "https://registry.yarnpkg.com/globby/-/globby-12.2.0.tgz#2ab8046b4fba4ff6eede835b29f678f90e3d3c22"
|
||||||
@@ -10132,11 +9873,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0,
|
|||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||||
|
|
||||||
graphemer@^1.4.0:
|
|
||||||
version "1.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
|
|
||||||
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
|
|
||||||
|
|
||||||
gzip-size@^6.0.0:
|
gzip-size@^6.0.0:
|
||||||
version "6.0.0"
|
version "6.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
|
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
|
||||||
@@ -10487,11 +10223,6 @@ ieee754@^1.1.13:
|
|||||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
|
||||||
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
|
||||||
|
|
||||||
ignore@^5.0.5:
|
|
||||||
version "5.3.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
|
|
||||||
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
|
|
||||||
|
|
||||||
ignore@^5.1.9, ignore@^5.2.0:
|
ignore@^5.1.9, ignore@^5.2.0:
|
||||||
version "5.2.4"
|
version "5.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
|
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
|
||||||
@@ -12501,7 +12232,7 @@ micromatch@4.0.5, micromatch@^4.0.2, micromatch@^4.0.4:
|
|||||||
braces "^3.0.2"
|
braces "^3.0.2"
|
||||||
picomatch "^2.3.1"
|
picomatch "^2.3.1"
|
||||||
|
|
||||||
micromatch@^4.0.0, micromatch@^4.0.7, micromatch@^4.0.8:
|
micromatch@^4.0.7, micromatch@^4.0.8:
|
||||||
version "4.0.8"
|
version "4.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
|
||||||
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
|
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
|
||||||
@@ -14130,6 +13861,11 @@ react-freeze@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d"
|
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d"
|
||||||
integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==
|
integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==
|
||||||
|
|
||||||
|
react-hotkeys-hook@5.2.4:
|
||||||
|
version "5.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-hotkeys-hook/-/react-hotkeys-hook-5.2.4.tgz#45ad54d78823b2a929963d482aff98efad0530f2"
|
||||||
|
integrity sha512-BgKg+A1+TawkYluh5Bo4cTmcgMN5L29uhJbDUQdHwPX+qgXRjIPYU5kIDHyxnAwCkCBiu9V5OpB2mpyeluVF2A==
|
||||||
|
|
||||||
react-image-crop@^11.0.7:
|
react-image-crop@^11.0.7:
|
||||||
version "11.0.7"
|
version "11.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-11.0.7.tgz#25f3d37ccbb65a05d19d23b4740a5912835c741e"
|
resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-11.0.7.tgz#25f3d37ccbb65a05d19d23b4740a5912835c741e"
|
||||||
@@ -14932,16 +14668,16 @@ selfsigned@^2.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
node-forge "^1"
|
node-forge "^1"
|
||||||
|
|
||||||
semver@7.6.3, semver@^7.1.3:
|
|
||||||
version "7.6.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
|
|
||||||
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
|
||||||
|
|
||||||
semver@^6.0.0, semver@^6.3.0, semver@^6.3.1:
|
semver@^6.0.0, semver@^6.3.0, semver@^6.3.1:
|
||||||
version "6.3.1"
|
version "6.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||||
|
|
||||||
|
semver@^7.1.3:
|
||||||
|
version "7.6.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
|
||||||
|
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
||||||
|
|
||||||
semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@~7.5.4:
|
semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@~7.5.4:
|
||||||
version "7.5.4"
|
version "7.5.4"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||||
@@ -14949,11 +14685,6 @@ semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@~7.5.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
lru-cache "^6.0.0"
|
lru-cache "^6.0.0"
|
||||||
|
|
||||||
semver@^7.3.7:
|
|
||||||
version "7.7.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a"
|
|
||||||
integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==
|
|
||||||
|
|
||||||
semver@^7.6.0:
|
semver@^7.6.0:
|
||||||
version "7.6.2"
|
version "7.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
|
||||||
@@ -15507,11 +15238,6 @@ string-length@^5.0.1:
|
|||||||
char-regex "^2.0.0"
|
char-regex "^2.0.0"
|
||||||
strip-ansi "^7.0.1"
|
strip-ansi "^7.0.1"
|
||||||
|
|
||||||
string-natural-compare@^3.0.1:
|
|
||||||
version "3.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
|
|
||||||
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
|
|
||||||
|
|
||||||
"string-width-cjs@npm:string-width@^4.2.0":
|
"string-width-cjs@npm:string-width@^4.2.0":
|
||||||
version "4.2.3"
|
version "4.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||||
@@ -16022,11 +15748,6 @@ tr46@~0.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||||
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
|
||||||
|
|
||||||
ts-api-utils@^1.3.0:
|
|
||||||
version "1.4.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064"
|
|
||||||
integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==
|
|
||||||
|
|
||||||
ts-api-utils@^2.5.0:
|
ts-api-utils@^2.5.0:
|
||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.5.0.tgz#4acd4a155e22734990a5ed1fe9e97f113bcb37c1"
|
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.5.0.tgz#4acd4a155e22734990a5ed1fe9e97f113bcb37c1"
|
||||||
@@ -16042,11 +15763,6 @@ ts-plugin-sort-import-suggestions@^1.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/ts-plugin-sort-import-suggestions/-/ts-plugin-sort-import-suggestions-1.0.4.tgz#d1ed6c235feb8c8bb8b34c625ea75b46e3e62925"
|
resolved "https://registry.yarnpkg.com/ts-plugin-sort-import-suggestions/-/ts-plugin-sort-import-suggestions-1.0.4.tgz#d1ed6c235feb8c8bb8b34c625ea75b46e3e62925"
|
||||||
integrity sha512-85n5lm2OQQ+b7aRNK9omU1gmjMNXRsgeLwojm5u4OSY5sVBkAHTcgMQPEeHMNlyyfFW0uXnwgqAU0pNfhD96Bw==
|
integrity sha512-85n5lm2OQQ+b7aRNK9omU1gmjMNXRsgeLwojm5u4OSY5sVBkAHTcgMQPEeHMNlyyfFW0uXnwgqAU0pNfhD96Bw==
|
||||||
|
|
||||||
tslib@^1.8.1:
|
|
||||||
version "1.14.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
|
||||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
|
||||||
|
|
||||||
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0:
|
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0:
|
||||||
version "2.6.2"
|
version "2.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
||||||
@@ -16057,13 +15773,6 @@ tslib@^2.8.0, tslib@^2.8.1:
|
|||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||||
|
|
||||||
tsutils@^3.21.0:
|
|
||||||
version "3.21.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
|
|
||||||
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
|
|
||||||
dependencies:
|
|
||||||
tslib "^1.8.1"
|
|
||||||
|
|
||||||
type-check@^0.4.0, type-check@~0.4.0:
|
type-check@^0.4.0, type-check@~0.4.0:
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
||||||
@@ -16188,7 +15897,7 @@ typed-array-length@^1.0.7:
|
|||||||
possible-typed-array-names "^1.0.0"
|
possible-typed-array-names "^1.0.0"
|
||||||
reflect.getprototypeof "^1.0.6"
|
reflect.getprototypeof "^1.0.6"
|
||||||
|
|
||||||
typescript-eslint@^8.57.2:
|
typescript-eslint@^8.58.0:
|
||||||
version "8.58.0"
|
version "8.58.0"
|
||||||
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.58.0.tgz#5758b1b68ae7ec05d756b98c63a1f6953a01172b"
|
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.58.0.tgz#5758b1b68ae7ec05d756b98c63a1f6953a01172b"
|
||||||
integrity sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==
|
integrity sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==
|
||||||
|
|||||||
Reference in New Issue
Block a user