Merge branch 'main' into web-layout

This commit is contained in:
Dan Abramov
2023-12-22 02:53:34 +00:00
25 changed files with 3177 additions and 233 deletions
+140 -27
View File
@@ -1,6 +1,5 @@
import {RichText} from '@atproto/api'
import {
getYoutubeVideoId,
makeRecordUri,
toNiceDomain,
toShortUrl,
@@ -12,6 +11,7 @@ import {detectLinkables} from '../../src/lib/strings/rich-text-detection'
import {shortenLinks} from '../../src/lib/strings/rich-text-manip'
import {makeValidHandle, createFullHandle} from '../../src/lib/strings/handles'
import {cleanError} from '../../src/lib/strings/errors'
import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player'
describe('detectLinkables', () => {
const inputs = [
@@ -335,32 +335,6 @@ describe('toShareUrl', () => {
})
})
describe('getYoutubeVideoId', () => {
it(' should return undefined for invalid youtube links', () => {
expect(getYoutubeVideoId('')).toBeUndefined()
expect(getYoutubeVideoId('https://www.google.com')).toBeUndefined()
expect(getYoutubeVideoId('https://www.youtube.com')).toBeUndefined()
expect(
getYoutubeVideoId('https://www.youtube.com/channelName'),
).toBeUndefined()
expect(
getYoutubeVideoId('https://www.youtube.com/channel/channelName'),
).toBeUndefined()
})
it('getYoutubeVideoId should return video id for valid youtube links', () => {
expect(getYoutubeVideoId('https://www.youtube.com/watch?v=videoId')).toBe(
'videoId',
)
expect(
getYoutubeVideoId(
'https://www.youtube.com/watch?v=videoId&feature=share',
),
).toBe('videoId')
expect(getYoutubeVideoId('https://youtu.be/videoId')).toBe('videoId')
})
})
describe('shortenLinks', () => {
const inputs = [
'start https://middle.com/foo/bar?baz=bux#hash end',
@@ -396,6 +370,7 @@ describe('shortenLinks', () => {
],
],
]
it('correctly shortens rich text while preserving facet URIs', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
@@ -410,3 +385,141 @@ describe('shortenLinks', () => {
}
})
})
describe('parseEmbedPlayerFromUrl', () => {
const inputs = [
'https://youtu.be/videoId',
'https://www.youtube.com/watch?v=videoId',
'https://www.youtube.com/watch?v=videoId&feature=share',
'https://youtube.com/watch?v=videoId',
'https://youtube.com/watch?v=videoId&feature=share',
'https://youtube.com/shorts/videoId',
'https://youtube.com/shorts/',
'https://youtube.com/',
'https://youtube.com/random',
'https://twitch.tv/channelName',
'https://www.twitch.tv/channelName',
'https://open.spotify.com/playlist/playlistId',
'https://open.spotify.com/playlist/playlistId?param=value',
'https://open.spotify.com/track/songId',
'https://open.spotify.com/track/songId?param=value',
'https://open.spotify.com/album/albumId',
'https://open.spotify.com/album/albumId?param=value',
'https://soundcloud.com/user/track',
'https://soundcloud.com/user/sets/set',
'https://soundcloud.com/user/',
]
const outputs = [
{
type: 'youtube_video',
videoId: 'videoId',
playerUri: 'https://www.youtube.com/embed/videoId?autoplay=1',
},
{
type: 'youtube_video',
videoId: 'videoId',
playerUri: 'https://www.youtube.com/embed/videoId?autoplay=1',
},
{
type: 'youtube_video',
videoId: 'videoId',
playerUri: 'https://www.youtube.com/embed/videoId?autoplay=1',
},
{
type: 'youtube_video',
videoId: 'videoId',
playerUri: 'https://www.youtube.com/embed/videoId?autoplay=1',
},
{
type: 'youtube_video',
videoId: 'videoId',
playerUri: 'https://www.youtube.com/embed/videoId?autoplay=1',
},
{
type: 'youtube_video',
videoId: 'videoId',
playerUri: 'https://www.youtube.com/embed/videoId?autoplay=1',
},
undefined,
undefined,
undefined,
{
type: 'twitch_live',
channelId: 'channelName',
playerUri: `https://player.twitch.tv/?volume=0.5&!muted&autoplay&channel=channelName&parent=localhost`,
},
{
type: 'twitch_live',
channelId: 'channelName',
playerUri: `https://player.twitch.tv/?volume=0.5&!muted&autoplay&channel=channelName&parent=localhost`,
},
{
type: 'spotify_playlist',
playlistId: 'playlistId',
playerUri: `https://open.spotify.com/embed/playlist/playlistId`,
},
{
type: 'spotify_playlist',
playlistId: 'playlistId',
playerUri: `https://open.spotify.com/embed/playlist/playlistId`,
},
{
type: 'spotify_song',
songId: 'songId',
playerUri: `https://open.spotify.com/embed/track/songId`,
},
{
type: 'spotify_song',
songId: 'songId',
playerUri: `https://open.spotify.com/embed/track/songId`,
},
{
type: 'spotify_album',
albumId: 'albumId',
playerUri: `https://open.spotify.com/embed/album/albumId`,
},
{
type: 'spotify_album',
albumId: 'albumId',
playerUri: `https://open.spotify.com/embed/album/albumId`,
},
{
type: 'soundcloud_track',
user: 'user',
track: 'track',
playerUri: `https://w.soundcloud.com/player/?url=https://soundcloud.com/user/track&auto_play=true&visual=false&hide_related=true`,
},
{
type: 'soundcloud_set',
user: 'user',
set: 'set',
playerUri: `https://w.soundcloud.com/player/?url=https://soundcloud.com/user/sets/set&auto_play=true&visual=false&hide_related=true`,
},
undefined,
]
it('correctly grabs the correct id from uri', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const output = outputs[i]
const res = parseEmbedPlayerFromUrl(input)
console.log(input)
expect(res).toEqual(output)
}
})
})
+2 -2
View File
@@ -32,7 +32,7 @@ import { Text } from "react-native";
const text = "Hello World";
<Text accessibilityLabel="Label is here">{text}</Text>
```
In this case, you cannot use the `useLingui()` hook:
In this case, you can use the `useLingui()` hook:
```jsx
import { msg } from "@lingui/macro";
import { useLingui } from "@lingui/react";
@@ -116,4 +116,4 @@ export function Welcome() {
### Credits
Please check each individual `messages.po` file for the credits of the translators. We are very grateful for their help!
If you would like to translate the Bluesky app into your language, please open a PR or issue on this repo.
If you would like to translate the Bluesky app into your language, please open a PR or issue on this repo.
+1 -1
View File
@@ -1,6 +1,6 @@
/** @type {import('@lingui/conf').LinguiConfig} */
module.exports = {
locales: ['en', 'hi', 'ja'],
locales: ['en', 'hi', 'ja', 'fr'],
catalogs: [
{
path: '<rootDir>/src/locale/locales/{locale}/messages',
+4 -1
View File
@@ -137,7 +137,7 @@
"react-dom": "^18.2.0",
"react-native": "0.72.5",
"react-native-appstate-hook": "^1.0.6",
"react-native-drawer-layout": "^3.2.0",
"react-native-drawer-layout": "^4.0.0-alpha.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "^2.12.1",
"react-native-get-random-values": "^1.8.0",
@@ -160,6 +160,9 @@
"react-native-version-number": "^0.3.6",
"react-native-web": "~0.19.6",
"react-native-web-linear-gradient": "^1.1.2",
"react-native-web-webview": "^1.0.2",
"react-native-webview": "^13.6.2",
"react-native-youtube-iframe": "^2.3.0",
"react-responsive": "^9.0.2",
"rn-fetch-blob": "^0.12.0",
"sentry-expo": "~7.0.1",
+147
View File
@@ -0,0 +1,147 @@
export type EmbedPlayerParams =
| {type: 'youtube_video'; videoId: string; playerUri: string}
| {type: 'twitch_live'; channelId: string; playerUri: string}
| {type: 'spotify_album'; albumId: string; playerUri: string}
| {
type: 'spotify_playlist'
playlistId: string
playerUri: string
}
| {type: 'spotify_song'; songId: string; playerUri: string}
| {type: 'soundcloud_track'; user: string; track: string; playerUri: string}
| {type: 'soundcloud_set'; user: string; set: string; playerUri: string}
export function parseEmbedPlayerFromUrl(
url: string,
): EmbedPlayerParams | undefined {
let urlp
try {
urlp = new URL(url)
} catch (e) {
return undefined
}
// youtube
if (urlp.hostname === 'youtu.be') {
const videoId = urlp.pathname.split('/')[1]
if (videoId) {
return {
type: 'youtube_video',
videoId,
playerUri: `https://www.youtube.com/embed/${videoId}?autoplay=1`,
}
}
}
if (urlp.hostname === 'www.youtube.com' || urlp.hostname === 'youtube.com') {
const [_, page, shortVideoId] = urlp.pathname.split('/')
const videoId =
page === 'shorts' ? shortVideoId : (urlp.searchParams.get('v') as string)
if (videoId) {
return {
type: 'youtube_video',
videoId,
playerUri: `https://www.youtube.com/embed/${videoId}?autoplay=1`,
}
}
}
// twitch
if (urlp.hostname === 'twitch.tv' || urlp.hostname === 'www.twitch.tv') {
const parts = urlp.pathname.split('/')
if (parts.length === 2 && parts[1]) {
return {
type: 'twitch_live',
channelId: parts[1],
playerUri: `https://player.twitch.tv/?volume=0.5&!muted&autoplay&channel=${parts[1]}&parent=localhost`,
}
}
}
// spotify
if (urlp.hostname === 'open.spotify.com') {
const [_, type, id] = urlp.pathname.split('/')
if (type && id) {
if (type === 'playlist') {
return {
type: 'spotify_playlist',
playlistId: id,
playerUri: `https://open.spotify.com/embed/playlist/${id}`,
}
}
if (type === 'album') {
return {
type: 'spotify_album',
albumId: id,
playerUri: `https://open.spotify.com/embed/album/${id}`,
}
}
if (type === 'track') {
return {
type: 'spotify_song',
songId: id,
playerUri: `https://open.spotify.com/embed/track/${id}`,
}
}
}
}
// soundcloud
if (
urlp.hostname === 'soundcloud.com' ||
urlp.hostname === 'www.soundcloud.com'
) {
const [_, user, trackOrSets, set] = urlp.pathname.split('/')
if (user && trackOrSets) {
if (trackOrSets === 'sets' && set) {
return {
type: 'soundcloud_set',
user,
set: set,
playerUri: `https://w.soundcloud.com/player/?url=${url}&auto_play=true&visual=false&hide_related=true`,
}
}
return {
type: 'soundcloud_track',
user,
track: trackOrSets,
playerUri: `https://w.soundcloud.com/player/?url=${url}&auto_play=true&visual=false&hide_related=true`,
}
}
}
}
export function getPlayerHeight({
type,
width,
hasThumb,
}: {
type: EmbedPlayerParams['type']
width: number
hasThumb: boolean
}) {
if (!hasThumb) return (width / 16) * 9
switch (type) {
case 'youtube_video':
case 'twitch_live':
return (width / 16) * 9
case 'spotify_album':
return 380
case 'spotify_playlist':
return 360
case 'spotify_song':
if (width <= 300) {
return 180
}
return 232
case 'soundcloud_track':
return 165
case 'soundcloud_set':
return 360
default:
return width
}
}
-29
View File
@@ -139,35 +139,6 @@ export function feedUriToHref(url: string): string {
}
}
export function getYoutubeVideoId(link: string): string | undefined {
let url
try {
url = new URL(link)
} catch (e) {
return undefined
}
if (
url.hostname !== 'www.youtube.com' &&
url.hostname !== 'youtube.com' &&
url.hostname !== 'youtu.be'
) {
return undefined
}
if (url.hostname === 'youtu.be') {
const videoId = url.pathname.split('/')[1]
if (!videoId) {
return undefined
}
return videoId
}
const videoId = url.searchParams.get('v') as string
if (!videoId) {
return undefined
}
return videoId
}
/**
* Checks if the label in the post text matches the host of the link facet.
*
+2 -2
View File
@@ -7,6 +7,6 @@ test('sanitizeAppLanguageSetting', () => {
expect(sanitizeAppLanguageSetting('en')).toBe(AppLanguage.en)
expect(sanitizeAppLanguageSetting('hi')).toBe(AppLanguage.hi)
expect(sanitizeAppLanguageSetting('foo')).toBe(AppLanguage.en)
expect(sanitizeAppLanguageSetting('en,fr')).toBe(AppLanguage.en)
expect(sanitizeAppLanguageSetting('fr,en')).toBe(AppLanguage.en)
expect(sanitizeAppLanguageSetting('en,foo')).toBe(AppLanguage.en)
expect(sanitizeAppLanguageSetting('foo,en')).toBe(AppLanguage.en)
})
+2
View File
@@ -114,6 +114,8 @@ export function sanitizeAppLanguageSetting(appLanguage: string): AppLanguage {
return AppLanguage.hi
case 'ja':
return AppLanguage.ja
case 'fr':
return AppLanguage.fr
default:
continue
}
+5
View File
@@ -5,6 +5,7 @@ import {useLanguagePrefs} from '#/state/preferences'
import {messages as messagesEn} from '#/locale/locales/en/messages'
import {messages as messagesHi} from '#/locale/locales/hi/messages'
import {messages as messagesJa} from '#/locale/locales/ja/messages'
import {messages as messagesFr} from '#/locale/locales/fr/messages'
import {sanitizeAppLanguageSetting} from '#/locale/helpers'
import {AppLanguage} from '#/locale/languages'
@@ -21,6 +22,10 @@ export async function dynamicActivate(locale: AppLanguage) {
i18n.loadAndActivate({locale, messages: messagesJa})
break
}
case AppLanguage.fr: {
i18n.loadAndActivate({locale, messages: messagesFr})
break
}
default: {
i18n.loadAndActivate({locale, messages: messagesEn})
break
+4
View File
@@ -20,6 +20,10 @@ export async function dynamicActivate(locale: AppLanguage) {
mod = await import(`./locales/ja/messages`)
break
}
case AppLanguage.fr: {
mod = await import(`./locales/fr/messages`)
break
}
default: {
mod = await import(`./locales/en/messages`)
break
+2
View File
@@ -8,6 +8,7 @@ export enum AppLanguage {
en = 'en',
hi = 'hi',
ja = 'ja',
fr = 'fr',
}
interface AppLanguageConfig {
@@ -19,6 +20,7 @@ export const APP_LANGUAGES: AppLanguageConfig[] = [
{code2: AppLanguage.en, name: 'English'},
{code2: AppLanguage.hi, name: 'हिंदी'},
{code2: AppLanguage.ja, name: '日本語'},
{code2: AppLanguage.fr, name: 'Français'},
]
export const LANGUAGES: Language[] = [
File diff suppressed because one or more lines are too long
+27 -27
View File
@@ -375,7 +375,7 @@ msgstr ""
#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Composer.tsx:288
#: src/view/com/modals/AltImage.tsx:127
#: src/view/com/modals/AltImage.tsx:128
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/Confirm.tsx:88
@@ -398,7 +398,7 @@ msgstr ""
msgid "Cancel account deletion"
msgstr ""
#: src/view/com/modals/AltImage.tsx:122
#: src/view/com/modals/AltImage.tsx:123
msgid "Cancel add image alt text"
msgstr ""
@@ -809,7 +809,7 @@ msgstr ""
msgid "Enable this setting to only see replies between people you follow."
msgstr ""
#: src/view/screens/Profile.tsx:425
#: src/view/screens/Profile.tsx:426
msgid "End of feed"
msgstr ""
@@ -854,7 +854,7 @@ msgstr ""
msgid "Failed to load recommended feeds"
msgstr ""
#: src/view/screens/Feeds.tsx:559
#: src/view/screens/Feeds.tsx:560
msgid "Feed offline"
msgstr ""
@@ -868,9 +868,9 @@ msgid "Feedback"
msgstr ""
#: src/view/screens/Feeds.tsx:475
#: src/view/screens/Profile.tsx:164
#: src/view/screens/Profile.tsx:165
#: src/view/shell/bottom-bar/BottomBar.tsx:181
#: src/view/shell/desktop/LeftNav.tsx:339
#: src/view/shell/desktop/LeftNav.tsx:340
#: src/view/shell/Drawer.tsx:455
#: src/view/shell/Drawer.tsx:456
msgid "Feeds"
@@ -973,7 +973,7 @@ msgstr ""
#: src/view/com/auth/LoggedOut.tsx:81
#: src/view/com/auth/LoggedOut.tsx:82
#: src/view/com/util/moderation/ScreenHider.tsx:123
#: src/view/shell/desktop/LeftNav.tsx:103
#: src/view/shell/desktop/LeftNav.tsx:104
msgid "Go back"
msgstr ""
@@ -1041,7 +1041,7 @@ msgstr ""
#~ msgstr ""
#: src/view/shell/bottom-bar/BottomBar.tsx:137
#: src/view/shell/desktop/LeftNav.tsx:303
#: src/view/shell/desktop/LeftNav.tsx:304
#: src/view/shell/Drawer.tsx:379
#: src/view/shell/Drawer.tsx:380
msgid "Home"
@@ -1074,7 +1074,7 @@ msgstr ""
msgid "If none are selected, suitable for all ages."
msgstr ""
#: src/view/com/modals/AltImage.tsx:96
#: src/view/com/modals/AltImage.tsx:97
msgid "Image alt text"
msgstr ""
@@ -1195,7 +1195,7 @@ msgstr ""
msgid "Liked by"
msgstr ""
#: src/view/screens/Profile.tsx:163
#: src/view/screens/Profile.tsx:164
msgid "Likes"
msgstr ""
@@ -1215,8 +1215,8 @@ msgstr ""
msgid "List Name"
msgstr ""
#: src/view/screens/Profile.tsx:165
#: src/view/shell/desktop/LeftNav.tsx:376
#: src/view/screens/Profile.tsx:166
#: src/view/shell/desktop/LeftNav.tsx:377
#: src/view/shell/Drawer.tsx:471
#: src/view/shell/Drawer.tsx:472
msgid "Lists"
@@ -1263,7 +1263,7 @@ msgstr ""
msgid "Make sure this is where you intend to go!"
msgstr ""
#: src/view/screens/Profile.tsx:162
#: src/view/screens/Profile.tsx:163
msgid "Media"
msgstr ""
@@ -1285,7 +1285,7 @@ msgstr ""
#: src/view/screens/Moderation.tsx:64
#: src/view/screens/Settings.tsx:563
#: src/view/shell/desktop/LeftNav.tsx:394
#: src/view/shell/desktop/LeftNav.tsx:395
#: src/view/shell/Drawer.tsx:490
#: src/view/shell/Drawer.tsx:491
msgid "Moderation"
@@ -1361,7 +1361,7 @@ msgstr ""
msgid "My Feeds"
msgstr ""
#: src/view/shell/desktop/LeftNav.tsx:64
#: src/view/shell/desktop/LeftNav.tsx:65
msgid "My Profile"
msgstr ""
@@ -1384,16 +1384,16 @@ msgid "New"
msgstr ""
#: src/view/com/feeds/FeedPage.tsx:200
#: src/view/screens/Feeds.tsx:510
#: src/view/screens/Profile.tsx:353
#: src/view/screens/Feeds.tsx:511
#: src/view/screens/Profile.tsx:354
#: src/view/screens/ProfileFeed.tsx:430
#: src/view/screens/ProfileList.tsx:193
#: src/view/screens/ProfileList.tsx:221
#: src/view/shell/desktop/LeftNav.tsx:246
#: src/view/shell/desktop/LeftNav.tsx:247
msgid "New post"
msgstr ""
#: src/view/shell/desktop/LeftNav.tsx:256
#: src/view/shell/desktop/LeftNav.tsx:257
msgid "New Post"
msgstr ""
@@ -1470,7 +1470,7 @@ msgstr ""
#: src/view/screens/Notifications.tsx:109
#: src/view/screens/Notifications.tsx:133
#: src/view/shell/bottom-bar/BottomBar.tsx:205
#: src/view/shell/desktop/LeftNav.tsx:358
#: src/view/shell/desktop/LeftNav.tsx:359
#: src/view/shell/Drawer.tsx:416
#: src/view/shell/Drawer.tsx:417
msgid "Notifications"
@@ -1634,7 +1634,7 @@ msgstr ""
msgid "Post not found"
msgstr ""
#: src/view/screens/Profile.tsx:160
#: src/view/screens/Profile.tsx:161
msgid "Posts"
msgstr ""
@@ -1667,7 +1667,7 @@ msgid "Processing..."
msgstr ""
#: src/view/shell/bottom-bar/BottomBar.tsx:247
#: src/view/shell/desktop/LeftNav.tsx:412
#: src/view/shell/desktop/LeftNav.tsx:413
#: src/view/shell/Drawer.tsx:69
#: src/view/shell/Drawer.tsx:525
#: src/view/shell/Drawer.tsx:526
@@ -1759,7 +1759,7 @@ msgstr ""
msgid "Removed from list"
msgstr ""
#: src/view/screens/Profile.tsx:161
#: src/view/screens/Profile.tsx:162
msgid "Replies"
msgstr ""
@@ -1859,7 +1859,7 @@ msgstr ""
#~ msgid "Retry change handle"
#~ msgstr ""
#: src/view/com/modals/AltImage.tsx:114
#: src/view/com/modals/AltImage.tsx:115
#: src/view/com/modals/BirthDateSettings.tsx:93
#: src/view/com/modals/BirthDateSettings.tsx:96
#: src/view/com/modals/ChangeHandle.tsx:173
@@ -1869,7 +1869,7 @@ msgstr ""
msgid "Save"
msgstr ""
#: src/view/com/modals/AltImage.tsx:105
#: src/view/com/modals/AltImage.tsx:106
msgid "Save alt text"
msgstr ""
@@ -1898,7 +1898,7 @@ msgstr ""
#: src/view/screens/Search/Search.tsx:401
#: src/view/screens/Search/Search.tsx:567
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:321
#: src/view/shell/desktop/LeftNav.tsx:322
#: src/view/shell/desktop/Search.tsx:161
#: src/view/shell/desktop/Search.tsx:170
#: src/view/shell/Drawer.tsx:343
@@ -1993,7 +1993,7 @@ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your f
msgstr ""
#: src/view/screens/Settings.tsx:277
#: src/view/shell/desktop/LeftNav.tsx:430
#: src/view/shell/desktop/LeftNav.tsx:431
#: src/view/shell/Drawer.tsx:546
#: src/view/shell/Drawer.tsx:547
msgid "Settings"
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+27 -27
View File
@@ -375,7 +375,7 @@ msgstr "केवल अक्षर, संख्या, रिक्त स्
#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Composer.tsx:288
#: src/view/com/modals/AltImage.tsx:127
#: src/view/com/modals/AltImage.tsx:128
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/Confirm.tsx:88
@@ -398,7 +398,7 @@ msgstr "कैंसिल"
msgid "Cancel account deletion"
msgstr "अकाउंट बंद मत करो"
#: src/view/com/modals/AltImage.tsx:122
#: src/view/com/modals/AltImage.tsx:123
msgid "Cancel add image alt text"
msgstr "ऑल्ट टेक्स्ट मत जोड़ें"
@@ -805,7 +805,7 @@ msgstr "ईमेल:"
msgid "Enable this setting to only see replies between people you follow."
msgstr "इस सेटिंग को केवल उन लोगों के बीच जवाब देखने में सक्षम करें जिन्हें आप फॉलो करते हैं।।"
#: src/view/screens/Profile.tsx:425
#: src/view/screens/Profile.tsx:426
msgid "End of feed"
msgstr ""
@@ -850,7 +850,7 @@ msgstr "ऑल्ट टेक्स्ट"
msgid "Failed to load recommended feeds"
msgstr "अनुशंसित फ़ीड लोड करने में विफल"
#: src/view/screens/Feeds.tsx:559
#: src/view/screens/Feeds.tsx:560
msgid "Feed offline"
msgstr "फ़ीड ऑफ़लाइन है"
@@ -864,9 +864,9 @@ msgid "Feedback"
msgstr "प्रतिक्रिया"
#: src/view/screens/Feeds.tsx:475
#: src/view/screens/Profile.tsx:164
#: src/view/screens/Profile.tsx:165
#: src/view/shell/bottom-bar/BottomBar.tsx:181
#: src/view/shell/desktop/LeftNav.tsx:339
#: src/view/shell/desktop/LeftNav.tsx:340
#: src/view/shell/Drawer.tsx:455
#: src/view/shell/Drawer.tsx:456
msgid "Feeds"
@@ -965,7 +965,7 @@ msgstr "प्रारंभ करें"
#: src/view/com/auth/LoggedOut.tsx:81
#: src/view/com/auth/LoggedOut.tsx:82
#: src/view/com/util/moderation/ScreenHider.tsx:123
#: src/view/shell/desktop/LeftNav.tsx:103
#: src/view/shell/desktop/LeftNav.tsx:104
msgid "Go back"
msgstr "वापस जाओ"
@@ -1033,7 +1033,7 @@ msgstr ""
#~ msgstr ""
#: src/view/shell/bottom-bar/BottomBar.tsx:137
#: src/view/shell/desktop/LeftNav.tsx:303
#: src/view/shell/desktop/LeftNav.tsx:304
#: src/view/shell/Drawer.tsx:379
#: src/view/shell/Drawer.tsx:380
msgid "Home"
@@ -1066,7 +1066,7 @@ msgstr "मेरे पास अपना डोमेन है"
msgid "If none are selected, suitable for all ages."
msgstr "यदि किसी को चुना जाता है, तो सभी उम्र के लिए उपयुक्त है।।"
#: src/view/com/modals/AltImage.tsx:96
#: src/view/com/modals/AltImage.tsx:97
msgid "Image alt text"
msgstr "छवि alt पाठ"
@@ -1187,7 +1187,7 @@ msgstr "इस फ़ीड को लाइक करो"
msgid "Liked by"
msgstr "इन यूजर ने लाइक किया है"
#: src/view/screens/Profile.tsx:163
#: src/view/screens/Profile.tsx:164
msgid "Likes"
msgstr ""
@@ -1207,8 +1207,8 @@ msgstr "सूची अवतार"
msgid "List Name"
msgstr "सूची का नाम"
#: src/view/screens/Profile.tsx:165
#: src/view/shell/desktop/LeftNav.tsx:376
#: src/view/screens/Profile.tsx:166
#: src/view/shell/desktop/LeftNav.tsx:377
#: src/view/shell/Drawer.tsx:471
#: src/view/shell/Drawer.tsx:472
msgid "Lists"
@@ -1255,7 +1255,7 @@ msgstr "उस खाते में लॉग इन करें जो स
msgid "Make sure this is where you intend to go!"
msgstr "यह सुनिश्चित करने के लिए कि आप कहाँ जाना चाहते हैं!"
#: src/view/screens/Profile.tsx:162
#: src/view/screens/Profile.tsx:163
msgid "Media"
msgstr ""
@@ -1277,7 +1277,7 @@ msgstr ""
#: src/view/screens/Moderation.tsx:64
#: src/view/screens/Settings.tsx:563
#: src/view/shell/desktop/LeftNav.tsx:394
#: src/view/shell/desktop/LeftNav.tsx:395
#: src/view/shell/Drawer.tsx:490
#: src/view/shell/Drawer.tsx:491
msgid "Moderation"
@@ -1353,7 +1353,7 @@ msgstr "जन्मदिन"
msgid "My Feeds"
msgstr "मेरी फ़ीड"
#: src/view/shell/desktop/LeftNav.tsx:64
#: src/view/shell/desktop/LeftNav.tsx:65
msgid "My Profile"
msgstr "मेरी प्रोफाइल"
@@ -1376,16 +1376,16 @@ msgid "New"
msgstr "नया"
#: src/view/com/feeds/FeedPage.tsx:200
#: src/view/screens/Feeds.tsx:510
#: src/view/screens/Profile.tsx:353
#: src/view/screens/Feeds.tsx:511
#: src/view/screens/Profile.tsx:354
#: src/view/screens/ProfileFeed.tsx:430
#: src/view/screens/ProfileList.tsx:193
#: src/view/screens/ProfileList.tsx:221
#: src/view/shell/desktop/LeftNav.tsx:246
#: src/view/shell/desktop/LeftNav.tsx:247
msgid "New post"
msgstr "नई पोस्ट"
#: src/view/shell/desktop/LeftNav.tsx:256
#: src/view/shell/desktop/LeftNav.tsx:257
msgid "New Post"
msgstr "नई पोस्ट"
@@ -1462,7 +1462,7 @@ msgstr ""
#: src/view/screens/Notifications.tsx:109
#: src/view/screens/Notifications.tsx:133
#: src/view/shell/bottom-bar/BottomBar.tsx:205
#: src/view/shell/desktop/LeftNav.tsx:358
#: src/view/shell/desktop/LeftNav.tsx:359
#: src/view/shell/Drawer.tsx:416
#: src/view/shell/Drawer.tsx:417
msgid "Notifications"
@@ -1626,7 +1626,7 @@ msgstr "पोस्ट भाषा"
msgid "Post not found"
msgstr "पोस्ट नहीं मिला"
#: src/view/screens/Profile.tsx:160
#: src/view/screens/Profile.tsx:161
msgid "Posts"
msgstr ""
@@ -1659,7 +1659,7 @@ msgid "Processing..."
msgstr "प्रसंस्करण..."
#: src/view/shell/bottom-bar/BottomBar.tsx:247
#: src/view/shell/desktop/LeftNav.tsx:412
#: src/view/shell/desktop/LeftNav.tsx:413
#: src/view/shell/Drawer.tsx:69
#: src/view/shell/Drawer.tsx:525
#: src/view/shell/Drawer.tsx:526
@@ -1751,7 +1751,7 @@ msgstr "इस फ़ीड को सहेजे गए फ़ीड से
msgid "Removed from list"
msgstr ""
#: src/view/screens/Profile.tsx:161
#: src/view/screens/Profile.tsx:162
msgid "Replies"
msgstr ""
@@ -1851,7 +1851,7 @@ msgstr "फिर से कोशिश करो"
#~ msgid "Retry change handle"
#~ msgstr "हैंडल बदलना फिर से कोशिश करो"
#: src/view/com/modals/AltImage.tsx:114
#: src/view/com/modals/AltImage.tsx:115
#: src/view/com/modals/BirthDateSettings.tsx:93
#: src/view/com/modals/BirthDateSettings.tsx:96
#: src/view/com/modals/ChangeHandle.tsx:173
@@ -1861,7 +1861,7 @@ msgstr "फिर से कोशिश करो"
msgid "Save"
msgstr "सेव करो"
#: src/view/com/modals/AltImage.tsx:105
#: src/view/com/modals/AltImage.tsx:106
msgid "Save alt text"
msgstr "सेव ऑल्ट टेक्स्ट"
@@ -1890,7 +1890,7 @@ msgstr "सहेजे गए फ़ीड"
#: src/view/screens/Search/Search.tsx:401
#: src/view/screens/Search/Search.tsx:567
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:321
#: src/view/shell/desktop/LeftNav.tsx:322
#: src/view/shell/desktop/Search.tsx:161
#: src/view/shell/desktop/Search.tsx:170
#: src/view/shell/Drawer.tsx:343
@@ -1985,7 +1985,7 @@ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your f
msgstr "इस सेटिंग को अपने निम्नलिखित फ़ीड में अपने सहेजे गए फ़ीड के नमूने दिखाने के लिए \"हाँ\" पर सेट करें। यह एक प्रयोगात्मक विशेषता है।।"
#: src/view/screens/Settings.tsx:277
#: src/view/shell/desktop/LeftNav.tsx:430
#: src/view/shell/desktop/LeftNav.tsx:431
#: src/view/shell/Drawer.tsx:546
#: src/view/shell/Drawer.tsx:547
msgid "Settings"
File diff suppressed because one or more lines are too long
+27 -27
View File
@@ -347,7 +347,7 @@ msgstr "文字、数字、スペース、ハイフン、およびアンダース
#: src/view/com/composer/Composer.tsx:285
#: src/view/com/composer/Composer.tsx:288
#: src/view/com/modals/AltImage.tsx:127
#: src/view/com/modals/AltImage.tsx:128
#: src/view/com/modals/ChangeEmail.tsx:218
#: src/view/com/modals/ChangeEmail.tsx:220
#: src/view/com/modals/Confirm.tsx:88
@@ -370,7 +370,7 @@ msgstr "キャンセル"
msgid "Cancel account deletion"
msgstr "アカウントの削除をキャンセル"
#: src/view/com/modals/AltImage.tsx:122
#: src/view/com/modals/AltImage.tsx:123
msgid "Cancel add image alt text"
msgstr "画像のALTテキストの追加をキャンセル"
@@ -773,7 +773,7 @@ msgstr "メールアドレス:"
msgid "Enable this setting to only see replies between people you follow."
msgstr "この設定を有効にすると、フォローしているユーザー間の返信だけが表示されます。"
#: src/view/screens/Profile.tsx:425
#: src/view/screens/Profile.tsx:426
msgid "End of feed"
msgstr "フィードの終わり"
@@ -818,7 +818,7 @@ msgstr "ALTテキストを展開"
msgid "Failed to load recommended feeds"
msgstr "おすすめのフィードのロードに失敗しました"
#: src/view/screens/Feeds.tsx:559
#: src/view/screens/Feeds.tsx:560
msgid "Feed offline"
msgstr "フィードはオフラインです"
@@ -832,9 +832,9 @@ msgid "Feedback"
msgstr "フィードバック"
#: src/view/screens/Feeds.tsx:475
#: src/view/screens/Profile.tsx:164
#: src/view/screens/Profile.tsx:165
#: src/view/shell/bottom-bar/BottomBar.tsx:181
#: src/view/shell/desktop/LeftNav.tsx:339
#: src/view/shell/desktop/LeftNav.tsx:340
#: src/view/shell/Drawer.tsx:455
#: src/view/shell/Drawer.tsx:456
msgid "Feeds"
@@ -933,7 +933,7 @@ msgstr "はじめに"
#: src/view/com/auth/LoggedOut.tsx:81
#: src/view/com/auth/LoggedOut.tsx:82
#: src/view/com/util/moderation/ScreenHider.tsx:123
#: src/view/shell/desktop/LeftNav.tsx:103
#: src/view/shell/desktop/LeftNav.tsx:104
msgid "Go back"
msgstr "戻る"
@@ -993,7 +993,7 @@ msgid "Hmm, we're having trouble finding this feed. It may have been deleted."
msgstr "このフィードが見つからないようです。もしかしたら削除されたのかもしれません。"
#: src/view/shell/bottom-bar/BottomBar.tsx:137
#: src/view/shell/desktop/LeftNav.tsx:303
#: src/view/shell/desktop/LeftNav.tsx:304
#: src/view/shell/Drawer.tsx:379
#: src/view/shell/Drawer.tsx:380
msgid "Home"
@@ -1026,7 +1026,7 @@ msgstr "自分のドメインを持っています"
msgid "If none are selected, suitable for all ages."
msgstr "選択されていない場合は、すべての年齢に適しています。"
#: src/view/com/modals/AltImage.tsx:96
#: src/view/com/modals/AltImage.tsx:97
msgid "Image alt text"
msgstr "画像のALTテキスト"
@@ -1138,7 +1138,7 @@ msgstr "このフィードをいいね"
msgid "Liked by"
msgstr "いいねした人"
#: src/view/screens/Profile.tsx:163
#: src/view/screens/Profile.tsx:164
msgid "Likes"
msgstr "いいね"
@@ -1154,8 +1154,8 @@ msgstr "リストアバター"
msgid "List Name"
msgstr "リストの名前"
#: src/view/screens/Profile.tsx:165
#: src/view/shell/desktop/LeftNav.tsx:376
#: src/view/screens/Profile.tsx:166
#: src/view/shell/desktop/LeftNav.tsx:377
#: src/view/shell/Drawer.tsx:471
#: src/view/shell/Drawer.tsx:472
msgid "Lists"
@@ -1202,7 +1202,7 @@ msgstr "リストにないアカウントにログイン"
msgid "Make sure this is where you intend to go!"
msgstr "意図した場所であることを確認してください!"
#: src/view/screens/Profile.tsx:162
#: src/view/screens/Profile.tsx:163
msgid "Media"
msgstr "メディア"
@@ -1224,7 +1224,7 @@ msgstr "サーバーからのメッセージ"
#: src/view/screens/Moderation.tsx:64
#: src/view/screens/Settings.tsx:563
#: src/view/shell/desktop/LeftNav.tsx:394
#: src/view/shell/desktop/LeftNav.tsx:395
#: src/view/shell/Drawer.tsx:490
#: src/view/shell/Drawer.tsx:491
msgid "Moderation"
@@ -1292,7 +1292,7 @@ msgstr "誕生日"
msgid "My Feeds"
msgstr "マイフィード"
#: src/view/shell/desktop/LeftNav.tsx:64
#: src/view/shell/desktop/LeftNav.tsx:65
msgid "My Profile"
msgstr "マイプロフィール"
@@ -1315,16 +1315,16 @@ msgid "New"
msgstr "新規"
#: src/view/com/feeds/FeedPage.tsx:200
#: src/view/screens/Feeds.tsx:510
#: src/view/screens/Profile.tsx:353
#: src/view/screens/Feeds.tsx:511
#: src/view/screens/Profile.tsx:354
#: src/view/screens/ProfileFeed.tsx:430
#: src/view/screens/ProfileList.tsx:193
#: src/view/screens/ProfileList.tsx:221
#: src/view/shell/desktop/LeftNav.tsx:246
#: src/view/shell/desktop/LeftNav.tsx:247
msgid "New post"
msgstr "新しい投稿"
#: src/view/shell/desktop/LeftNav.tsx:256
#: src/view/shell/desktop/LeftNav.tsx:257
msgid "New Post"
msgstr "新しい投稿"
@@ -1388,7 +1388,7 @@ msgstr "注記:Blueskyはオープンでパブリックなネットワーク
#: src/view/screens/Notifications.tsx:109
#: src/view/screens/Notifications.tsx:133
#: src/view/shell/bottom-bar/BottomBar.tsx:205
#: src/view/shell/desktop/LeftNav.tsx:358
#: src/view/shell/desktop/LeftNav.tsx:359
#: src/view/shell/Drawer.tsx:416
#: src/view/shell/Drawer.tsx:417
msgid "Notifications"
@@ -1552,7 +1552,7 @@ msgstr "投稿の言語"
msgid "Post not found"
msgstr "投稿が見つかりません"
#: src/view/screens/Profile.tsx:160
#: src/view/screens/Profile.tsx:161
msgid "Posts"
msgstr "投稿"
@@ -1585,7 +1585,7 @@ msgid "Processing..."
msgstr "処理中..."
#: src/view/shell/bottom-bar/BottomBar.tsx:247
#: src/view/shell/desktop/LeftNav.tsx:412
#: src/view/shell/desktop/LeftNav.tsx:413
#: src/view/shell/Drawer.tsx:69
#: src/view/shell/Drawer.tsx:525
#: src/view/shell/Drawer.tsx:526
@@ -1672,7 +1672,7 @@ msgstr "保存したフィードからこのフィードを削除しますか?
msgid "Removed from list"
msgstr "リストから削除されました"
#: src/view/screens/Profile.tsx:161
#: src/view/screens/Profile.tsx:162
msgid "Replies"
msgstr "返信"
@@ -1760,7 +1760,7 @@ msgstr "設定の状態をリセット"
msgid "Retry"
msgstr "再試行"
#: src/view/com/modals/AltImage.tsx:114
#: src/view/com/modals/AltImage.tsx:115
#: src/view/com/modals/BirthDateSettings.tsx:93
#: src/view/com/modals/BirthDateSettings.tsx:96
#: src/view/com/modals/ChangeHandle.tsx:173
@@ -1770,7 +1770,7 @@ msgstr "再試行"
msgid "Save"
msgstr "保存"
#: src/view/com/modals/AltImage.tsx:105
#: src/view/com/modals/AltImage.tsx:106
msgid "Save alt text"
msgstr "ALTテキストを保存"
@@ -1795,7 +1795,7 @@ msgstr "保存されたフィード"
#: src/view/screens/Search/Search.tsx:401
#: src/view/screens/Search/Search.tsx:567
#: src/view/shell/bottom-bar/BottomBar.tsx:159
#: src/view/shell/desktop/LeftNav.tsx:321
#: src/view/shell/desktop/LeftNav.tsx:322
#: src/view/shell/desktop/Search.tsx:161
#: src/view/shell/desktop/Search.tsx:170
#: src/view/shell/Drawer.tsx:343
@@ -1890,7 +1890,7 @@ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your f
msgstr "保存されたフィードのサンプルを次のフィードに表示するには、この設定を「はい」にします。これは実験的な機能です。"
#: src/view/screens/Settings.tsx:277
#: src/view/shell/desktop/LeftNav.tsx:430
#: src/view/shell/desktop/LeftNav.tsx:431
#: src/view/shell/Drawer.tsx:546
#: src/view/shell/Drawer.tsx:547
msgid "Settings"
+7 -5
View File
@@ -287,15 +287,11 @@ export class Logger {
metadata: Metadata = {},
) {
if (!this.enabled) return
if (!enabledLogLevels[this.level].includes(level)) return
const timestamp = Date.now()
const meta = metadata || {}
for (const transport of this.transports) {
transport(level, message, meta, timestamp)
}
// send every log to syslog
add({
id: nanoid(),
timestamp,
@@ -303,6 +299,12 @@ export class Logger {
message,
metadata: meta,
})
if (!enabledLogLevels[this.level].includes(level)) return
for (const transport of this.transports) {
transport(level, message, meta, timestamp)
}
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ let entries: ConsoleTransportEntry[] = []
export function add(entry: ConsoleTransportEntry) {
entries.unshift(entry)
entries = entries.slice(0, 50)
entries = entries.slice(0, 500)
}
export function getEntries() {
@@ -6,22 +6,28 @@ import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {AppBskyEmbedExternal} from '@atproto/api'
import {toNiceDomain} from 'lib/strings/url-helpers'
import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player'
import {ExternalPlayer} from 'view/com/util/post-embeds/ExternalPlayerEmbed'
export const ExternalLinkEmbed = ({
link,
imageChild,
}: {
link: AppBskyEmbedExternal.ViewExternal
imageChild?: React.ReactNode
}) => {
const pal = usePalette('default')
const {isMobile} = useWebMediaQueries()
const embedPlayerParams = React.useMemo(
() => parseEmbedPlayerFromUrl(link.uri),
[link.uri],
)
return (
<View
style={{
flexDirection: isMobile ? 'column' : 'row',
flexDirection: !isMobile && !embedPlayerParams ? 'row' : 'column',
}}>
{link.thumb ? (
{link.thumb && !embedPlayerParams ? (
<View
style={
!isMobile
@@ -45,9 +51,11 @@ export const ExternalLinkEmbed = ({
source={{uri: link.thumb}}
accessibilityIgnoresInvertColors
/>
{imageChild}
</View>
) : undefined}
{embedPlayerParams && (
<ExternalPlayer link={link} params={embedPlayerParams} />
)}
<View
style={{
paddingHorizontal: isMobile ? 10 : 14,
@@ -0,0 +1,251 @@
import React from 'react'
import {
ActivityIndicator,
Dimensions,
GestureResponderEvent,
Pressable,
StyleSheet,
View,
} from 'react-native'
import {Image} from 'expo-image'
import {WebView} from 'react-native-webview'
import YoutubePlayer from 'react-native-youtube-iframe'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {EmbedPlayerParams, getPlayerHeight} from 'lib/strings/embed-player'
import {EventStopper} from '../EventStopper'
import {AppBskyEmbedExternal} from '@atproto/api'
import {isNative} from 'platform/detection'
import {useNavigation} from '@react-navigation/native'
import {NavigationProp} from 'lib/routes/types'
interface ShouldStartLoadRequest {
url: string
}
// This renders the overlay when the player is either inactive or loading as a separate layer
function PlaceholderOverlay({
isLoading,
isPlayerActive,
onPress,
}: {
isLoading: boolean
isPlayerActive: boolean
onPress: (event: GestureResponderEvent) => void
}) {
// If the player is active and not loading, we don't want to show the overlay.
if (isPlayerActive && !isLoading) return null
return (
<View style={[styles.layer, styles.overlayLayer]}>
<Pressable
accessibilityRole="button"
accessibilityLabel="Play Video"
accessibilityHint=""
onPress={onPress}
style={[styles.overlayContainer, styles.topRadius]}>
{!isPlayerActive ? (
<FontAwesomeIcon icon="play" size={42} color="white" />
) : (
<ActivityIndicator size="large" color="white" />
)}
</Pressable>
</View>
)
}
// This renders the webview/youtube player as a separate layer
function Player({
height,
params,
onLoad,
isPlayerActive,
}: {
isPlayerActive: boolean
params: EmbedPlayerParams
height: number
onLoad: () => void
}) {
// ensures we only load what's requested
const onShouldStartLoadWithRequest = React.useCallback(
(event: ShouldStartLoadRequest) => event.url === params.playerUri,
[params.playerUri],
)
// Don't show the player until it is active
if (!isPlayerActive) return null
return (
<View style={[styles.layer, styles.playerLayer]}>
<EventStopper>
{isNative && params.type === 'youtube_video' ? (
<YoutubePlayer
videoId={params.videoId}
play
height={height}
onReady={onLoad}
webViewStyle={[styles.webview, styles.topRadius]}
/>
) : (
<View style={{height, width: '100%'}}>
<WebView
javaScriptEnabled={true}
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
mediaPlaybackRequiresUserAction={false}
allowsInlineMediaPlayback
bounces={false}
allowsFullscreenVideo
nestedScrollEnabled
source={{uri: params.playerUri}}
onLoad={onLoad}
setSupportMultipleWindows={false} // Prevent any redirects from opening a new window (ads)
style={[styles.webview, styles.topRadius]}
/>
</View>
)}
</EventStopper>
</View>
)
}
// This renders the player area and handles the logic for when to show the player and when to show the overlay
export function ExternalPlayer({
link,
params,
}: {
link: AppBskyEmbedExternal.ViewExternal
params: EmbedPlayerParams
}) {
const navigation = useNavigation<NavigationProp>()
const [isPlayerActive, setPlayerActive] = React.useState(false)
const [isLoading, setIsLoading] = React.useState(true)
const [dim, setDim] = React.useState({
width: 0,
height: 0,
})
const viewRef = React.useRef<View>(null)
// watch for leaving the viewport due to scrolling
React.useEffect(() => {
// Interval for scrolling works in most cases, However, for twitch embeds, if we navigate away from the screen the webview will
// continue playing. We need to watch for the blur event
const unsubscribe = navigation.addListener('blur', () => {
setPlayerActive(false)
})
const interval = setInterval(() => {
viewRef.current?.measure((x, y, w, h, pageX, pageY) => {
const window = Dimensions.get('window')
const top = pageY
const bot = pageY + h
const isVisible = isNative
? top >= 0 && bot <= window.height
: !(top >= window.height || bot <= 0)
if (!isVisible) {
setPlayerActive(false)
}
})
}, 1e3)
return () => {
unsubscribe()
clearInterval(interval)
}
}, [viewRef, navigation])
// calculate height for the player and the screen size
const height = React.useMemo(
() =>
getPlayerHeight({
type: params.type,
width: dim.width,
hasThumb: !!link.thumb,
}),
[params.type, dim.width, link.thumb],
)
const onLoad = React.useCallback(() => {
setIsLoading(false)
}, [])
const onPlayPress = React.useCallback((event: GestureResponderEvent) => {
// Prevent this from propagating upward on web
event.preventDefault()
setPlayerActive(true)
}, [])
// measure the layout to set sizing
const onLayout = React.useCallback(
(event: {nativeEvent: {layout: {width: any; height: any}}}) => {
setDim({
width: event.nativeEvent.layout.width,
height: event.nativeEvent.layout.height,
})
},
[],
)
return (
<View
ref={viewRef}
style={{height}}
collapsable={false}
onLayout={onLayout}>
{link.thumb && (!isPlayerActive || isLoading) && (
<Image
style={[
{
width: dim.width,
height,
},
styles.topRadius,
]}
source={{uri: link.thumb}}
accessibilityIgnoresInvertColors
/>
)}
<PlaceholderOverlay
isLoading={isLoading}
isPlayerActive={isPlayerActive}
onPress={onPlayPress}
/>
<Player
isPlayerActive={isPlayerActive}
params={params}
height={height}
onLoad={onLoad}
/>
</View>
)
}
const styles = StyleSheet.create({
topRadius: {
borderTopLeftRadius: 6,
borderTopRightRadius: 6,
},
layer: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
},
overlayContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.5)',
},
overlayLayer: {
zIndex: 2,
},
playerLayer: {
zIndex: 3,
},
webview: {
backgroundColor: 'transparent',
},
})
@@ -1,55 +0,0 @@
import React from 'react'
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
import {usePalette} from 'lib/hooks/usePalette'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {ExternalLinkEmbed} from './ExternalLinkEmbed'
import {AppBskyEmbedExternal} from '@atproto/api'
import {Link} from '../Link'
export const YoutubeEmbed = ({
link,
style,
}: {
link: AppBskyEmbedExternal.ViewExternal
style?: StyleProp<ViewStyle>
}) => {
const pal = usePalette('default')
const imageChild = (
<View style={styles.playButton}>
<FontAwesomeIcon icon="play" size={24} color="white" />
</View>
)
return (
<Link
asAnchor
style={[styles.extOuter, pal.view, pal.border, style]}
href={link.uri}>
<ExternalLinkEmbed link={link} imageChild={imageChild} />
</Link>
)
}
const styles = StyleSheet.create({
extOuter: {
borderWidth: 1,
borderRadius: 8,
},
playButton: {
position: 'absolute',
alignSelf: 'center',
alignItems: 'center',
top: '44%',
justifyContent: 'center',
backgroundColor: 'black',
padding: 10,
borderRadius: 50,
opacity: 0.8,
},
webView: {
alignItems: 'center',
alignContent: 'center',
justifyContent: 'center',
},
})
+5 -13
View File
@@ -23,9 +23,7 @@ import {ImageLayoutGrid} from '../images/ImageLayoutGrid'
import {useLightboxControls, ImagesLightbox} from '#/state/lightbox'
import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {YoutubeEmbed} from './YoutubeEmbed'
import {ExternalLinkEmbed} from './ExternalLinkEmbed'
import {getYoutubeVideoId} from 'lib/strings/url-helpers'
import {MaybeQuoteEmbed} from './QuoteEmbed'
import {AutoSizedImage} from '../images/AutoSizedImage'
import {ListEmbed} from './ListEmbed'
@@ -168,19 +166,13 @@ export function PostEmbeds({
// =
if (AppBskyEmbedExternal.isView(embed)) {
const link = embed.external
const youtubeVideoId = getYoutubeVideoId(link.uri)
if (youtubeVideoId) {
return <YoutubeEmbed link={link} style={style} />
}
return (
<Link
asAnchor
style={[styles.extOuter, pal.view, pal.border, style]}
href={link.uri}>
<ExternalLinkEmbed link={link} />
</Link>
<View style={[styles.extOuter, pal.view, pal.border, style]}>
<Link asAnchor href={link.uri}>
<ExternalLinkEmbed link={link} />
</Link>
</View>
)
}
+45 -11
View File
@@ -10433,16 +10433,16 @@ escape-html@~1.0.3:
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
escape-string-regexp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
@@ -12501,7 +12501,7 @@ interpret@^3.1.1:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4"
integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==
invariant@*, invariant@^2.2.4:
invariant@*, invariant@2.2.4, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@@ -17330,6 +17330,13 @@ qs@6.11.0:
dependencies:
side-channel "^1.0.4"
qs@^6.5.1:
version "6.11.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==
dependencies:
side-channel "^1.0.4"
query-string@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328"
@@ -17535,12 +17542,12 @@ react-native-dotenv@^3.3.1:
dependencies:
dotenv "^16.3.1"
react-native-drawer-layout@^3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/react-native-drawer-layout/-/react-native-drawer-layout-3.2.1.tgz#eb626216181965e72de6d9377ca619fab40226f2"
integrity sha512-9GDzSLBblxox1zEACcbdXHMU8m22gCTdpT9g1G3Za4Bu766IDxVnIbgRGz6Z2dL99EMtz5E2JoWx257tdHkbpw==
react-native-drawer-layout@^4.0.0-alpha.3:
version "4.0.0-alpha.3"
resolved "https://registry.yarnpkg.com/react-native-drawer-layout/-/react-native-drawer-layout-4.0.0-alpha.3.tgz#0adf51e816f2ce094d415fe33d9f43c1e6df6ae2"
integrity sha512-BRlX8l2gDD41fs8RfaemjDBDV0PPspDMvej/3b9QWfp+JQ/H8tkSdWBtUBbSBzYdqyqy2bHV4epOCMb4t+0B0g==
dependencies:
use-latest-callback "^0.1.5"
use-latest-callback "^0.1.9"
react-native-fs@^2.20.0:
version "2.20.0"
@@ -17680,6 +17687,13 @@ react-native-web-linear-gradient@^1.1.2:
resolved "https://registry.yarnpkg.com/react-native-web-linear-gradient/-/react-native-web-linear-gradient-1.1.2.tgz#33f85f7085a0bb5ffa5106faf02ed105b92a9ed7"
integrity sha512-SmUnpwT49CEe78pXvIvYf72Es8Pv+ZYKCnEOgb2zAKpEUDMo0+xElfRJhwt5nfI8krJ5WbFPKnoDgD0uUjAN1A==
react-native-web-webview@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-native-web-webview/-/react-native-web-webview-1.0.2.tgz#c215efa70c17589f2c8d640b1f1dc669b18c6e02"
integrity sha512-oNAYNuqUqeqTuAAdIejzDqvUtYA+k5lrvhUYmASdUznZNmyIaoQFA6OKoA4K9F3wdMvark42vUXkUWIp875ewg==
dependencies:
qs "^6.5.1"
react-native-web@~0.19.6:
version "0.19.8"
resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.19.8.tgz#46127f8b310148fde11e4fef67fe625603599d47"
@@ -17694,6 +17708,21 @@ react-native-web@~0.19.6:
postcss-value-parser "^4.2.0"
styleq "^0.1.3"
react-native-webview@^13.6.2:
version "13.6.2"
resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-13.6.2.tgz#0a9b18793e915add5b5dbdbf32509d7751b49167"
integrity sha512-QzhQ5JCU+Nf2W285DtvCZOVQy/MkJXMwNDYPZvOWQbAOgxJMSSO+BtqXTMA1UPugDsko6PxJ0TxSlUwIwJijDg==
dependencies:
escape-string-regexp "2.0.0"
invariant "2.2.4"
react-native-youtube-iframe@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/react-native-youtube-iframe/-/react-native-youtube-iframe-2.3.0.tgz#40ca8e55db929b91bfa8e8d30e411658cbc304c5"
integrity sha512-M+z63xwXVtS4dX3k8PbtHUUcWN+gRZt6J1EtPE7Y60BMOB979KjpkdrHqeR96or9pNR2W8K5tQhIkMXW2jwo7Q==
dependencies:
events "^3.2.0"
react-native@0.72.5:
version "0.72.5"
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.72.5.tgz#2c343fa6f3ead362cf07376634a33a4078864357"
@@ -20142,6 +20171,11 @@ use-latest-callback@^0.1.5:
resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.1.6.tgz#3fa6e7babbb5f9bfa24b5094b22939e1e92ebcf6"
integrity sha512-VO/P91A/PmKH9bcN9a7O3duSuxe6M14ZoYXgA6a8dab8doWNdhiIHzEkX/jFeTTRBsX0Ubk6nG4q2NIjNsj+bg==
use-latest-callback@^0.1.9:
version "0.1.9"
resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.1.9.tgz#10191dc54257e65a8e52322127643a8940271e2a"
integrity sha512-CL/29uS74AwreI/f2oz2hLTW7ZqVeV5+gxFeGudzQrgkCytrHw33G4KbnQOrRlAEzzAFXi7dDLMC9zhWcVpzmw==
use-sidecar@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"