Compare commits

...

185 Commits

Author SHA1 Message Date
Dan Abramov f4e7dcae46 gestures setup 2025-01-10 18:30:21 +00:00
dan 6ca97406c1 A simpler fix for trending swipe issue (#7424) 2025-01-10 18:06:07 +00:00
Samuel Newman a7da646286 [ELI5] Validate too long handles in signup (#7422)
* validate too long handles in signup

* make change handle screen generic
2025-01-10 17:57:10 +00:00
Hailey d79c66af8a add back statsig gate testing (#7404) 2025-01-10 09:45:58 -08:00
dan 02dbcc134e Fix trending swipe gesture (#7417) 2025-01-10 00:32:08 +00:00
Eric Bailey 72dc508cb7 Move intent dialogs inside Alf, but above intent handlers (#7416) 2025-01-09 15:34:00 -06:00
Samuel Newman 3b9a51c43f Fix Android composer padding: Director's Cut (#7412)
* fix android 15 composer padding

* while I'm here, alf some bits and pieces

* add comments
2025-01-09 18:06:24 +00:00
Samuel Newman e5c587450f fix padding on android 15 (#7411) 2025-01-09 17:29:33 +00:00
Samuel Newman b49e93d58f Downgrade paste input dependency (#7410)
* downgrade paste input

* rm wnitespace
2025-01-09 16:47:37 +00:00
Samuel Newman d10cbb8f42 Fix avatar shape in Account switch menu (#7388) 2025-01-09 00:19:59 +00:00
Samuel Newman a0393fcd48 [ELI5] change sign in to create account (#6931)
* change sign in to create account

* alf buttons on native bottom bar

* manually edit .po file
2025-01-08 22:13:24 +00:00
Samuel Newman 7c8c78b18f [ELI5] Tweaks to hosting provider (#6935)
* minimal hosting provider

* change wording and move back up

* first time user nudge

* move tip

* reexport ticket svg

* fix ticket fr this time

* text tweak + add minHeight
2025-01-08 19:22:04 +00:00
dan 40ab77781c Delete <AppProfiler> (#7403) 2025-01-08 18:59:39 +00:00
Christian Schmidt aa3d8c5230 Preconnect to public.api.bsky.app (#7396) 2025-01-08 17:21:21 +00:00
Roland Crosby c564981405 Add key to invalidate spinner when theme changes (#7351) 2025-01-08 00:13:03 +00:00
Samuel Newman f61390fdf4 Hide menu button when search is focused (#7373)
* hide menu btn when cancel is shown

* remove useless ts-ignores
2025-01-07 22:21:58 +00:00
dan f3229d554b Bump version to 1.97.0 (#7386) 2025-01-07 21:14:14 +00:00
Dan Abramov 89353c6f22 Remove unused default argument 2025-01-07 21:07:06 +00:00
Jonathan Herbert cdd7d040b9 Fix moveToPermanentPath ext Default Missing '.' (#7281) 2025-01-07 19:13:01 +00:00
Samuel Newman fe8d3b081c Fix double text input in composer (#7381)
* upgrade paste input

* override how backing uitextinput is created

* different approach
2025-01-07 18:29:27 +00:00
Hailey 615bbc3532 bump version (#7337) 2025-01-02 16:10:34 -08:00
bnewbold 59709ad8d8 bump golang version to v1.23 (#7325) 2025-01-02 12:57:03 -08:00
dan 85ad52e398 Add loading state to new trending interstitial (#7332) 2025-01-02 20:20:40 +00:00
dan 3e0ed3b834 Remove upstreamed drawer patch (#7331)
* Remove upstreamed drawer patch

* Bump more
2025-01-02 20:20:30 +00:00
dan c11a90124c Fix key issue in trending topics (#7329) 2025-01-02 17:27:15 +00:00
Stanislas Signoud 9f075b1340 Localize lang selectors according to the app language (#6207)
* Localize lang selectors according to the app language

* Explicitly ignore RangeError when translating locale names
2024-12-31 13:27:14 -08:00
Paul Frazee 09297d92cb Release 1.96.3 (#7318)
* Run intl extract

* 1.96.3
2024-12-31 13:06:33 -08:00
Yiannis Mertzanis 2300410b4d Add Greek Language ('el') Support and Internationalization (#6677)
* Add Greek language support to the application

* Add support for Greek language in date handling and tests

* Update Greek locale file with translator and team information

* Add support for Greek language in date handling and tests

* Add support for Greek language in app configuration, and updated translation from the reviewers' comments

* Update src/locale/i18n.ts

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update src/locale/i18n.ts

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2024-12-31 12:28:17 -08:00
f e l p s 30d110dbcd PT-BR Translation update (#6975)
* PT-BR Translation update to 1.95.0

* PT-BR Translation update to 1.95.0

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2024-12-31 12:25:42 -08:00
Virenbar af94b79e2c Update Russian localization (#7116)
* Update messages.po

* Update messages.po

* Update messages.po (е -> ё)

* Update messages.po (plurals)

* Update messages.po

* Update messages.po

More е -> ё
Fix some strings

* Update messages.po

* Update messages.po

* Update messages.po (draft)

* Update messages.po

* Update messages.po

* Update messages.po

---------

Co-authored-by: ponfertato <ponfertato@ya.ru>
2024-12-31 12:20:38 -08:00
Takayuki KUSANO 6e94de9f83 Update Japanese translation (#7170)
* Update translation

* Update translation
2024-12-31 12:20:01 -08:00
Minseo Lee 9dc04bbfb0 Update Korean localization (#7171)
* Update messages.po

* Update messages.po

* Update src/locale/locales/ko/messages.po

Co-authored-by: Akamig <akamig@posteo.net>

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

---------

Co-authored-by: Akamig <akamig@posteo.net>
2024-12-31 12:19:43 -08:00
Ivan Beà eb3bfc9ff0 Update catalan messages.po for 1.96.0 (#7182)
* Update catalan messages.po

Ready for 1.96.0
Please take a look at it @jordimas @darccio @surfdude29 @rortan134 @magarcia @aryiu

* Update messages.po

Tema del moment per Trending Topic segons optimot https://aplicacions.llengua.gencat.cat/llc/AppJava/index.html;jsessionid=43E324EDAEFCD750A95579FEB9B5A164?action=Principal&method=detall&input_cercar=trending+topic&numPagina=1&database=TERMCAT&idFont=3279826&idHit=3279826&tipusFont=Diccionaris+terminol%F2gics+del+TERMCAT&numeroResultat=8&databases_avansada=&categories_avansada=&clickLink=detall&titol=tema+del+moment&tematica=Tecnologies+de+la+informaci%F3+i+la+comunicaci%F3&t%C3%ADtol=tema%20del%20moment&tipusCerca=cerca.tot
2024-12-31 12:19:22 -08:00
Valtteri Laitinen ad42a9297a Update Finnish localization (#7183)
* Remove obsolete Finnish strings

* Update and adjust Finnish locale
2024-12-31 12:18:43 -08:00
Michele Locati 97288983c3 Update Italian translations (#7184)
* Update po from Transifex

* Update Italian translations

* Update Italian translations

* Update Italian translations

* Update Italian translations

* Update Italian translations

* Update Italian translations

* Update Italian translations

---------

Co-authored-by: GitHub <noreply@github.com>
2024-12-31 12:18:16 -08:00
voitech 0118fe75e0 Update Polish translation (#7206)
Translated new strings and corrected various errors.
2024-12-31 12:16:18 -08:00
smileyhead e44726529c Update Hungarian translation for 1.96 (#7219)
* Update Hungarian translation for 1.96

* Update Hungarian translation
2024-12-31 11:40:12 -08:00
Gerson Lázaro 619da81911 Fix Spanish translations for some messages (#7233)
* Fix Spanish translations for some messages

* Fix minor issues in es localization
- Use "etiqueta" instead of "tag"
- Use "eliminar" instead of "remover"
- Unify "entrar en pantalla completa"
- Use "Clic" instead of "Click"
- Use "paquete de inicio" instead of "pack de inicio"
- Unify use of "trasladado" instead of "mudado"
- Unify use of "solo" instead of "sólo"
- Unify use of "feed" instead of "noticias"
- Unify use of quotes for "me gusta" as "likes"
- Improve sentences using "2FA"
- Unify sentences mentioning quote posts (citas)
- Other small inconsistencies
- Tú vs usted inconsistencies:
  - agregue -> agrega
  - inténtelo -> inténtalo
  - cierre -> cierra
  - su -> tu
  - complete -> completa
  - comience -> comienza
  - seleccionaba -> seleccionabas
  - intentaba -> intentabas
  - puede -> puedes
- Inconsistencies to discuss and solve
  - Post: use of "post" and "publicación"
  - Repost: use of "repost"/"repostear" and "republicación"/"republicar"
  - Add: use of "agregar"/"agrega" and "añadir"/"añade"
  - Feed: use of Feeds in uppercase
  - Video: use of vídeo (es-ES) or video
  - User and account ("usuario" and "cuenta")
  - Punctuation consistency
  - Uppercase and lowercase consistency

* Fix typos and improve Spanish localization in messages.po

---------

Co-authored-by: Daniel García Ruano <dgruano.code@gmail.com>
2024-12-31 11:36:33 -08:00
Frudrax Cheng cf1ccdf8e3 Update Chinese & Cantonese localization (#7235)
* Update translates from crowdin

* Convert language codes from RFC-1766 to RFC-4646

* Update translates from crowdin

* Update deviceLocales.ts

* Revert 'changes zh-HK to yue'

* Fix zh-HK messages.po

* Revert 'en/messages.po'

* Update deviceLocales.ts

* Revert code comments

* Update translates from crowdin

* zh-TW: Improved translations
2024-12-31 11:34:48 -08:00
Stanislas Signoud 444c4a944e Update French translation (1.96.3 or 1.97) (#7299)
* Bump locales in French

* Translate French strings for 1.97 (or 1.96.3)
2024-12-31 11:30:49 -08:00
Lucasofchirstms 8af540f284 Update messages.po (#7305) 2024-12-31 11:27:56 -08:00
Hailey 6c40efb3a3 change copy on list blocked (#7316) 2024-12-31 11:24:50 -08:00
Paul Frazee 2dc6932f29 Rework discover-feed trending interstitial (#7314)
* Rework discover-feed trending interstitial to take one row

* Fix loading state

* Try putting it at the top

* Color consistency

* Tweak some spacing

* Show trending when progress guide is there
2024-12-31 09:44:52 -08:00
Eric Bailey c6d26a0a9c Some metrics (#7294)
* Add trending metrics

* Progress guide events

* Fix naming, improve existing events
2024-12-27 14:21:17 -08:00
Eric Bailey 8b7a331815 Fix mute words in trending (#7293) 2024-12-27 14:19:02 -08:00
Hailey d27ed32188 bump video version, fix android crash (#7292) 2024-12-27 13:10:01 -08:00
Samuel Newman 6c9e1d4837 Unlock orientation when lightbox is open (#7257)
* unlock orientation when lightbox is open

* rm outer safe area view, make sure alt text is safe

* restore safe area view for android 14 and below

* lock orientation on launch for android

* set system ui background to black when lightbox is open

* reset state on relayout

* catch async functions with noops

* rm superfluous catches

* Delay unlock until after animation

* Simplify how key is determined

* Make landscape backdrop opaque

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-12-24 20:05:54 +00:00
Minseo Lee f05962a492 Fix Nepali language code (#7265)
* Replace `np` with `ne`

* Reorder
2024-12-24 16:54:05 +00:00
Samuel Newman 2b28c85b43 Cropper - opt out of edge-to-edge enforcement on Android 15 (#7254)
* opt out of edge-to-edge enforcement

* revert unintended change
2024-12-23 18:17:09 +00:00
Ahmed Soliman 1e4ea1a271 checking list/feed owner on empty state when prompting to add users (#7247) 2024-12-23 17:42:10 +00:00
Barry Pollard 08a5f7a0bd Correct font preload (#7249) 2024-12-23 17:41:00 +00:00
Samuel Newman 5020e4233a make horizontal scrollview touch edges (#7256) 2024-12-23 15:58:54 +00:00
Christian Schmidt 190c7d6ed8 Extend clickable area to height of container (#7248) 2024-12-23 15:12:38 +00:00
Christian Schmidt 9d4ae02300 Make "Retry" translatable (#7243) 2024-12-22 17:45:08 +00:00
Christian Schmidt fa2072cefa Apply avatar moderation to quote post (#7229) 2024-12-20 23:15:45 +00:00
Dan Abramov 3aa1a5f884 Bump 2024-12-20 21:34:10 +00:00
Dan Abramov 7d86bba7f1 Fix Android save to camera permissions 2024-12-20 21:34:10 +00:00
Samuel Newman f5a9ac1313 fix lightbox on android 15 (#7221) 2024-12-20 20:39:18 +00:00
Samuel Newman c5421596a8 fix recent searches tap handling (#7214) 2024-12-20 20:37:55 +00:00
Samuel Newman 8f7a6e5ffc add default empty state text (#7212) 2024-12-20 20:33:34 +00:00
Hailey aeb78daf84 bump package (#7223) 2024-12-20 20:15:21 +00:00
Eric Bailey 8116d12c15 Fix Emoji picker focus (#7217)
* Only portal the emoji picker where needed

* Add optional portal prop to emoji picker

* Use FocusScope to our advantage

* Pare back, add guards, fix focus trap

* Don't return focus to emoji button

* Set DM input position on emoji insert

* Let the caller determine next focus node

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-12-20 19:59:33 +00:00
dan 8a3dfcb9d0 Don't add unused keydown listeners (#7218) 2024-12-20 18:00:30 +00:00
Samuel Newman 6afa44ddcb Moderate composer quote (#7213)
* moderate composer quote

* consistency with other uses
2024-12-20 16:57:19 +00:00
dan ab0697a0ec Bump clamp max value (#7198) 2024-12-19 23:14:33 +00:00
Dan Abramov 7f63679a5e Fix build 2024-12-19 21:57:45 +00:00
Hailey 975e61d450 bump (#7197) 2024-12-19 13:51:18 -08:00
dan 10981eec50 Proper fix for iOS cropper being stuck (#7194)
* Revert "Add iOS hack to fix cropper failing to show (#7191)"

This reverts commit 25d20c6395.

* Proper fix
2024-12-19 21:47:00 +00:00
dan fb920f89d1 Revert "Fix post time localization on Android (#6742)" (#7196)
This reverts commit b1b6affb71.
2024-12-19 21:45:44 +00:00
dan 25d20c6395 Add iOS hack to fix cropper failing to show (#7191)
* Add iOS hack to fix cropper failing to show

* Make it 800
2024-12-19 21:12:58 +00:00
Dan Abramov a3031de19b Tweak GH action 2024-12-19 05:50:37 +00:00
Dan Abramov 59739a6088 Tweak GH action 2024-12-19 05:36:19 +00:00
Dan Abramov 24540400d9 Try to fix action 2024-12-19 05:24:05 +00:00
Dan Abramov 513a188a21 Add a GitHub Action verifying lockfile against base 2024-12-19 05:14:15 +00:00
dan 29dad38ab7 Add lockfile lint (#7177) 2024-12-19 04:01:21 +00:00
dan c390c32788 Remove unreliable repository (#7176) 2024-12-19 04:00:27 +00:00
dan c2ca84c636 Temporarily remove Bitdrift (#7173)
* Temporarily remove Bitdrift

* Rm plugin
2024-12-19 01:16:32 +00:00
Paul Frazee e2dfe3f438 Fix translation file 2024-12-18 17:07:41 -08:00
Hailey 9ebd362224 add key (#7169) 2024-12-18 16:17:55 -08:00
Paul Frazee 25f3aeaa08 Release 1.96.0 (#7168)
* Update test

* Run intl extract

* Update join count
2024-12-18 15:56:42 -08:00
Mert Şişmanoğlu 6e58a1e8e1 Update Turkish(tr) translations 62% (#6386)
* Update Turkish(tr) translations

* Update Turkish(tr) translations

- Accessibility Page fully translated
- Some error and warning messages
- Some PostInteraction components

* Update Turkish(tr) translations

- Po-Revision-Date, Last-Translator, Language-Team update
- Translate most of the Chat, Message, Conversation messages

* Update Turkish(tr) translations

- useTimeAgo time conventions
- FeedItem messages
- Verification warnings

* Update Turkish(tr) translations

- n days ago, n hours ago
- Newskie
- Post and Feed actions
- Some of the Starter Pack

* Update Turkish(tr) translations

- Use `kaydoldu` instead of `kayıt oldu`

* Fix typo "{}sn" in Turkish(tr) translations

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* fix turkish(tr) translations 'reply' word

- Use 'yanıt' instead of 'cevap'

* Update src/locale/locales/tr/messages.po

Co-authored-by: Burak Güner <md.burak.guner@gmail.com>

* Update Turkish(tr) translations for improved clarity and accuracy

* Update Turkish(tr) translations

* Update Turkish(tr) translations for various phrases and improve clarity

- learn more
- moderation things

* Update Turkish(tr) translations

* Update Turkish(tr) translations

* Update Turkish(tr) translations

* Update src/locale/locales/tr/messages.po

Co-authored-by: Burak Güner <md.burak.guner@gmail.com>

* Update src/locale/locales/tr/messages.po

Co-authored-by: Burak Güner <md.burak.guner@gmail.com>

* Update Turkish (tr) translations in messages.po

%62 done

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Burak Güner <md.burak.guner@gmail.com>
2024-12-18 15:47:26 -08:00
Softastur 62f43ee15a Update ast locale translation (#6905)
* Update ast locale translation

This commit updates strings and fixes some errors.

* Update messages.po

Fixes a critical translation error

* Update messages.po

Fixed a mistake

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2024-12-18 15:46:50 -08:00
smileyhead 2e598f7bd7 Update Hungarian translation to 1.95 (#6869)
* Fetch newest translations

* Translate new strings

* Apply fixes to strings

Reworded the ‘Deleted’ string and the body text placeholders of the ‘Who can interact with this post?’ dialogue.

* Unify wording/cases of toast messages

The wording of responsive toasts such as ‘Message deleted’ have all been changed to a case like ‘You have deleted this message’. Wording messages in the former way sounds very ‘un-Hungarian,’ so I have gone through the code to find any toast messages not worded this way.

There are a few exceptions, however:
- Error messages – these are already proper, full sentences and do not sound odd when translated as-is.
- ‘Copied to clipboard’, QR code-related toasts – keeping the original case sounded more appropriate here.

* Small correction

Noticed I've accidentally translated ‘About’ as ‘Help’

* Pull newest strings

* Translate new strings
2024-12-18 15:45:55 -08:00
Juan Pablo Martínez 2aeb098b4e Update AN to 1.95.0 [ER]. (#6857)
Co-authored-by: Guido Leenders <guido.leenders@invantive.com>
2024-12-18 15:44:04 -08:00
Guido Leenders 1eb17ac9fa Update NL to 1.95.0 [ER]. (#6855) 2024-12-18 15:43:04 -08:00
Eric Bailey 3408d47a1b Remove deactivate dialog link from delete modal (#7167)
* Rm closeModal

* rm link
2024-12-18 23:42:02 +00:00
Luan 64dbaed24c Update Portuguese localization (#6793)
* Update messages.po

* Update messages.po
2024-12-18 15:35:26 -08:00
Ankit Bhandari bdae89b67b Nepali Translation (divyaswormakai's reviewed & some changes) (#7033)
* feat: prepare necesaary files

* fix: message file for nepali translation

* feat: language file update

* feat: add missing pieces

* feat: one and other updates

* additional changes

---------

Co-authored-by: Divyaswor Makai <makaidivya@gmail.com>
2024-12-18 15:34:50 -08:00
Stanislas Signoud 0e7ad19830 French translations (for v1.96) (#6991)
* Bump translation strings for fr

* Translate new strings in French

* Fix a few problems and typos in existing fr locale

- Archivé par followed by a date do not make sense
- l’arrive is clearly a typo, and I rewrote it so it feels better in French
- Ex. with this casing is not frequent, so I moved it at the end (no terseness required here)
- Feedback is now translated using a common translation of those in other UIs
- Removed "Les" in "Les mots" as it's a menu item
- Plus aucune is correct but too formal and weird so switching to Pas d’autre

* Remove all legacy, commented strings

* Use guillemets on fr string about app icons

* Fix translation of “Back” to “Retour” in french

Originally fixed by @lsaudon in #6778, thanks :)

Co-authored-by: Lucas SAUDON <lucas.saudon@beta.gouv.fr>

* Improve fr translations thanks to @CerryTsuki input

* Remove even more legacy strings in fr translations

* Bump translation strings for fr (again)

* Attempt to translate new strings in fr

* Improve 'Archived from' translation in fr

* Bump translation strings for fr (yet again)

* Translate new strings in French

* Get rid of recently removed strings in fr

* Stay consistent when translating handle

---------

Co-authored-by: Lucas SAUDON <lucas.saudon@beta.gouv.fr>
2024-12-18 15:34:06 -08:00
Lucas O. S. c9aa2b1e30 Fix spanish translation (#6984) 2024-12-18 15:33:38 -08:00
roth 323c974c6b Add Khmer Localization (#6914)
* add khmer language

* update translate

* update translate

* add missing localization key

* update khmer wording

* update khmer wording

* add missing translate

* add missing translate

* chore: add khmer local date-time format

* Update src/locale/i18n.ts

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2024-12-18 15:33:19 -08:00
voitech 9b35521d3c Updated Polish translation (#6862)
* Updated Polish translation

* Update pl/messages.po

@axiand Thanks for such a detailed analysis and all the suggestions! I've already corrected the mistakes you pointed out.

- The word "repost" was initially translated as "opublikować ponownie," but after consulting members of the Polish community, they agreed that "repostować" would be more appropriate. Personally, I would leave it as is or change it to "opublikować ponownie," but that is a longer phrase and might not fit well in certain interface elements.  
- Similarly, with the word "czat"—in my opinion, it aligns better with the app, whereas I translated "conversation" as "rozmowa."  
- "Obserwować wzajemnie" doesn't sound very natural in Polish, which was even noted by users who reverted to the English interface because of it. The phrases "również Cię obserwuje" and "również obserwuj" fully capture the meaning of the English original and look good as notifications in the app.  
- `L414-440`, `1618` – without the word "zostało," the phrasing lacks clarity.  
- `L600`, `1796`, `2804`, `4056`, `7552` and `L718`, `1316`, `2219`, `4662-4667`, `6056`, `6714` – my changes are linguistically correct and look better. The previous formulations were often ambiguous and unclear. I fixed the errors found in these sections.  
- `L1447` – I reverted to the previous version.  
- I changed "kod potwierdzający" to "kod weryfikacyjny" because it sounds more natural and clear.  
- I changed "lista moderowana" to "lista moderacji" as per your suggestion. In Polish, "lista moderacji" sounds like the list belongs to people involved in moderation. It also gives the impression that it might be a list showing moderators or moderation-related services. "Lista moderowana" suggests that someone is overseeing the moderation of the list. I'm still not entirely sure what the intended meaning is or what the audience is meant to understand from the name.  
- I changed "rolka aparatu" to "galeria zdjęć."
- I changed "obrazki" to "zdjęcia".

* Update messages.po

Suggested changes were made.
Changed “użytkownik” to “osoba” where it was logical for consistency. Removed where it was not needed.

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2024-12-18 15:32:27 -08:00
dan 45c6308607 Don't hide recommended (#7166)
* Don't hide recommended

* Rm unused
2024-12-18 23:31:18 +00:00
Valtteri Laitinen 65eccc79aa Update and improve Finnish locale (#6840)
* Update and improve Finnish locale

* Remove obsolete Finnish strings
2024-12-18 15:30:59 -08:00
Frudrax Cheng 8f171451ef Update Chinese & Cantonese localization (#6839)
* Update translates from crowdin

* zh-CN: Improved translations

* Both: Improved translations

* TW & HK: Improved translations

* CN: Re-translate 'Quote posts enabled'

* TW: Improved translations

* CN: Unify the translations of 'label'

* CN: Fix grammar

* CN & HK: Improved translation

* TW: Improved translations

* Update translates from crowdin

* Translated new Layout & Improved zh-TW translations

* zh-CN: Unified label translation

* zh-HK: Fix translation

* zh-TW: Improved translation

* Update from crowdin

* Improved translation

* Update translates from crowdin

* Update from crowdin

* Update the latest translations

* Update translations according #7065

* zh-TW: Improved translations

* Update translates from crowdin

* zh-HK: Improved translations

* Update translates from crowdin

* Improved translations

* zh-CN & zh-HK: Improved translations

* zh-CN: Re-translated 'Bluesky is better with friends!'

* Update translates from crowdin

* Translated #7128

* Remove placeholder

* Translated #7144 #7147

* Improved translations

* Improved translations#2

* zh-CN: Improved translations
2024-12-18 15:30:32 -08:00
Vinh Pham ac42f90e4d enhance translations, add new translation tags (#6838) 2024-12-18 15:30:00 -08:00
Ivan Beà 2e72b0a7a2 Update catalan messages.po (#6811)
* Update catalan messages.po

No new lines to translate this one, just fixing some minor errors

Please take a look at it @jordimas @darccio @surfdude29 @rortan134 @magarcia @aryiu

* Update messages.po
2024-12-18 15:29:34 -08:00
Minseo Lee bc948cb725 Update Korean localization (#6799)
* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po
2024-12-18 15:29:13 -08:00
Michele Locati e7a34669ff Update Italian translations (#6775)
* Update Italian translations

* Translate "Discover Feed"

* Update translations from Transifex

* Update translations from Transifex

* Update translations from Transifex

* Update translations from Transifex

* Update translations from Transifex

* Update translations from Transifex

* Update translations from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

* Update po from Transifex

---------

Co-authored-by: GitHub <noreply@github.com>
2024-12-18 15:28:45 -08:00
hogaza 4697b92b6a Spanish localization - completion and some fixes (#6691)
* Updates and missing translations.

Added some missing translations, corrected a few inconsistencies (paquete inicial; video) and edited to strings to use gender-neutral language.

* Update src/locale/locales/es/messages.po

Thanks @surfdude29 for pointing this out

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Update src/locale/locales/es/messages.po

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2024-12-18 15:28:19 -08:00
Takayuki KUSANO d42f768347 Update Japanese translation (#6620)
* Update Japanese translation

* Update

* Remove obsoleted entries

* Update translation

* minimize diff to main

* apply middlingphys's review, erase obsoleted messages.

* Traslate new messages (app icon)

* modified on feedback

* Update translation

* Update translation

* Update translation

* translate new messages on new screen

* Remove the typo entry fixed by #7064

* Update translation

* Update translaiton

* Update translation

* Update translation

* Update translation

* Translate new progress guide
2024-12-18 15:25:17 -08:00
Claudiu Cristea afd338b0f3 Romanian localization (#6456)
* Empty

* First pass

* More colloquial Romanian

* Add Romanian lanaguage

* Romanian specfic plural with 3 variants

* Adjustments

* Chat > Conversație

* Keep code alphabetical order

* Update messages.po

* Add 'ro' to app.config.js

* Regenerate and finish RO

* Update messages.po

* Fixing a previous wrong conflict resolution

* Adapt after #6742

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

---------

Co-authored-by: Alex <alextec70@outlook.com>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2024-12-18 15:24:38 -08:00
Dan Abramov 2d1a5e71ab Remove X from recommended 2024-12-18 22:48:09 +00:00
Eric Bailey 925a240ec4 Fork close logic for android to match previous usage (#7165) 2024-12-18 22:22:16 +00:00
Eric Bailey 62daf047ca Adjust height of radio (#7164) 2024-12-18 20:25:54 +00:00
Samuel Newman 674153c725 move header inside sticky area (#7163) 2024-12-18 20:15:05 +00:00
Eric Bailey c8e307b5cf Trending tracking 2 (#7162)
* Move

(cherry picked from commit bfb96f4ce2)

* Add to recommeded too

(cherry picked from commit e6844883a6)

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-12-18 19:55:59 +00:00
dan a7f763faf2 Add reply sorting in-thread (#7156)
* Add button

* Extract component

* Make it work

* Extract and use RadioCircle

* Add tree/list setting

* Prefer local state

* Factor out threadViewPrefs

* Fix optimistic stuff

* Revert RadioButton changes

* Tweak radio styles, add Menu.LabelText

* Labels

* Margins

* Update copy

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-12-18 19:50:37 +00:00
Samuel Newman 4097fe07c5 make trending buttons pressable scale (#7160) 2024-12-18 19:48:24 +00:00
Eric Bailey e7b015f53f Trending tracking (#7161)
* Add hide to Explore

* Event for show

* Add hide events to each location
2024-12-18 11:37:46 -08:00
Samuel Newman 05c43ed998 Better list empty state (#7157)
* render header conditionally, use modern footer

* move add button to empty state if empty

* center align empty state

* Tweak add people btn

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2024-12-18 11:03:53 -08:00
Hailey 5c4f870898 change stale time to three minutes (#7158) 2024-12-18 10:58:26 -08:00
Samuel Newman 3481d16577 Remove header subtitle from list-related screens (#7154)
* rm subtitle, add admonition

* rm top border from empty state

* Minimal approach

* Revert uneeded change

* Even more minimal

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-12-18 10:23:40 -08:00
Samuel Newman 2d827430ee Web sticky headers for most screens (#7153)
* web sticky headers, with opt-out for notifs

* rm from postthread

* Fix jump

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-12-18 16:58:20 +00:00
Paul Frazee 3262b83420 Fix tests 2024-12-17 21:29:45 -08:00
Paul Frazee ff02868afc Layout tweaks (#7150)
* Reduce weight of right sidebar active feed

* ProfileFeedHeader tweaks

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-12-17 19:50:59 -08:00
Eric Bailey a2019aceec Trending (Beta) (#7144)
* Add WIP UIs for trending topics and suggested starterpacks

* Disable SPs for now

* Improve explore treatment a bit, add some polish to cards

* Add tiny option in RightNav

* Add persisted option to hide trending from sidebar

* Add to settings, abstract state, not updating in tab

* Fix up hide/show toggle state, WITH broadcast hacK

* Clean up persisted code, add new setting

* Add new interstitial to Discover

* Exploration

* First hack at mute words

* Wire up interstitial and Explore page

* Align components

* Some skeleton UI

* Handle service config, enablement, load states, update lex contract

* Centralize mute word handling

* Stale time to 30m

* Cache enabled value for reloads, use real data for service config

* Remove broadcast hack

* Remove titleChild

* Gate settings too

* Update package, rm langs

* Add feature gate

* Only english during beta period

* Hook up real data

* Tweak config

* Straight passthrough links

* Hook up prod agent

* Fix no-show logic

* Up config query to 5 min

* Remove old file

* Remove comment

* Remove stray flex_1

* Make trending setting global

* Quick placeholder state

* Limit # in sidebar, tweak spacing

* Tweak gaps

* Handle hide/show of sidebar

* Simplify messages

* Remove interstitial

* Revert "Remove interstitial"

This reverts commit 1358ad47fd.

* Only show interstitial on mobile

* Fix gap

* Add explore page recommendations

* [topics] add topic screen (#7149)

* add topic screen

* decode

* fix search query

* decode

* add server route

* Fix potential bad destructure (undefined)

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
Co-authored-by: Hailey <me@haileyok.com>
2024-12-17 19:45:39 -08:00
Eric Bailey a07949ec8e Fix emoji picker position (#7146) 2024-12-17 21:12:53 -06:00
dan 65d4416f9e Tweak Follow dialog Search placeholder (#7147) 2024-12-18 02:53:42 +00:00
Samuel Newman 0cbb03cd14 New progress guide - 10 follows (#7128)
* new follow-10 progress guide

* find follows dialog

* wip tabs

* flatlist version with search

* hardcode out jake gold

* lazy load followup suggestions

* Update src/components/ProgressGuide/FollowDialog.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* comment out replacing, enable paging

* rm autofocus

* find shadow profiles in paginated search

* clear search when press tabs

* better tab a11y

* fix label

* adjust scroll indicator insets

* do the same scroll indicator adjustment for searchable people list

* hardcode jake to just be 'tech'

* Retain state on close/reopen

* only change follow btn color when not followed

* add guide to inside dialog

* fix task alignment

* Enable contextual suggestions

* WIP: show multiple suggestions

* Rework so it animates well

* Show more items

* remove card style

* move tabs to own component

* split out header top

* scroll active tab into view

* rm log

* Improve perf a bit

* boost popular interests over alphabetical ones

* scroll active tab into view

* revert back to round buttons

* Fix overrenders of the tab bar items

* Fix unintended animation

* Scroll initial into view if needed

* Unlift state, the dialog thing breaks lifting

* Persist simply

* Fix empty state

* Fix incorrect gate exposure

* Fix another bad useGate

* Nit

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-12-17 17:13:18 +00:00
dan 32611391a3 Pipe statsig events to logger (#7141)
* Pipe statsig events to logger

* Log rich objects to bitdrift

* Fix tests

* Consolidate mocks, fix tests

* Reduce log trash on native
2024-12-17 12:22:09 +00:00
dan 07b7250682 Fix notifications borders (#7140) 2024-12-17 11:22:49 +00:00
dan 31d2aa6716 Refetch empty feed on focus (#7139) 2024-12-17 11:09:06 +00:00
dan 20d4266e2f Read storage on window.onstorage (#7137) 2024-12-17 03:13:51 +00:00
dan c9e429760d [ELI5] Tweak wording on the signup screen (#7136)
* Tweak signup wordings

* Update translations
2024-12-17 00:11:21 +00:00
Samuel Newman be33c626b0 alf error screen (#7135) 2024-12-17 00:11:03 +00:00
Samuel Newman 1a160df396 add safe area view to profile error screen (#7134) 2024-12-17 00:02:56 +00:00
dan de97c07c63 Adjust gates (#7132)
* Remove dead gate

* Adjust gates

* No need to disable exposures
2024-12-16 22:26:40 +00:00
Samuel Newman c339dc5b05 disable automaticallAdjustsScrollIndicatorInsets (#7131) 2024-12-16 22:06:15 +00:00
dan 3ed237b629 Bump more native deps (#7129)
* Undo expo modules patch

* Upgrade expo modules release

* Patch facebook/react-native#46944

* Remove explicit prebuild config dep

* Bump to rm duplicates
2024-12-16 21:46:39 +00:00
dan 21c288272d Update more Expo packages (#7127)
* Bump Expo resolutions

* Bump packages

* Bumpy bump
2024-12-16 17:35:44 +00:00
Karol Stawowski c4fffba11b feat: widen recent search profile link for mobile devices (#7119)
* feat: widen recent search profile link for mobile devices

* chore: apply style to non-mobile screens
2024-12-16 16:53:00 +00:00
dan e4e5a589b1 Fix video uploads on native (#7126)
* Fix duplicate expo-modules-core

* Patch expo/expo#33621
2024-12-16 15:42:29 +00:00
Frudrax Cheng b1b6affb71 Fix post time localization on Android (#6742)
* Fix post time localization on native

* Fix timezone

* Revent time.ts

* Add time.android.ts

* Add missing 'an' and 'ast'

* Revent PostThreadItem.tsx

* Resolve duplicate versions in lockfile

* Move to time.native.ts

* Follow #7055 to upgrade intl-datetimeformat version

* Remove time.native.ts
2024-12-16 14:25:59 +00:00
dan 1ac307bc42 [Experiment] Remove "Load Latest" button (#7120)
* Remove "show latest" behind the gate

* Add HomeBadgeProvider

* Update provider state from home feed tabs

* Add Home badge to native

* Add Home badge to mobile web

* Add Home badge to desktop web
2024-12-15 20:30:17 +00:00
dan 80c0125d6b Fix image upload on native (#7121) 2024-12-15 17:42:45 +00:00
Eric Bailey c959dc351f ProfileFeed cleanups (#7115)
* Clean up feed load state

* Fix feed info dialog load state
2024-12-14 15:30:01 -06:00
Ben Harris b806f3e85d apply fonts to TextField (#6288)
system fonts were leaking. i'm sure there's a better way to apply this
without duplicating but idk it works
2024-12-14 03:02:12 +00:00
dan c5e60ba006 Fix posting images on web (#7105)
* Fix uploadBlob to handle blob: URI

* Patch expo-image-manipulator to support "compress" argument

* Narrow down the fix
2024-12-14 02:25:32 +00:00
dan 55222c5b0e Fix z-indexes to make tabbar scroll on Android (#7102) 2024-12-14 00:01:31 +00:00
Eric Bailey ca8ca903b2 Add some helper text for custom domains (#7103)
* Add some helper text for custom domains

* endsWith

* ope
2024-12-13 23:05:53 +00:00
dan da6bcc54cf Tweak ProfileList design (#7100)
* Remove "No description"

* Move Lists about into header

* Remove pager with one tab

* Layout tweaks
2024-12-13 21:38:43 +00:00
dan adbc27059a Add Emily to discover debug (#7101) 2024-12-13 21:16:25 +00:00
Eric Bailey ce69e052b7 Allow non-graph emoji to inherit parent color (#7096) 2024-12-13 12:36:00 -06:00
dan f6aecf5c28 Give minWidth to tab indicator only (#7095) 2024-12-13 18:20:48 +00:00
Eric Bailey 41228dce19 Better alignment on web (#7098) 2024-12-13 18:20:38 +00:00
dan 356dad1932 Remove the environment indirections (#7089)
* Use raw underlying globals for environment

* Set dev EXPO_PUBLIC_ENV by exclusion
2024-12-13 17:16:53 +00:00
dan e2a7965e43 Gate bitdrift integration (#7088)
* Move Statsig init call earlier

* Gate Bitdrift init call

* Remove IS_TEST env constant

* Mock statsig
2024-12-13 17:14:41 +00:00
Brad Estey 5655241bef Uppercase the auth factor token in input value to match the email casing. (#7094) 2024-12-13 17:14:31 +00:00
dan add7a91d54 Fix web Home header (#7086)
* Fix header disappearing on web

* Make border nicer
2024-12-12 21:57:26 +00:00
dan 8a790cdd7f Revert "Edit string to avoid churning translations (#6737)" (#7087)
This reverts commit 9d3bdbb2b9.
2024-12-12 21:52:51 +00:00
surfdude29 10dd0f76eb mark string for localization (#7083) 2024-12-12 21:50:30 +00:00
dan 6e20893a0c Fix double border due to progress guide (#7084) 2024-12-12 15:16:15 -06:00
Hailey 2276cb0e75 Fix share button not working for some users (#5849)
* fix share button

* Revert "fix share button"

This reverts commit 3521c241729dc9bbe3dd7b62fc6e3e61e011cdf9.

* tweak

* Clean up context

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-12-12 13:50:29 -06:00
Eric Bailey 2808f8b73d New profile feed header (#7056)
* Init hacking

* Lil baby button checkpoint

* Playing around

* Revert "Playing around"

This reverts commit f58a7fafa1.

* Mostly there

* Cleanups

* Cleanup

* Fix report dialog nesting

* Remove transform on native

* Rename header

* Fix layout, overflowing FAB buttons

* Remove hack

* Couple of fixes

* Keep Pin primary CTA (#7061)

* Update src/screens/Profile/components/ProfileFeedHeader.tsx

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* Simplify, use old string

* Wrap Trans better

---------

Co-authored-by: dan <dan.abramov@gmail.com>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2024-12-12 11:48:26 -06:00
Samuel Newman ffc63dc85f [Layout] Bleed profile banner into safe area (#6967)
* bleed profile banner into safe area

(cherry picked from commit 50b3a4d0c6fd94b583ffe4efa65de35c81ae7f4e)

* pointer events none when hidden

(cherry picked from commit bae2c7b2dd6d7f858a98812196628308c0877755)

* fix web

(cherry picked from commit e3f9597170375f2903b6e567b963f008ec95aed1)

* add status bar shadow

* rm log

* rm mini header

* speed up animation

* pass bool rather than int in light status bar
2024-12-12 17:46:19 +00:00
Samuel Newman 4b32b0a71b Increase scrubber height if touch device (#7081)
* further increase target area of scrubber

* make scrubber bigger if touch device

---------

Co-authored-by: Antonio Sarcevic <sarcevicantonio@gmail.com>
2024-12-12 17:42:36 +00:00
dan f8cdd6b9ae [Notifications] Add a Mentions tab (#7044)
* Split out NotificationsTab

* Remove unused route parameter

* Refine the split between components

* Hoist some logic out of NotificationFeed

* Remove unused option

* Add all|conversations to query, hardcode "all"

* Add a Conversations tab

* Rename to Mentions

* Bump packages

* Rename fields

* Fix oopsie

* Simplify header

* Track active tab

* Fix types

* Separate logic for tabs

* Better border for first unread

* Highlight unread for all only

* Fix spinner races

* Fix fetchPage races

* Fix bottom bar border being obscured by glimmer

* Remember last tab within the session

* One tab at a time

* Fix TS

* Handle all RQKEY usages

* Nit
2024-12-12 17:37:07 +00:00
Samuel Newman 10e241e7eb followersCount -> followsCount (#7080) 2024-12-12 17:21:28 +00:00
dan 88166926fa Make the pager take full width (#7066)
* Wide tabs for web

* Wide tabs on mobile

* Tweak min for profile

* Driveby border fix

* Fix single tab indicator
2024-12-12 15:35:56 +00:00
dan 704e36c280 Fix web build (#7069)
* Fix web build

* Fix circular deps

* Hoist log functions
2024-12-12 05:00:09 +00:00
Snow Pettersen 20ac42a5a3 configure the bitdrift Capture SDK (#6979)
* configure bitdrift Capture SDK

* remove console log

* use the new url

* add patch to fix devtool interaction

* update patches

* fix patch

* add BITDRIFT_API_KEY to .env.example
2024-12-12 04:28:15 +00:00
dan c8745a9ab0 Cache Reanimated worklets (#7068)
* Undo perf hackfix

* Bump Reanimated to include https://github.com/software-mansion/react-native-reanimated/pull/6758

* Bump to 3.17.0-nightly-20241211-17e89ca24
2024-12-12 04:20:22 +00:00
Minseo Lee 084905c146 refine plural marks (#7065) 2024-12-12 03:48:02 +00:00
Frudrax Cheng ddeadc21a0 Update PostRepostedBy.tsx (#7064) 2024-12-12 01:56:43 +00:00
Samuel Newman e49dad2889 Nicer app icon screen (#6972)
* wip exploration

* list format instead of grid

* fix normalising default name

* adjust margins

* Rework the app icon link

* Decrease app icon size

* Adjust some spacing

* Move some things around to fix web errors

* Fix pathname

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: Eric Bailey <git@esb.lol>
2024-12-11 22:33:45 +00:00
dan 69f22b9dba Point "Continue thread" at last shown post (#7060) 2024-12-11 22:29:57 +00:00
Samuel Newman 48346edde6 More exact counts (#7059)
* post liked by

* rm unnecessary layout.center

* do post quotes/reposts

* set height of header to prevent layout shifts
2024-12-11 22:24:22 +00:00
Samuel Newman 89c6ca94fe Followers/following exact count (#7057)
* followers exact count in heading

* exact count for following

* move files to new dir

* use <Plural>
2024-12-11 21:12:58 +00:00
dan 7db5882ea2 Merge pull request #7058 from bluesky-social/fix-profile-empty-space-nobio 2024-12-11 21:01:56 +00:00
Dan Abramov c55063d262 Reduce excessive empty space on profile with no bio 2024-12-11 20:35:13 +00:00
Samuel Newman b081f8f8d9 Remove rounding mode hack (#7055)
* bump formatjs and remove hack

* maybe fix tests?

* Revert "maybe fix tests?"

This reverts commit f1b448e5b8.

* rm test
2024-12-11 19:13:09 +00:00
かっこかり de15f8e2d3 feat(embed): Add support for dark mode (#6912)
* feat(embed): Support dark mode (wip)

* finishing up the implementation

* fix tailwind color selector

* tweak design

* refactor: unify types

* fix

* fix english grammar

* refactor: unify types

* tweak design

* remove the customization part
2024-12-11 16:31:29 +00:00
dan 48c5341644 Fix iOS build (#7042) 2024-12-10 22:17:27 +00:00
dan 86155986af Fix composer shortcut detaching a reply (#7041) 2024-12-10 21:19:53 +00:00
Barry Pollard bee50c3954 Font loading improvements (#6993)
* Font loading improvements

* Reconvert with missing files

* Update bskyweb/templates/base.html

Co-authored-by: Rick Viscomi <rviscomi@users.noreply.github.com>

* Update bskyweb/templates/base.html

Co-authored-by: Rick Viscomi <rviscomi@users.noreply.github.com>

* Run web-build to update hashes

* Revert Android to otf

* Use Inter woff2 files

---------

Co-authored-by: Rick Viscomi <rviscomi@users.noreply.github.com>
2024-12-10 21:17:58 +00:00
rcombs 6308e91de6 LoginForm: enable autocomplete on 2FA code field (#7019)
This should (fingers crossed) work in Safari, at least.
2024-12-10 21:16:45 +00:00
Renan Mav b7ddb07d90 fix: typo in filename list-converations (#7036) 2024-12-10 20:59:35 +00:00
dan d00879e628 Disambiguate feed component naming (#7040)
* Rename posts/Feed* -> posts/PostFeed*

* Rename notifications/Feed* -> notifications/NotificationFeed*
2024-12-10 20:57:53 +00:00
Eric Bailey e052f5e198 Refactor sidebar (#6971)
* Refactor RightNav

(cherry picked from commit 96bb02acfd2d7452df18a0e7410e6a7169a583ed)

* Better gutter handling

* Clean up styles

* Memoize breakpoints

* Format

* Comment

* Loosen spacing, handle overflow, smaller text to match prod

* Fix circular imports on native

* Return 0 instead of undefined for easier calculations

* Re-assign

* Fix

* Port over fix from subs/base

* Space out right nav feeds, widen sidebar to match prod

* Fix lost padding on home header

* Fix perf by not actually linking to new URL

* Remove underline on focus

* Foramt

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-12-10 20:52:30 +00:00
dan f34e8d8cdf Limit feed prefetching to native (#7038) 2024-12-10 18:23:23 +00:00
dan 46e1e5cee6 Fix drawer swipe (#7007)
* Fix drawer swipe

* Remove existing setDrawerSwipeDisabled management

This is already pretty error-prone. And with tracking whether we're idle it's going to get more complicated. Let's pause and think.

* Move setDrawerSwipeDisabled logic into Pager

* Remove win/2 threshold

It feels super arbitrary and breaks muscle memory. If the gesture is reliable, we shouldn't need it.

* Maybe work around iOS freeze

* Tweak gestures, add comments

* Tune gestures
2024-12-10 04:40:40 +00:00
Dmitry Grachikov fec3352b68 Access content of extended block properly (block.Super instead of super()) (#7026) 2024-12-09 22:23:36 +00:00
Eric Bailey bc4b4a3cfe Add isSelfHosted to SessionAccount (#7028)
* Add isSelfHosted to SessionAccount

* Update snaps
2024-12-09 13:43:16 -06:00
Eric Bailey 63c0c7e621 Add back button to desktop threads (#7010) 2024-12-08 14:44:01 -06:00
342 changed files with 90908 additions and 45529 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
# Copy this to `.env` and `.env.test` files
BITDRIFT_API_KEY=
SENTRY_AUTH_TOKEN=
EXPO_PUBLIC_ENV=development
EXPO_PUBLIC_LOG_LEVEL=debug
EXPO_PUBLIC_LOG_DEBUG=
EXPO_PUBLIC_BUNDLE_IDENTIFIER=
@@ -64,6 +64,7 @@ jobs:
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "$json" > google-services.json
- name: 🏗️ EAS Build
+1
View File
@@ -76,6 +76,7 @@ jobs:
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "${{ secrets.GOOGLE_SERVICES_TOKEN }}" > google-services.json
- name: 🏗️ EAS Build
@@ -69,6 +69,9 @@ jobs:
- name: Lint check
run: yarn lint
- name: Lint lockfile
run: yarn lockfile-lint
- name: Prettier check
run: yarn prettier --check .
@@ -101,6 +104,7 @@ jobs:
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "$json" > google-services.json
- name: 🏗️ Create Bundle
@@ -196,6 +200,7 @@ jobs:
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "${{ secrets.GOOGLE_SERVICES_TOKEN }}" > google-services.json
- name: 🏗️ EAS Build
@@ -222,7 +227,7 @@ jobs:
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}-build-android
cancel-in-progress: false
needs: [ bundleDeploy ]
needs: [bundleDeploy]
# Gotta check if its NOT '[]' because any md5 hash in the outputs is detected as a possible secret and won't be
# available here
if: ${{ inputs.channel != 'production' && needs.bundleDeploy.outputs.changes-detected }}
@@ -273,6 +278,7 @@ jobs:
echo "${{ secrets.ENV_TOKEN }}" > .env
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$(git rev-parse --short HEAD)" >> .env
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "$json" > google-services.json
- name: 🏗️ EAS Build
+2 -2
View File
@@ -19,7 +19,7 @@ jobs:
- name: Set up Go tooling
uses: actions/setup-go@v3
with:
go-version: '1.22'
go-version: '1.23'
- name: Dummy Static Files
run: touch bskyweb/static/js/blah.js && touch bskyweb/static/css/blah.txt && touch bskyweb/static/media/blah.txt
- name: Check
@@ -36,7 +36,7 @@ jobs:
- name: Set up Go tooling
uses: actions/setup-go@v3
with:
go-version: '1.22'
go-version: '1.23'
- name: Dummy Static Files
run: touch bskyweb/static/js/blah.js && touch bskyweb/static/css/blah.txt && touch bskyweb/static/media/blah.txt
- name: Lint
+3 -1
View File
@@ -28,6 +28,8 @@ jobs:
attempt_delay: 2000
- name: Lint check
run: yarn lint
- name: Lint lockfile
run: yarn lockfile-lint
- name: Prettier check
run: yarn prettier --check .
- name: Check & compile i18n
@@ -54,4 +56,4 @@ jobs:
run: yarn intl:build
- name: Run tests
run: |
NODE_ENV=test EXPO_PUBLIC_ENV=test yarn test --forceExit
NODE_ENV=test yarn test --forceExit
+46
View File
@@ -0,0 +1,46 @@
name: Lockfile
on:
pull_request:
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: true
jobs:
verify-yarn-lock:
name: No manual yarn.lock edits
runs-on: ubuntu-latest
steps:
- name: Check out PR HEAD
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Fetch base branch
run: git fetch origin ${{ github.base_ref }} --depth=1
- name: Install node
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- name: Reset yarn.lock to base
run: git show "origin/${{ github.base_ref }}:yarn.lock" > yarn.lock
- name: Yarn install
uses: Wandalen/wretry.action@master
with:
# Fine to skip scripts since we don't run any code
command: yarn install --ignore-scripts
attempt_limit: 3
attempt_delay: 2000
- name: Verify yarn.lock
run: |
git diff --quiet --exit-code || {
echo '::error::`yarn.lock` does not match what Yarn would generate given the base `yarn.lock` and the head `package.json`.'
echo '::error:: - If this is intentional, you can ignore this check.'
echo '::error:: - If this is unintentional, apply the following diff:'
git --no-pager diff
exit 1
}
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.22-bullseye AS build-env
FROM golang:1.23-bullseye AS build-env
WORKDIR /usr/src/social-app
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.22-bullseye AS build-env
FROM golang:1.23-bullseye AS build-env
WORKDIR /usr/src/social-app
+1 -1
View File
@@ -20,7 +20,7 @@ build-web-embed: ## Compile web embed bundle, copy to bskyweb/embedr* directorie
.PHONY: test
test: ## Run all tests
NODE_ENV=test EXPO_PUBLIC_ENV=test yarn test
NODE_ENV=test yarn test
.PHONY: lint
lint: ## Run style checks and verify syntax
+5 -8
View File
@@ -26,7 +26,7 @@ appId: xyz.blueskyweb.app
- tapOn: "Save"
- assertNotVisible:
id: "createOrEditListModal"
- tapOn: "About"
- tapOn: "People"
- assertVisible: "Good Ppl"
- assertVisible: "They good"
@@ -74,7 +74,6 @@ appId: xyz.blueskyweb.app
- tapOn: "Delete List"
- tapOn:
id: "confirmBtn"
- assertVisible: "This list is empty!"
- tapOn:
label: "Create a new curatelist"
@@ -93,14 +92,12 @@ appId: xyz.blueskyweb.app
- tapOn: "Save"
- assertNotVisible:
id: "createOrEditListModal"
- tapOn: "About"
- tapOn: "People"
- assertVisible: "Good Ppl"
- assertVisible: "They good"
- tapOn: "About"
- tapOn: "People"
- tapOn:
label: "Adds users on curatelists from the list"
id: "addUserBtn"
- tapOn: "Start adding people"
- assertVisible:
id: "listAddUserModal"
- tapOn:
@@ -145,7 +142,7 @@ appId: xyz.blueskyweb.app
id: "e2eGotoLists"
- tapOn: "Good Ppl"
- tapOn: "About"
- tapOn: "People"
- assertVisible:
label: "Removes users on curatelists from the list"
id: "user-bob.test"
+8 -16
View File
@@ -11,10 +11,8 @@ appId: xyz.blueskyweb.app
# Pin alice's feed
- extendedWaitUntil:
visible:
id: "viewHeaderDrawerBtn"
- tapOn:
id: "viewHeaderDrawerBtn"
visible: "Open drawer menu"
- tapOn: "Open drawer menu"
- tapOn:
id: "profileCardButton"
- tapOn:
@@ -32,8 +30,7 @@ appId: xyz.blueskyweb.app
text: "alice-favs"
# Set alice-favs first
- tapOn:
id: "viewHeaderDrawerBtn"
- tapOn: "Open drawer menu"
- tapOn:
id: "menuItemButton-Feeds"
- tapOn:
@@ -44,8 +41,7 @@ appId: xyz.blueskyweb.app
- tapOn:
label: "Save button"
id: "saveChangesBtn"
- tapOn:
id: "viewHeaderDrawerBtn"
- tapOn: "Go back"
- assertVisible:
id: "homeScreenFeedTabs-selector-0"
text: "alice-favs"
@@ -54,8 +50,7 @@ appId: xyz.blueskyweb.app
text: "Following"
# Set following first
- tapOn:
id: "viewHeaderDrawerBtn"
- tapOn: "Open drawer menu"
- tapOn:
id: "menuItemButton-Feeds"
- tapOn:
@@ -66,8 +61,7 @@ appId: xyz.blueskyweb.app
- tapOn:
label: "Save button"
id: "saveChangesBtn"
- tapOn:
id: "viewHeaderDrawerBtn"
- tapOn: "Go back"
- assertVisible:
id: "homeScreenFeedTabs-selector-0"
text: "Following"
@@ -76,8 +70,7 @@ appId: xyz.blueskyweb.app
text: "alice-favs"
# Remove following
- tapOn:
id: "viewHeaderDrawerBtn"
- tapOn: "Open drawer menu"
- tapOn:
id: "menuItemButton-Feeds"
- tapOn:
@@ -88,8 +81,7 @@ appId: xyz.blueskyweb.app
- tapOn:
label: "Save button"
id: "saveChangesBtn"
- tapOn:
id: "viewHeaderDrawerBtn"
- tapOn: "Go back"
- assertVisible:
id: "homeScreenFeedTabs-selector-0"
text: "alice-favs"
+3 -1
View File
@@ -27,7 +27,9 @@ appId: xyz.blueskyweb.app
- tapOn:
id: "bottomBarHomeBtn"
- tapOn:
id: "viewHeaderDrawerBtn"
id: "bottomBarHomeBtn"
- tapOn:
id: "bottomBarHomeBtn"
- assertNotVisible: "Feeds ✨"
- tapOn:
+1 -1
View File
@@ -14,7 +14,7 @@ appId: xyz.blueskyweb.app
id: "e2eGotoModeration"
- tapOn:
id: "moderationlistsBtn"
- tapOn: "New"
- tapOn: "New list"
- tapOn:
id: "editNameInput"
- inputText: "Muted Users"
+2
View File
@@ -6,6 +6,8 @@ appId: xyz.blueskyweb.app
- waitForAnimationToEnd
- tapOn: "http://localhost:8081"
- waitForAnimationToEnd
- extendedWaitUntil:
visible: "Continue"
- swipe:
from: "Bluesky"
direction: DOWN
+11 -4
View File
@@ -15,9 +15,9 @@ module.exports = function (config) {
*/
const PLATFORM = process.env.EAS_BUILD_PLATFORM
const IS_DEV = process.env.EXPO_PUBLIC_ENV === 'development'
const IS_TESTFLIGHT = process.env.EXPO_PUBLIC_ENV === 'testflight'
const IS_PRODUCTION = process.env.EXPO_PUBLIC_ENV === 'production'
const IS_DEV = !IS_TESTFLIGHT || !IS_PRODUCTION
const ASSOCIATED_DOMAINS = [
'applinks:bsky.app',
@@ -50,7 +50,6 @@ module.exports = function (config) {
runtimeVersion: {
policy: 'appVersion',
},
orientation: 'portrait',
icon: './assets/app-icons/ios_icon_default_light.png',
userInterfaceStyle: 'automatic',
primaryColor: '#1083fe',
@@ -77,6 +76,7 @@ module.exports = function (config) {
'ast',
'ca',
'de',
'el',
'es',
'fi',
'fr',
@@ -87,10 +87,13 @@ module.exports = function (config) {
'id',
'it',
'ja',
'km',
'ko',
'ne',
'nl',
'pl',
'pt-BR',
'ro',
'ru',
'th',
'tr',
@@ -222,11 +225,14 @@ module.exports = function (config) {
},
],
'react-native-compressor',
// TODO: Reenable when the build issue is fixed.
// '@bitdrift/react-native',
'./plugins/starterPackAppClipExtension/withStarterPackAppClip.js',
'./plugins/withAndroidManifestPlugin.js',
'./plugins/withAndroidManifestFCMIconPlugin.js',
'./plugins/withAndroidStylesAccentColorPlugin.js',
'./plugins/withAndroidSplashScreenStatusBarTranslucentPlugin.js',
'./plugins/withAndroidNoJitpackPlugin.js',
'./plugins/shareExtension/withShareExtensions.js',
'./plugins/notificationsExtension/withNotificationsExtension.js',
'./plugins/withAppDelegateReferrer.js',
@@ -234,8 +240,8 @@ module.exports = function (config) {
'expo-font',
{
fonts: [
'./assets/fonts/inter/InterVariable.ttf',
'./assets/fonts/inter/InterVariable-Italic.ttf',
'./assets/fonts/inter/InterVariable.woff2',
'./assets/fonts/inter/InterVariable-Italic.woff2',
// Android only
'./assets/fonts/inter/Inter-Regular.otf',
'./assets/fonts/inter/Inter-Italic.otf',
@@ -340,6 +346,7 @@ module.exports = function (config) {
},
},
],
['expo-screen-orientation', {initialOrientation: 'PORTRAIT_UP'}],
].filter(Boolean),
extra: {
eas: {
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M7.5 2a1 1 0 0 0-1 1v3.997a6.25 6.25 0 0 1-1.83 4.42l-.377.376A1 1 0 0 0 4 12.5V15a1 1 0 0 0 1 1h6v5a1 1 0 1 0 2 0v-5h6a1 1 0 0 0 1-1v-2.5a1 1 0 0 0-.293-.707l-.376-.377a6.25 6.25 0 0 1-1.831-4.42V3.001a1 1 0 0 0-1-1h-9Z"/></svg>

After

Width:  |  Height:  |  Size: 323 B

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" stroke="#000" stroke-linejoin="round" d="M4 5.5a.5.5 0 0 0-.5.5v2.535a.5.5 0 0 0 .25.433A3.5 3.5 0 0 1 5.5 12a3.5 3.5 0 0 1-1.75 3.032.5.5 0 0 0-.25.433V18a.5.5 0 0 0 .5.5h16a.5.5 0 0 0 .5-.5v-2.535a.5.5 0 0 0-.25-.433A3.5 3.5 0 0 1 18.5 12a3.5 3.5 0 0 1 1.75-3.032.5.5 0 0 0 .25-.433V6a.5.5 0 0 0-.5-.5H4ZM2.5 6A1.5 1.5 0 0 1 4 4.5h16A1.5 1.5 0 0 1 21.5 6v3.17a.5.5 0 0 1-.333.472 2.501 2.501 0 0 0 0 4.716.5.5 0 0 1 .333.471V18a1.5 1.5 0 0 1-1.5 1.5H4A1.5 1.5 0 0 1 2.5 18v-3.17a.5.5 0 0 1 .333-.472 2.501 2.501 0 0 0 0-4.716.5.5 0 0 1-.333-.471V6Zm12 2a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0Zm0 4a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0Zm0 4a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3 4a1 1 0 0 0-1 1v4.17a1 1 0 0 0 .667.944 2.001 2.001 0 0 1 0 3.772A1 1 0 0 0 2 14.83V19a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1v-4.17a1 1 0 0 0-.667-.944 2.001 2.001 0 0 1 0-3.772A1 1 0 0 0 22 9.17V5a1 1 0 0 0-1-1H3Zm1 4.535V6h16v2.535A4 4 0 0 0 18 12c0 1.482.805 2.773 2 3.465V18H4v-2.535A4 4 0 0 0 6 12a4 4 0 0 0-2-3.465ZM15 15a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-1-3a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm1-5a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" clip-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 756 B

After

Width:  |  Height:  |  Size: 561 B

+1
View File
@@ -4,6 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bluesky Embed</title>
<link rel="preconnect" href="https://public.api.bsky.app">
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png">
+1
View File
@@ -4,6 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bluesky Embed</title>
<link rel="preconnect" href="https://public.api.bsky.app">
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png">
+3 -1
View File
@@ -20,6 +20,7 @@ window.addEventListener('message', event => {
return
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const id = (event.data as {id: string}).id
if (!id) {
return
@@ -33,6 +34,7 @@ window.addEventListener('message', event => {
return
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const height = (event.data as {height: number}).height
if (height) {
embed.style.height = `${height}px`
@@ -47,7 +49,7 @@ window.addEventListener('message', event => {
* @returns
*/
function scan(node = document) {
const embeds = node.querySelectorAll('[data-bluesky-uri]')
const embeds = node.querySelectorAll<HTMLIFrameElement>('[data-bluesky-uri]')
for (let i = 0; i < embeds.length; i++) {
const id = String(Math.random()).slice(2)
+17
View File
@@ -0,0 +1,17 @@
export function applyTheme(theme: 'light' | 'dark') {
document.documentElement.classList.remove('light', 'dark')
document.documentElement.classList.add(theme)
}
export function initColorMode() {
applyTheme(
window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light',
)
window
.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', mql => {
applyTheme(mql.matches ? 'dark' : 'light')
})
}
+1 -1
View File
@@ -37,7 +37,7 @@ export function Container({
return (
<div
ref={ref}
className="w-full bg-white hover:bg-neutral-50 relative transition-colors max-w-[600px] min-w-[300px] flex border rounded-xl"
className="w-full bg-white text-black hover:bg-neutral-50 dark:bg-dimmedBg dark:hover:bg-dimmedBgLighten relative transition-colors max-w-[600px] min-w-[300px] flex border dark:border-slate-600 dark:text-slate-200 rounded-xl"
onClick={() => {
if (ref.current && href) {
// forwardRef requires preact/compat - let's keep it simple
+20 -14
View File
@@ -78,9 +78,9 @@ export function Embed({
return (
<Link
href={`/profile/${record.author.did}/post/${getRkey(record)}`}
className="transition-colors hover:bg-neutral-100 border rounded-lg p-2 gap-1.5 w-full flex flex-col">
className="transition-colors hover:bg-neutral-100 dark:hover:bg-slate-700 border dark:border-slate-600 rounded-lg p-2 gap-1.5 w-full flex flex-col">
<div className="flex gap-1.5 items-center">
<div className="w-4 h-4 overflow-hidden rounded-full bg-neutral-300 shrink-0">
<div className="w-4 h-4 overflow-hidden rounded-full bg-neutral-300 dark:bg-slate-700 shrink-0">
<img
src={record.author.avatar}
style={isAuthorLabeled ? {filter: 'blur(1.5px)'} : undefined}
@@ -88,7 +88,7 @@ export function Embed({
</div>
<p className="line-clamp-1 text-sm">
<span className="font-bold">{record.author.displayName}</span>
<span className="text-textLight ml-1">
<span className="text-textLight dark:text-textDimmed ml-1">
@{record.author.handle}
</span>
</p>
@@ -209,7 +209,7 @@ function Info({children}: {children: ComponentChildren}) {
return (
<div className="w-full rounded-lg border py-2 px-2.5 flex-row flex gap-2 bg-neutral-50">
<img src={infoIcon} className="w-4 h-4 shrink-0 mt-0.5" />
<p className="text-sm text-textLight">{children}</p>
<p className="text-sm text-textLight dark:text-textDimmed">{children}</p>
</div>
)
}
@@ -308,7 +308,7 @@ function ExternalEmbed({
return (
<Link
href={content.external.uri}
className="w-full rounded-lg overflow-hidden border flex flex-col items-stretch"
className="w-full rounded-lg overflow-hidden border dark:border-slate-600 flex flex-col items-stretch"
disableTracking>
{content.external.thumb && (
<img
@@ -317,11 +317,11 @@ function ExternalEmbed({
/>
)}
<div className="py-3 px-4">
<p className="text-sm text-textLight line-clamp-1">
<p className="text-sm text-textLight dark:text-textDimmed line-clamp-1">
{toNiceDomain(content.external.uri)}
</p>
<p className="font-semibold line-clamp-3">{content.external.title}</p>
<p className="text-sm text-textLight line-clamp-2 mt-0.5">
<p className="text-sm text-textLight dark:text-textDimmed line-clamp-2 mt-0.5">
{content.external.description}
</p>
</div>
@@ -345,23 +345,29 @@ function GenericWithImageEmbed({
return (
<Link
href={href}
className="w-full rounded-lg border py-2 px-3 flex flex-col gap-2">
className="w-full rounded-lg border dark:border-slate-600 py-2 px-3 flex flex-col gap-2">
<div className="flex gap-2.5 items-center">
{image ? (
<img
src={image}
alt={title}
className="w-8 h-8 rounded-md bg-neutral-300 shrink-0"
className="w-8 h-8 rounded-md bg-neutral-300 dark:bg-slate-700 shrink-0"
/>
) : (
<div className="w-8 h-8 rounded-md bg-brand shrink-0" />
)}
<div className="flex-1">
<p className="font-bold text-sm">{title}</p>
<p className="text-textLight text-sm">{subtitle}</p>
<p className="text-textLight dark:text-textDimmed text-sm">
{subtitle}
</p>
</div>
</div>
{description && <p className="text-textLight text-sm">{description}</p>}
{description && (
<p className="text-textLight dark:text-textDimmed text-sm">
{description}
</p>
)}
</Link>
)
}
@@ -406,7 +412,7 @@ function StarterPackEmbed({
return (
<Link
href={starterPackHref}
className="w-full rounded-lg overflow-hidden border flex flex-col items-stretch">
className="w-full rounded-lg overflow-hidden border dark:border-slate-600 flex flex-col items-stretch">
<img src={imageUri} className="aspect-[1.91/1] object-cover" />
<div className="py-3 px-4">
<div className="flex space-x-2 items-center">
@@ -415,7 +421,7 @@ function StarterPackEmbed({
<p className="font-semibold leading-[21px]">
{content.record.name}
</p>
<p className="text-sm text-textLight line-clamp-2 leading-[18px]">
<p className="text-sm text-textLight dark:text-textDimmed line-clamp-2 leading-[18px]">
Starter pack by{' '}
{content.creator.displayName || `@${content.creator.handle}`}
</p>
@@ -425,7 +431,7 @@ function StarterPackEmbed({
<p className="text-sm mt-1">{content.record.description}</p>
)}
{!!content.joinedAllTimeCount && content.joinedAllTimeCount > 50 && (
<p className="text-sm font-semibold text-textLight mt-1">
<p className="text-sm font-semibold text-textLight dark:text-textDimmed mt-1">
{content.joinedAllTimeCount} users have joined!
</p>
)}
+10 -8
View File
@@ -38,7 +38,7 @@ export function Post({thread}: Props) {
<div className="flex-1 flex-col flex gap-2" lang={record?.langs?.[0]}>
<div className="flex gap-2.5 items-center cursor-pointer">
<Link href={`/profile/${post.author.did}`} className="rounded-full">
<div className="w-10 h-10 overflow-hidden rounded-full bg-neutral-300 shrink-0">
<div className="w-10 h-10 overflow-hidden rounded-full bg-neutral-300 dark:bg-slate-700 shrink-0">
<img
src={post.author.avatar}
style={isAuthorLabeled ? {filter: 'blur(2.5px)'} : undefined}
@@ -53,7 +53,7 @@ export function Post({thread}: Props) {
</Link>
<Link
href={`/profile/${post.author.did}`}
className="text-[15px] text-textLight hover:underline line-clamp-1">
className="text-[15px] text-textLight dark:text-textDimmed hover:underline line-clamp-1">
<p>@{post.author.handle}</p>
</Link>
</div>
@@ -69,15 +69,15 @@ export function Post({thread}: Props) {
<Link href={href}>
<time
datetime={new Date(post.indexedAt).toISOString()}
className="text-textLight mt-1 text-sm hover:underline">
className="text-textLight dark:text-textDimmed mt-1 text-sm hover:underline">
{niceDate(post.indexedAt)}
</time>
</Link>
<div className="border-t w-full pt-2.5 flex items-center gap-5 text-sm cursor-pointer">
<div className="border-t dark:border-slate-600 w-full pt-2.5 flex items-center gap-5 text-sm cursor-pointer">
{!!post.likeCount && (
<div className="flex items-center gap-2 cursor-pointer">
<img src={likeIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px">
<p className="font-bold text-neutral-500 dark:text-neutral-300 mb-px">
{prettyNumber(post.likeCount)}
</p>
</div>
@@ -85,17 +85,19 @@ export function Post({thread}: Props) {
{!!post.repostCount && (
<div className="flex items-center gap-2 cursor-pointer">
<img src={repostIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px">
<p className="font-bold text-neutral-500 dark:text-neutral-300 mb-px">
{prettyNumber(post.repostCount)}
</p>
</div>
)}
<div className="flex items-center gap-2 cursor-pointer">
<img src={replyIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px">Reply</p>
<p className="font-bold text-neutral-500 dark:text-neutral-300 mb-px">
Reply
</p>
</div>
<div className="flex-1" />
<p className="cursor-pointer text-brand font-bold hover:underline hidden min-[450px]:inline">
<p className="cursor-pointer text-brand dark:text-brandLighten font-bold hover:underline hidden min-[450px]:inline">
{post.replyCount
? `Read ${prettyNumber(post.replyCount)} ${
post.replyCount > 1 ? 'replies' : 'reply'
+4
View File
@@ -5,3 +5,7 @@
.break-word {
word-break: break-word;
}
:root {
color-scheme: light dark;
}
+18 -13
View File
@@ -6,6 +6,7 @@ import {useEffect, useMemo, useRef, useState} from 'preact/hooks'
import arrowBottom from '../../assets/arrowBottom_stroke2_corner0_rounded.svg'
import logo from '../../assets/logo.svg'
import {initColorMode} from '../color-mode'
import {Container} from '../components/container'
import {Link} from '../components/link'
import {Post} from '../components/post'
@@ -21,6 +22,8 @@ export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js`
const root = document.getElementById('app')
if (!root) throw new Error('No root element')
initColorMode()
const agent = new BskyAgent({
service: 'https://public.api.bsky.app',
})
@@ -108,7 +111,7 @@ function LandingPage() {
}, [uri])
return (
<main className="w-full min-h-screen flex flex-col items-center gap-8 py-14 px-4 md:pt-32">
<main className="w-full min-h-screen flex flex-col items-center gap-8 py-14 px-4 md:pt-32 dark:bg-dimmedBgDarken dark:text-slate-200">
<Link
href="https://bsky.social/about"
className="transition-transform hover:scale-110">
@@ -121,20 +124,22 @@ function LandingPage() {
type="text"
value={uri}
onInput={e => setUri(e.currentTarget.value)}
className="border rounded-lg py-3 w-full max-w-[600px] px-4"
className="border rounded-lg py-3 w-full max-w-[600px] px-4 dark:bg-dimmedBg dark:border-slate-500"
placeholder={DEFAULT_POST}
/>
<img src={arrowBottom} className="w-6" />
<img src={arrowBottom} className="w-6 dark:invert" />
{loading ? (
<Skeleton />
<div className="w-full max-w-[600px]">
<Skeleton />
</div>
) : (
<div className="w-full max-w-[600px] gap-8 flex flex-col">
{!error && thread && uri && <Snippet thread={thread} />}
{!error && thread && <Post thread={thread} key={thread.post.uri} />}
{error && (
<div className="w-full border border-red-500 bg-red-50 px-4 py-3 rounded-lg">
<div className="w-full border border-red-500 bg-red-500/10 px-4 py-3 rounded-lg">
<p className="text-red-500 text-center">{error}</p>
</div>
)}
@@ -149,15 +154,15 @@ function Skeleton() {
<Container>
<div className="flex-1 flex-col flex gap-2 pb-8">
<div className="flex gap-2.5 items-center">
<div className="w-10 h-10 overflow-hidden rounded-full bg-neutral-100 shrink-0 animate-pulse" />
<div className="w-10 h-10 overflow-hidden rounded-full bg-neutral-100 dark:bg-slate-700 shrink-0 animate-pulse" />
<div className="flex-1">
<div className="bg-neutral-100 animate-pulse w-64 h-4 rounded" />
<div className="bg-neutral-100 animate-pulse w-32 h-3 mt-1 rounded" />
<div className="bg-neutral-100 dark:bg-slate-700 animate-pulse w-64 h-4 rounded" />
<div className="bg-neutral-100 dark:bg-slate-700 animate-pulse w-32 h-3 mt-1 rounded" />
</div>
</div>
<div className="w-full h-4 mt-2 bg-neutral-100 rounded animate-pulse" />
<div className="w-5/6 h-4 bg-neutral-100 rounded animate-pulse" />
<div className="w-3/4 h-4 bg-neutral-100 rounded animate-pulse" />
<div className="w-full h-4 mt-2 bg-neutral-100 dark:bg-slate-700 rounded animate-pulse" />
<div className="w-5/6 h-4 bg-neutral-100 dark:bg-slate-700 rounded animate-pulse" />
<div className="w-3/4 h-4 bg-neutral-100 dark:bg-slate-700 rounded animate-pulse" />
</div>
</Container>
)
@@ -220,7 +225,7 @@ function Snippet({thread}: {thread: AppBskyFeedDefs.ThreadViewPost}) {
ref={ref}
type="text"
value={snippet}
className="border rounded-lg py-3 w-full px-4"
className="border rounded-lg py-3 w-full px-4 dark:bg-dimmedBg dark:border-slate-500"
readOnly
autoFocus
onFocus={() => {
@@ -228,7 +233,7 @@ function Snippet({thread}: {thread: AppBskyFeedDefs.ThreadViewPost}) {
}}
/>
<button
className="rounded-lg bg-brand text-white color-white py-3 px-4 whitespace-nowrap min-w-28"
className="rounded-lg bg-brand text-white py-3 px-4 whitespace-nowrap min-w-28"
onClick={() => {
ref.current?.focus()
ref.current?.select()
+6 -3
View File
@@ -4,6 +4,7 @@ import {AppBskyFeedDefs, AtpAgent} from '@atproto/api'
import {h, render} from 'preact'
import logo from '../../assets/logo.svg'
import {initColorMode} from '../color-mode'
import {Container} from '../components/container'
import {Link} from '../components/link'
import {Post} from '../components/post'
@@ -21,6 +22,8 @@ if (!uri) {
throw new Error('No uri in path')
}
initColorMode()
agent
.getPostThread({
uri,
@@ -55,13 +58,13 @@ function PwiOptOut({thread}: {thread: AppBskyFeedDefs.ThreadViewPost}) {
<img src={logo} className="h-6" />
</Link>
<div className="w-full py-12 gap-4 flex flex-col items-center">
<p className="max-w-80 text-center w-full text-textLight">
<p className="max-w-80 text-center w-full text-textLight dark:text-textDimmed">
The author of this post has requested their posts not be displayed on
external sites.
</p>
<Link
href={href}
className="max-w-80 rounded-lg bg-brand text-white color-white text-center py-1 px-4 w-full mx-auto">
className="max-w-80 rounded-lg bg-brand text-white text-center py-1 px-4 w-full mx-auto">
View on Bluesky
</Link>
</div>
@@ -77,7 +80,7 @@ function ErrorMessage() {
className="transition-transform hover:scale-110 absolute top-4 right-4">
<img src={logo} className="h-6" />
</Link>
<p className="my-16 text-center w-full text-textLight">
<p className="my-16 text-center w-full text-textLight dark:text-textDimmed">
Post not found, it may have been deleted.
</p>
</Container>
+8
View File
@@ -1,11 +1,19 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
darkMode: ['variant', [
'&:is(.dark *):not(:is(.dark .light *))',
]],
theme: {
extend: {
colors: {
brand: 'rgb(10,122,255)',
brandLighten: 'rgb(32,139,254)',
textLight: 'rgb(66,87,108)',
textDimmed: 'rgb(174,187,201)',
dimmedBgLighten: 'rgb(30,41,54)',
dimmedBg: 'rgb(22,30,39)',
dimmedBgDarken: 'rgb(18,25,32)',
},
},
},
+1 -2
View File
@@ -1,4 +1,3 @@
{
"compilerOptions": {
"target": "ES5",
@@ -20,5 +19,5 @@
"jsxFragmentFactory": "Fragment",
"downlevelIteration": true
},
"include": ["src", "vite.config.ts"]
"include": ["src", "snippet", "vite.config.ts"]
}
+1 -1
View File
@@ -24,7 +24,7 @@ Then build and copy over the big 'ol `bundle.web.js` file:
### Golang Daemon
Install golang. We are generally using v1.22+.
Install golang. We generally develop against the current stable release of the language, as declared in `go.mod`.
In this directory (`bskyweb/`):
+1
View File
@@ -235,6 +235,7 @@ func serve(cctx *cli.Context) error {
// generic routes
e.GET("/hashtag/:tag", server.WebGeneric)
e.GET("/topic/:topic", server.WebGeneric)
e.GET("/search", server.WebGeneric)
e.GET("/feeds", server.WebGeneric)
e.GET("/notifications", server.WebGeneric)
+2 -2
View File
@@ -1,8 +1,8 @@
module github.com/bluesky-social/social-app/bskyweb
go 1.22
go 1.23
toolchain go1.22.4
toolchain go1.23.4
require (
github.com/bluesky-social/indigo v0.0.0-20240624223826-fd66f93ce141
+3 -4
View File
@@ -13,8 +13,7 @@
<!-- Hello Humans! API docs at https://atproto.com -->
<link rel="preload" as="font" type="font/ttf" href="{{ staticCDNHost }}/static/media/InterVariable.c9f788f6e7ebaec75d7c.ttf">
<link rel="preload" as="font" type="font/ttf" href="{{ staticCDNHost }}/static/media/InterVariable-Italic.55d6a3f35e9b605ba6f4.ttf">
<link rel="preload" as="font" type="font/woff2" href="{{ staticCDNHost }}/static/media/InterVariable.c504db5c06caaf7cdfba.woff2" crossorigin>
<style>
/**
@@ -26,14 +25,14 @@
*/
@font-face {
font-family: 'InterVariable';
src: url("{{ staticCDNHost }}/static/media/InterVariable.c9f788f6e7ebaec75d7c.ttf") format('truetype');
src: url("{{ staticCDNHost }}/static/media/InterVariable.c504db5c06caaf7cdfba.woff2") format('woff2');
font-weight: 300 1000;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'InterVariableItalic';
src: url("{{ staticCDNHost }}/static/media/InterVariable-Italic.55d6a3f35e9b605ba6f4.ttf") format('truetype');
src: url("{{ staticCDNHost }}/static/media/InterVariable-Italic.01dcbad1bac635f9c9cd.woff2") format('woff2');
font-weight: 300 1000;
font-style: italic;
font-display: swap;
+2 -2
View File
@@ -12,14 +12,14 @@
{# don't include the bundle on non-404 error pages #}
{% block head_bundle %}
{% if statusCode == 404 %}
{{ super() }}
{{ block.Super }}
{% else %}
{% endif %}
{% endblock %}
{%- block body_all %}
{% if statusCode == 404 %}
{{ super() }}
{{ block.Super }}
{% else %}
<h1>{{ statusCode }}: Server Error</h1>
<p>Sorry about that! Our <a href="https://bluesky.statuspage.io/">Status Page</a> might have more context.
+6
View File
@@ -87,6 +87,12 @@ However, if you're a part of the Bluesky team and want to enable Sentry, fill in
If you change `SENTRY_AUTH_TOKEN`, you need to do `yarn prebuild` before running `yarn ios` or `yarn android` again.
### Adding bitdrift
Adding bitdirft is NOT required. You can keep `BITDRIFT_API_KEY=` in `.env` which will avoid initializing bitdrift during startup.
However, if you're a part of the Bluesky team and want to enable bitdrift, fill in `BITDRIFT_API_KEY` in your `.env` to enable bitdrift.
### Adding and Updating Locales
- `yarn intl:build` -> you will also need to run this anytime `./src/locale/{locale}/messages.po` change
+1 -2
View File
@@ -5,9 +5,8 @@ import {LogBox} from 'react-native'
import {registerRootComponent} from 'expo'
import App from '#/App'
import {IS_TEST} from '#/env'
if (IS_TEST) {
if (process.env.NODE_ENV === 'test') {
LogBox.ignoreAllLogs() // suppress all logs in tests
} else {
LogBox.ignoreLogs(['Require cycle:']) // suppress require-cycle warnings, it's fine
+16
View File
@@ -105,3 +105,19 @@ jest.mock('expo-modules-core', () => ({
return () => null
}),
}))
jest.mock('expo-localization', () => ({
getLocales: () => [],
}))
jest.mock('statsig-react-native-expo', () => ({
Statsig: {
initialize() {},
initializeCalled() {
return false
},
},
}))
jest.mock('../src/lib/bitdrift', () => ({}))
jest.mock('../src/lib/statsig/statsig', () => ({}))
+4
View File
@@ -6,6 +6,7 @@ module.exports = {
'ast',
'ca',
'de',
'el',
'en-GB',
'es',
'fi',
@@ -17,10 +18,13 @@ module.exports = {
'id',
'it',
'ja',
'km',
'ko',
'ne',
'nl',
'pl',
'pt-BR',
'ro',
'ru',
'th',
'tr',
+2
View File
@@ -14,6 +14,8 @@ if (process.env.BSKY_PROFILE) {
cfg.cacheVersion += ':PROFILE'
}
cfg.resolver.assetExts = [...cfg.resolver.assetExts, 'woff2']
cfg.resolver.resolveRequest = (context, moduleName, platform) => {
// HACK: manually resolve a few packages that use `exports` in `package.json`.
// A proper solution is to enable `unstable_enablePackageExports` but this needs careful testing.
+42 -18
View File
@@ -1,6 +1,6 @@
{
"name": "bsky.app",
"version": "1.96.0",
"version": "1.97.0",
"private": true,
"engines": {
"node": ">=20"
@@ -54,7 +54,7 @@
"icons:optimize": "svgo -f ./assets/icons"
},
"dependencies": {
"@atproto/api": "^0.13.18",
"@atproto/api": "^0.13.21",
"@braintree/sanitize-url": "^6.0.2",
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
"@emoji-mart/react": "^1.1.1",
@@ -62,19 +62,19 @@
"@expo/webpack-config": "^19.0.0",
"@floating-ui/dom": "^1.6.3",
"@floating-ui/react-dom": "^2.0.8",
"@formatjs/intl-locale": "^4.0.0",
"@formatjs/intl-numberformat": "^8.10.3",
"@formatjs/intl-pluralrules": "^5.2.14",
"@formatjs/intl-locale": "^4.2.8",
"@formatjs/intl-numberformat": "^8.15.1",
"@formatjs/intl-pluralrules": "^5.4.1",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/react-native-fontawesome": "^0.3.2",
"@haileyok/bluesky-video": "0.2.4",
"@haileyok/bluesky-video": "0.2.6",
"@ipld/dag-cbor": "^9.2.0",
"@lingui/react": "^4.14.1",
"@mattermost/react-native-paste-input": "^0.7.1",
"@miblanchard/react-native-slider": "^2.3.1",
"@mozzius/expo-dynamic-app-icon": "^1.4.1",
"@mozzius/expo-dynamic-app-icon": "^1.5.0",
"@radix-ui/react-dismissable-layer": "^1.1.1",
"@radix-ui/react-dropdown-menu": "2.0.1",
"@radix-ui/react-focus-guards": "^1.1.1",
@@ -118,7 +118,7 @@
"emoji-mart": "^5.5.2",
"emoji-regex": "^10.4.0",
"eventemitter3": "^5.0.1",
"expo": "~52.0.17",
"expo": "~52.0.19",
"expo-application": "^6.0.1",
"expo-blur": "^14.0.1",
"expo-build-properties": "^0.13.1",
@@ -126,7 +126,7 @@
"expo-clipboard": "^7.0.0",
"expo-dev-client": "^5.0.4",
"expo-device": "~7.0.1",
"expo-file-system": "^18.0.4",
"expo-file-system": "^18.0.6",
"expo-font": "~13.0.1",
"expo-haptics": "^14.0.0",
"expo-image": "~2.0.3",
@@ -137,13 +137,14 @@
"expo-localization": "~16.0.0",
"expo-media-library": "~17.0.3",
"expo-navigation-bar": "~4.0.4",
"expo-notifications": "~0.29.10",
"expo-notifications": "~0.29.11",
"expo-screen-orientation": "^8.0.2",
"expo-sharing": "^13.0.0",
"expo-splash-screen": "~0.29.16",
"expo-splash-screen": "~0.29.18",
"expo-status-bar": "~2.0.0",
"expo-system-ui": "^4.0.4",
"expo-task-manager": "~12.0.3",
"expo-updates": "~0.26.9",
"expo-updates": "~0.26.10",
"expo-web-browser": "~14.0.1",
"fast-text-encoding": "^1.0.6",
"history": "^5.3.0",
@@ -170,7 +171,7 @@
"react-native": "0.76.3",
"react-native-compressor": "1.10.3",
"react-native-date-picker": "^5.0.7",
"react-native-drawer-layout": "^4.0.4",
"react-native-drawer-layout": "^4.1.1",
"react-native-gesture-handler": "2.20.2",
"react-native-get-random-values": "~1.11.0",
"react-native-image-crop-picker": "^0.41.6",
@@ -181,7 +182,7 @@
"react-native-picker-select": "^9.3.1",
"react-native-progress": "bluesky-social/react-native-progress",
"react-native-qrcode-styled": "^0.3.3",
"react-native-reanimated": "^3.16.3",
"react-native-reanimated": "3.17.0-nightly-20241211-17e89ca24",
"react-native-root-siblings": "^4.1.1",
"react-native-safe-area-context": "4.14.0",
"react-native-screens": "~4.3.0",
@@ -205,13 +206,12 @@
"zod": "^3.20.2"
},
"devDependencies": {
"@atproto/dev-env": "^0.3.64",
"@atproto/dev-env": "^0.3.67",
"@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0",
"@babel/runtime": "^7.26.0",
"@did-plc/server": "^0.0.1",
"@expo/config-plugins": "9.0.10",
"@expo/prebuild-config": "8.0.22",
"@lingui/cli": "^4.14.1",
"@lingui/macro": "^4.14.1",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
@@ -250,6 +250,7 @@
"jest-expo": "^52.0.2",
"jest-junit": "^16.0.0",
"lint-staged": "^13.2.3",
"lockfile-lint": "^4.14.0",
"metro-react-native-babel-preset": "^0.76.9",
"prettier": "^2.8.3",
"react-native-dotenv": "^3.4.11",
@@ -266,8 +267,8 @@
"@react-native/normalize-colors": "0.76.1",
"@radix-ui/react-focus-scope": "1.1.0",
"@types/react": "^18",
"**/expo-constants": "16.0.1",
"**/expo-device": "6.0.2",
"**/expo-constants": "17.0.3",
"**/expo-device": "7.0.1",
"**/zod": "3.23.8"
},
"jest": {
@@ -329,5 +330,28 @@
"assets/icons/*.svg": [
"svgo"
]
},
"lockfile-lint": {
"path": "yarn.lock",
"allowedHosts": [
"npm",
"yarn"
],
"allowedSchemes": [
"https:"
],
"allowedPackageNameAliases": [
"@babel/traverse--for-generate-function-map:@babel/traverse",
"string-width-cjs:string-width",
"strip-ansi-cjs:strip-ansi",
"wrap-ansi-cjs:wrap-ansi"
],
"allowedUrls": [
"https://codeload.github.com/bluesky-social/react-native-bottom-sheet/tar.gz/28a87d1bb55e10fc355fa1455545a30734995908",
"https://codeload.github.com/bluesky-social/react-native-progress/tar.gz/5a372f4f2ce5feb26f4f47b6a4d187ab9b923ab4"
],
"emptyHostname": false,
"validatePackageNames": true,
"validateIntegrity": true
}
}
@@ -1,16 +1,157 @@
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..0564d97 100644
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
@@ -22,6 +22,11 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
_backedTextInputView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_backedTextInputView.textInputDelegate = self;
+ // Disable inline predictions to prevent jank in the composer
@@ -4,6 +4,7 @@
//
// Created by Elias Nahum on 04-11-20.
// Copyright © 2020 Facebook. All rights reserved.
+// Updated to remove parents 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 supers 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, *)) {
+ _backedTextInputView.inlinePredictionType = UITextInlinePredictionTypeNo;
+ _customBackedTextView.inlinePredictionType = UITextInlinePredictionTypeNo;
+ }
+
[self addSubview:_backedTextInputView];
}
+ // 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)scrollViewDidScroll:(UIScrollView *)scrollView
{
RCTDirectEventBlock onScroll = self.onScroll;
-
if (onScroll) {
CGPoint contentOffset = scrollView.contentOffset;
CGSize contentSize = scrollView.contentSize;
@@ -71,22 +100,22 @@
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),
});
+101
View File
@@ -0,0 +1,101 @@
diff --git a/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts b/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts
new file mode 100644
index 0000000..babbb3b
--- /dev/null
+++ b/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts
@@ -0,0 +1,60 @@
+import { useReleasingSharedObject } from 'expo-modules-core';
+import { SharedRef } from 'expo-modules-core/types';
+
+import { Action, ImageResult, SaveFormat, SaveOptions } from './ImageManipulator.types';
+import { ImageManipulatorContext } from './ImageManipulatorContext';
+import ExpoImageManipulator from './NativeImageManipulatorModule';
+import { validateArguments } from './validators';
+
+// @needsAudit
+/**
+ * Manipulate the image provided via `uri`. Available modifications are rotating, flipping (mirroring),
+ * resizing and cropping. Each invocation results in a new file. With one invocation you can provide
+ * a set of actions to perform over the image. Overwriting the source file would not have an effect
+ * in displaying the result as images are cached.
+ * @param uri URI of the file to manipulate. Should be on the local file system or a base64 data URI.
+ * @param actions An array of objects representing manipulation options. Each object should have
+ * __only one__ of the keys that corresponds to specific transformation.
+ * @param saveOptions A map defining how modified image should be saved.
+ * @return Promise which fulfils with [`ImageResult`](#imageresult) object.
+ * @deprecated It has been replaced by the new, contextual and object-oriented API.
+ * Use [`ImageManipulator.manipulate`](#manipulateuri) or [`useImageManipulator`](#useimagemanipulatoruri) instead.
+ */
+export async function manipulateAsync(
+ uri: string,
+ actions: Action[] = [],
+ saveOptions: SaveOptions = {}
+): Promise<ImageResult> {
+ validateArguments(uri, actions, saveOptions);
+
+ const { format = SaveFormat.JPEG, ...rest } = saveOptions;
+ const context = ExpoImageManipulator.manipulate(uri);
+
+ for (const action of actions) {
+ if ('resize' in action) {
+ context.resize(action.resize);
+ } else if ('rotate' in action) {
+ context.rotate(action.rotate);
+ } else if ('flip' in action) {
+ context.flip(action.flip);
+ } else if ('crop' in action) {
+ context.crop(action.crop);
+ } else if ('extent' in action && context.extent) {
+ context.extent(action.extent);
+ }
+ }
+ const image = await context.renderAsync(saveOptions.compress);
+ const result = await image.saveAsync({ format, ...rest });
+
+ // These shared objects will not be used anymore, so free up some memory.
+ context.release();
+ image.release();
+
+ return result;
+}
+
+export function useImageManipulator(source: string | SharedRef<'image'>): ImageManipulatorContext {
+ return useReleasingSharedObject(() => ExpoImageManipulator.manipulate(source), [source]);
+}
+
+export { ExpoImageManipulator as ImageManipulator };
diff --git a/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts b/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts
index 120d8d3..f8aa49c 100644
--- a/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts
+++ b/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts
@@ -52,7 +52,7 @@ export declare class ImageManipulatorContext extends SharedObject {
/**
* Awaits for all manipulation tasks to finish and resolves with a reference to the resulted native image.
*/
- renderAsync(): Promise<ImageRef>;
+ renderAsync(compress?: number): Promise<ImageRef>;
}
export default ExpoImageManipulator.Context as typeof ImageManipulatorContext;
diff --git a/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts b/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts
index 428848c..363a57a 100644
--- a/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts
+++ b/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts
@@ -41,7 +41,7 @@ export default class ImageManipulatorContext extends SharedObject {
return this;
}
- async renderAsync(): Promise<ImageManipulatorImageRef> {
+ async renderAsync(compress?: number): Promise<ImageManipulatorImageRef> {
const canvas = await this.currentTask;
return new Promise((resolve) => {
@@ -49,7 +49,7 @@ export default class ImageManipulatorContext extends SharedObject {
const url = blob ? URL.createObjectURL(blob) : canvas.toDataURL();
resolve(new ImageManipulatorImageRef(url, canvas.width, canvas.height));
- });
+ }, typeof compress === 'number' ? 'image/jpeg' : undefined, compress);
});
}
+19
View File
@@ -0,0 +1,19 @@
diff --git a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt
index b928b8f..7175cf6 100644
--- a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt
+++ b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt
@@ -99,12 +99,12 @@ class MediaLibraryModule : Module() {
}
AsyncFunction("createAssetAsync") { localUri: String, promise: Promise ->
- throwUnlessPermissionsGranted {
+ //throwUnlessPermissionsGranted {
withModuleScope(promise) {
CreateAsset(context, localUri, promise)
.execute()
}
- }
+ //}
}
AsyncFunction("addAssetsToAlbumAsync") { assetsId: List<String>, albumId: String, copyToAlbum: Boolean, promise: Promise ->
+3
View File
@@ -0,0 +1,3 @@
## expo-modules-core Patch
This patch fixes an issue where bitdrift's API stream gets blocked by the Expo interceptor used to power the devtools
+15
View File
@@ -0,0 +1,15 @@
diff --git a/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt b/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt
index 47c4d15..afe138d 100644
--- a/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt
+++ b/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/devtools/ExpoNetworkInspectOkHttpInterceptors.kt
@@ -125,6 +125,10 @@ internal fun peekResponseBody(
}
internal fun shouldParseBody(response: Response): Boolean {
+ if (response.request.url.encodedPath == "/bitdrift_public.protobuf.client.v1.ApiService/Mux") {
+ return false
+ }
+
// Check for Content-Type
val skipContentTypes = listOf(
"text/event-stream", // Server Sent Events
+36 -1
View File
@@ -222,7 +222,7 @@ index 40aaf9c..1c60164 100644
{
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m
index e9ce48c..ccd9ad6 100644
index e9ce48c..84a6fca 100644
--- a/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m
+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m
@@ -159,26 +159,8 @@ - (BOOL)touchesShouldCancelInContentView:(__unused UIView *)view
@@ -329,3 +329,38 @@ index e9ce48c..ccd9ad6 100644
}
}
@@ -1055,6 +1082,22 @@ -(type)getter \
RCT_SET_AND_PRESERVE_OFFSET(setShowsVerticalScrollIndicator, showsVerticalScrollIndicator, BOOL)
RCT_SET_AND_PRESERVE_OFFSET(setZoomScale, zoomScale, CGFloat);
+- (void)setScrollIndicatorInsets:(UIEdgeInsets)value
+{
+ [_scrollView setScrollIndicatorInsets:value];
+}
+
+- (UIEdgeInsets)scrollIndicatorInsets
+{
+ UIEdgeInsets verticalScrollIndicatorInsets = [_scrollView verticalScrollIndicatorInsets];
+ UIEdgeInsets horizontalScrollIndicatorInsets = [_scrollView horizontalScrollIndicatorInsets];
+ return UIEdgeInsetsMake(
+ verticalScrollIndicatorInsets.top,
+ horizontalScrollIndicatorInsets.left,
+ verticalScrollIndicatorInsets.bottom,
+ horizontalScrollIndicatorInsets.right);
+}
+
- (void)setAutomaticallyAdjustsScrollIndicatorInsets:(BOOL)automaticallyAdjusts API_AVAILABLE(ios(13.0))
{
// `automaticallyAdjustsScrollIndicatorInsets` is available since iOS 13.
diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
index cd1e7eb..c1d0172 100644
--- a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
@@ -83,6 +83,7 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval)
RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
+RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets)
RCT_EXPORT_VIEW_PROPERTY(verticalScrollIndicatorInsets, UIEdgeInsets)
RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
@@ -0,0 +1,36 @@
diff --git a/node_modules/react-native-gesture-handler/apple/RNGestureHandler.mm b/node_modules/react-native-gesture-handler/apple/RNGestureHandler.mm
index 43d11b4..5bf0d32 100644
--- a/node_modules/react-native-gesture-handler/apple/RNGestureHandler.mm
+++ b/node_modules/react-native-gesture-handler/apple/RNGestureHandler.mm
@@ -461,16 +461,23 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
- if ([_handlersToWaitFor count]) {
- RNGestureHandler *handler = [RNGestureHandler findGestureHandlerByRecognizer:otherGestureRecognizer];
- if (handler != nil) {
- for (NSNumber *handlerTag in _handlersToWaitFor) {
- if ([handler.tag isEqual:handlerTag]) {
- return YES;
- }
- }
+ RNGestureHandler *handler = [RNGestureHandler findGestureHandlerByRecognizer:otherGestureRecognizer];
+ if (handler == nil) {
+ return NO;
+ }
+
+ for (NSNumber *handlerTag in _handlersToWaitFor) {
+ if ([handler.tag isEqual:handlerTag]) {
+ return YES;
}
}
+
+ for (NSNumber *handlerTag in handler->_handlersThatShouldWait) {
+ if ([_tag isEqual:handlerTag]) {
+ return YES;
+ }
+ }
+
return NO;
}
@@ -0,0 +1,47 @@
diff --git a/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml b/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml
index 391f303..8e2c3db 100644
--- a/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml
+++ b/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml
@@ -24,7 +24,7 @@
<activity
android:name="com.yalantis.ucrop.UCropActivity"
- android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
+ android:theme="@style/Theme.UCropNoEdgeToEdge" />
</application>
</manifest>
diff --git a/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml b/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml
new file mode 100644
index 0000000..396d5a8
--- /dev/null
+++ b/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml
@@ -0,0 +1,5 @@
+<resources>
+ <style name="Theme.UCropNoEdgeToEdge" parent="Theme.AppCompat.Light.NoActionBar">
+ <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
+ </style>
+</resources>
diff --git a/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml b/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml
new file mode 100644
index 0000000..50129b6
--- /dev/null
+++ b/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml
@@ -0,0 +1,3 @@
+<resources>
+ <style name="Theme.UCropNoEdgeToEdge" parent="Theme.AppCompat.Light.NoActionBar"/>
+</resources>
diff --git a/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m b/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m
index 9f20973..68d4766 100644
--- a/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m
+++ b/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m
@@ -126,7 +126,8 @@ - (void) setConfiguration:(NSDictionary *)options
- (UIViewController*) getRootVC {
UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
- while (root.presentedViewController != nil) {
+ while (root.presentedViewController != nil &&
+ !root.presentedViewController.isBeingDismissed) {
root = root.presentedViewController;
}
+20
View File
@@ -0,0 +1,20 @@
const {withProjectBuildGradle} = require('@expo/config-plugins')
const jitpackRepository = "maven { url 'https://www.jitpack.io' }"
module.exports = function withAndroidNoJitpackPlugin(config) {
return withProjectBuildGradle(config, config => {
if (!config.modResults.contents.includes(jitpackRepository)) {
throw Error(
'Expected to find the jitpack string in the config. ' +
'You MUST verify whether it was actually removed upstream, ' +
'or if the format has changed and this plugin no longer recognizes it.',
)
}
config.modResults.contents = config.modResults.contents.replaceAll(
jitpackRepository,
'',
)
return config
})
}
+108 -221
View File
@@ -1,232 +1,119 @@
import 'react-native-url-polyfill/auto'
import '#/lib/sentry' // must be near top
import '#/view/icons'
import React, {useEffect, useState} from 'react'
import {GestureHandlerRootView} from 'react-native-gesture-handler'
import {RootSiblingParent} from 'react-native-root-siblings'
import {useState} from 'react'
import {ScrollView, Text, View} from 'react-native'
import {
initialWindowMetrics,
SafeAreaProvider,
} from 'react-native-safe-area-context'
import * as SplashScreen from 'expo-splash-screen'
import * as SystemUI from 'expo-system-ui'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
Gesture,
GestureDetector,
GestureHandlerRootView,
} from 'react-native-gesture-handler'
import PagerView from 'react-native-pager-view'
import Animated, {
useAnimatedStyle,
useSharedValue,
} from 'react-native-reanimated'
import {KeyboardControllerProvider} from '#/lib/hooks/useEnableKeyboardController'
import {QueryProvider} from '#/lib/react-query'
import {
initialize,
Provider as StatsigProvider,
tryFetchGates,
} from '#/lib/statsig/statsig'
import {s} from '#/lib/styles'
import {ThemeProvider} from '#/lib/ThemeContext'
import I18nProvider from '#/locale/i18nProvider'
import {logger} from '#/logger'
import {isIOS} from '#/platform/detection'
import {Provider as A11yProvider} from '#/state/a11y'
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
import {Provider as DialogStateProvider} from '#/state/dialogs'
import {listenSessionDropped} from '#/state/events'
import {
beginResolveGeolocation,
ensureGeolocationResolved,
Provider as GeolocationProvider,
} from '#/state/geolocation'
import {Provider as InvitesStateProvider} from '#/state/invites'
import {Provider as LightboxStateProvider} from '#/state/lightbox'
import {MessagesProvider} from '#/state/messages'
import {Provider as ModalStateProvider} from '#/state/modals'
import {init as initPersistedState} from '#/state/persisted'
import {Provider as PrefsStateProvider} from '#/state/preferences'
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread'
import {
Provider as SessionProvider,
SessionAccount,
useSession,
useSessionApi,
} from '#/state/session'
import {readLastActiveAccount} from '#/state/session/util'
import {Provider as ShellStateProvider} from '#/state/shell'
import {Provider as ComposerProvider} from '#/state/shell/composer'
import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
import {TestCtrls} from '#/view/com/testing/TestCtrls'
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
import * as Toast from '#/view/com/util/Toast'
import {Shell} from '#/view/shell'
import {ThemeProvider as Alf} from '#/alf'
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {NuxDialogs} from '#/components/dialogs/nuxs'
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
import {Provider as PortalProvider} from '#/components/Portal'
import {AppProfiler} from '#/AppProfiler'
import {Splash} from '#/Splash'
import {BottomSheetProvider} from '../modules/bottom-sheet'
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
export default function App() {
const val = useSharedValue(0)
const [swipeEnabled, setSwipeEnabled] = useState(true)
SplashScreen.preventAutoHideAsync()
if (isIOS) {
SystemUI.setBackgroundColorAsync('black')
}
/**
* Begin geolocation ASAP
*/
beginResolveGeolocation()
function InnerApp() {
const [isReady, setIsReady] = React.useState(false)
const {currentAccount} = useSession()
const {resumeSession} = useSessionApi()
const theme = useColorModeTheme()
const {_} = useLingui()
const hasCheckedReferrer = useStarterPackEntry()
// init
useEffect(() => {
async function onLaunch(account?: SessionAccount) {
try {
if (account) {
await resumeSession(account)
} else {
await initialize()
await tryFetchGates(undefined, 'prefer-fresh-gates')
}
} catch (e) {
logger.error(`session: resume failed`, {message: e})
} finally {
setIsReady(true)
}
}
const account = readLastActiveAccount()
onLaunch(account)
}, [resumeSession])
useEffect(() => {
return listenSessionDropped(() => {
Toast.show(
_(msg`Sorry! Your session expired. Please log in again.`),
'info',
)
let pan = Gesture.Pan()
.onBegin(() => {
'worklet'
console.log('begin')
val.set(0)
})
.onUpdate(e => {
'worklet'
console.log('update')
val.set(e.translationX)
})
.onEnd(() => {
'worklet'
console.log('end')
val.set(0)
})
.onFinalize(() => {
'worklet'
console.log('finalize')
val.set(0)
})
}, [_])
return (
<Alf theme={theme}>
<ThemeProvider theme={theme}>
<Splash isReady={isReady && hasCheckedReferrer}>
<RootSiblingParent>
<VideoVolumeProvider>
<React.Fragment
// Resets the entire tree below when it changes:
key={currentAccount?.did}>
<QueryProvider currentDid={currentAccount?.did}>
<ComposerProvider>
<StatsigProvider>
<MessagesProvider>
{/* LabelDefsProvider MUST come before ModerationOptsProvider */}
<LabelDefsProvider>
<ModerationOptsProvider>
<LoggedOutViewProvider>
<SelectedFeedProvider>
<HiddenRepliesProvider>
<UnreadNotifsProvider>
<BackgroundNotificationPreferencesProvider>
<MutedThreadsProvider>
<ProgressGuideProvider>
<GestureHandlerRootView
style={s.h100pct}>
<TestCtrls />
<Shell />
<NuxDialogs />
</GestureHandlerRootView>
</ProgressGuideProvider>
</MutedThreadsProvider>
</BackgroundNotificationPreferencesProvider>
</UnreadNotifsProvider>
</HiddenRepliesProvider>
</SelectedFeedProvider>
</LoggedOutViewProvider>
</ModerationOptsProvider>
</LabelDefsProvider>
</MessagesProvider>
</StatsigProvider>
</ComposerProvider>
</QueryProvider>
</React.Fragment>
</VideoVolumeProvider>
</RootSiblingParent>
</Splash>
</ThemeProvider>
</Alf>
)
}
function App() {
const [isReady, setReady] = useState(false)
React.useEffect(() => {
Promise.all([initPersistedState(), ensureGeolocationResolved()]).then(() =>
setReady(true),
)
}, [])
if (!isReady) {
return null
if (swipeEnabled) {
pan = pan.failOffsetX(-1).activeOffsetX(5)
} else {
pan = pan.failOffsetX([0, 0]).failOffsetY([0, 0])
}
/*
* NOTE: only nothing here can depend on other data or session state, since
* that is set up in the InnerApp component above.
*/
const style = useAnimatedStyle(() => {
return {
flex: 1,
transform: [
{
translateX: val.value,
},
],
}
})
return (
<AppProfiler>
<GeolocationProvider>
<A11yProvider>
<KeyboardControllerProvider>
<SessionProvider>
<PrefsStateProvider>
<I18nProvider>
<ShellStateProvider>
<InvitesStateProvider>
<ModalStateProvider>
<DialogStateProvider>
<LightboxStateProvider>
<PortalProvider>
<BottomSheetProvider>
<StarterPackProvider>
<SafeAreaProvider
initialMetrics={initialWindowMetrics}>
<IntentDialogProvider>
<InnerApp />
</IntentDialogProvider>
</SafeAreaProvider>
</StarterPackProvider>
</BottomSheetProvider>
</PortalProvider>
</LightboxStateProvider>
</DialogStateProvider>
</ModalStateProvider>
</InvitesStateProvider>
</ShellStateProvider>
</I18nProvider>
</PrefsStateProvider>
</SessionProvider>
</KeyboardControllerProvider>
</A11yProvider>
</GeolocationProvider>
</AppProfiler>
<GestureHandlerRootView>
<GestureDetector gesture={pan}>
<Animated.View style={style}>
<Pager pan={pan} setSwipeEnabled={setSwipeEnabled}>
<InnerScrollView pan={pan} />
</Pager>
</Animated.View>
</GestureDetector>
</GestureHandlerRootView>
)
}
export default App
function Pager({children, pan, setSwipeEnabled}) {
const native = Gesture.Native().requireExternalGestureToFail(pan)
return (
<GestureDetector gesture={native}>
<PagerView
overdrag={true}
initialPage={0}
style={{
flex: 1,
backgroundColor: 'green',
}}
onPageSelected={e => {
setSwipeEnabled(e.nativeEvent.position === 0)
}}>
{children}
{children}
{children}
</PagerView>
</GestureDetector>
)
}
function InnerScrollView({pan}) {
const native = Gesture.Native().blocksExternalGesture(pan)
return (
<View
style={{
paddingTop: 200,
alignItems: 'center',
}}>
<GestureDetector gesture={native}>
<ScrollView
horizontal
pagingEnabled
style={{
width: 300,
backgroundColor: 'yellow',
height: 200,
}}>
<Text
style={{
width: 1000,
}}>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
27 28 29 30 31 32 33 34 35 36 37 38 39 40
</Text>
</ScrollView>
</GestureDetector>
</View>
)
}
+23 -14
View File
@@ -22,6 +22,7 @@ import {
ensureGeolocationResolved,
Provider as GeolocationProvider,
} from '#/state/geolocation'
import {Provider as HomeBadgeProvider} from '#/state/home-badge'
import {Provider as InvitesStateProvider} from '#/state/invites'
import {Provider as LightboxStateProvider} from '#/state/lightbox'
import {MessagesProvider} from '#/state/messages'
@@ -40,11 +41,13 @@ import {
import {readLastActiveAccount} from '#/state/session/util'
import {Provider as ShellStateProvider} from '#/state/shell'
import {Provider as ComposerProvider} from '#/state/shell/composer'
import {Provider as LightStatusBarProvider} from '#/state/shell/light-status-bar'
import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
import {Provider as TrendingConfigProvider} from '#/state/trending-config'
import {Provider as ActiveVideoProvider} from '#/view/com/util/post-embeds/ActiveVideoWebContext'
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
import * as Toast from '#/view/com/util/Toast'
@@ -119,18 +122,24 @@ function InnerApp() {
<LoggedOutViewProvider>
<SelectedFeedProvider>
<HiddenRepliesProvider>
<UnreadNotifsProvider>
<BackgroundNotificationPreferencesProvider>
<MutedThreadsProvider>
<SafeAreaProvider>
<ProgressGuideProvider>
<Shell />
<NuxDialogs />
</ProgressGuideProvider>
</SafeAreaProvider>
</MutedThreadsProvider>
</BackgroundNotificationPreferencesProvider>
</UnreadNotifsProvider>
<HomeBadgeProvider>
<UnreadNotifsProvider>
<BackgroundNotificationPreferencesProvider>
<MutedThreadsProvider>
<SafeAreaProvider>
<ProgressGuideProvider>
<TrendingConfigProvider>
<IntentDialogProvider>
<Shell />
<NuxDialogs />
</IntentDialogProvider>
</TrendingConfigProvider>
</ProgressGuideProvider>
</SafeAreaProvider>
</MutedThreadsProvider>
</BackgroundNotificationPreferencesProvider>
</UnreadNotifsProvider>
</HomeBadgeProvider>
</HiddenRepliesProvider>
</SelectedFeedProvider>
</LoggedOutViewProvider>
@@ -180,9 +189,9 @@ function App() {
<LightboxStateProvider>
<PortalProvider>
<StarterPackProvider>
<IntentDialogProvider>
<LightStatusBarProvider>
<InnerApp />
</IntentDialogProvider>
</LightStatusBarProvider>
</StarterPackProvider>
</PortalProvider>
</LightboxStateProvider>
-29
View File
@@ -1,29 +0,0 @@
import React, {Profiler} from 'react'
// Don't let it get stripped out in profiling builds (which apply production Babel preset).
const log = (global as any)['con' + 'sole'].log
function onRender(id: string, phase: string, actualDuration: number) {
if (!__DEV__) {
// This block of code will exist in the production build of the app.
// However, only profiling builds of React call `onRender` so it's dead code in actual production.
const message = `<Profiler> ${id}:${phase} ${
actualDuration > 500
? '(╯°□°)╯ '
: actualDuration > 100
? '[!!] '
: actualDuration > 16
? '[!] '
: ''
}${Math.round(actualDuration)}ms`
log(message)
}
}
export function AppProfiler({children}: {children: React.ReactNode}) {
return (
<Profiler id="app" onRender={onRender}>
{children}
</Profiler>
)
}
+9 -3
View File
@@ -55,10 +55,7 @@ import {NotificationsScreen} from '#/view/screens/Notifications'
import {PostThreadScreen} from '#/view/screens/PostThread'
import {PrivacyPolicyScreen} from '#/view/screens/PrivacyPolicy'
import {ProfileScreen} from '#/view/screens/Profile'
import {ProfileFeedScreen} from '#/view/screens/ProfileFeed'
import {ProfileFeedLikedByScreen} from '#/view/screens/ProfileFeedLikedBy'
import {ProfileFollowersScreen} from '#/view/screens/ProfileFollowers'
import {ProfileFollowsScreen} from '#/view/screens/ProfileFollows'
import {ProfileListScreen} from '#/view/screens/ProfileList'
import {SavedFeeds} from '#/view/screens/SavedFeeds'
import {SearchScreen} from '#/view/screens/Search'
@@ -77,6 +74,9 @@ import {PostLikedByScreen} from '#/screens/Post/PostLikedBy'
import {PostQuotesScreen} from '#/screens/Post/PostQuotes'
import {PostRepostedByScreen} from '#/screens/Post/PostRepostedBy'
import {ProfileKnownFollowersScreen} from '#/screens/Profile/KnownFollowers'
import {ProfileFeedScreen} from '#/screens/Profile/ProfileFeed'
import {ProfileFollowersScreen} from '#/screens/Profile/ProfileFollowers'
import {ProfileFollowsScreen} from '#/screens/Profile/ProfileFollows'
import {ProfileLabelerLikedByScreen} from '#/screens/Profile/ProfileLabelerLikedBy'
import {AppearanceSettingsScreen} from '#/screens/Settings/AppearanceSettings'
import {AppIconSettingsScreen} from '#/screens/Settings/AppIconSettings'
@@ -100,6 +100,7 @@ import {LanguageSettingsScreen} from './screens/Settings/LanguageSettings'
import {PrivacyAndSecuritySettingsScreen} from './screens/Settings/PrivacyAndSecuritySettings'
import {SettingsScreen} from './screens/Settings/Settings'
import {ThreadPreferencesScreen} from './screens/Settings/ThreadPreferences'
import TopicScreen from './screens/Topic'
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
@@ -376,6 +377,11 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
getComponent={() => HashtagScreen}
options={{title: title(msg`Hashtag`)}}
/>
<Stack.Screen
name="Topic"
getComponent={() => TopicScreen}
options={{title: title(msg`Topic`)}}
/>
<Stack.Screen
name="MessagesConversation"
getComponent={() => MessagesConversationScreen}
+15
View File
@@ -158,6 +158,9 @@ export const atoms = {
flex_wrap: {
flexWrap: 'wrap',
},
flex_nowrap: {
flexWrap: 'nowrap',
},
flex_0: {
flex: web('0 0 auto') || (native(0) as number),
},
@@ -302,6 +305,18 @@ export const atoms = {
border_0: {
borderWidth: 0,
},
border_t_0: {
borderTopWidth: 0,
},
border_b_0: {
borderBottomWidth: 0,
},
border_l_0: {
borderLeftWidth: 0,
},
border_r_0: {
borderRightWidth: 0,
},
border: {
borderWidth: StyleSheet.hairlineWidth,
},
+28
View File
@@ -0,0 +1,28 @@
import {useMemo} from 'react'
import {useMediaQuery} from 'react-responsive'
export type Breakpoint = 'gtPhone' | 'gtMobile' | 'gtTablet'
export function useBreakpoints(): Record<Breakpoint, boolean> & {
activeBreakpoint: Breakpoint | undefined
} {
const gtPhone = useMediaQuery({minWidth: 500})
const gtMobile = useMediaQuery({minWidth: 800})
const gtTablet = useMediaQuery({minWidth: 1300})
return useMemo(() => {
let active: Breakpoint | undefined
if (gtTablet) {
active = 'gtTablet'
} else if (gtMobile) {
active = 'gtMobile'
} else if (gtPhone) {
active = 'gtPhone'
}
return {
activeBreakpoint: active,
gtPhone,
gtMobile,
gtTablet,
}
}, [gtPhone, gtMobile, gtTablet])
}
+2 -13
View File
@@ -1,5 +1,4 @@
import React from 'react'
import {useMediaQuery} from 'react-responsive'
import {
computeFontScaleMultiplier,
@@ -14,13 +13,14 @@ import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration'
import {Device} from '#/storage'
export {atoms} from '#/alf/atoms'
export * from '#/alf/breakpoints'
export * from '#/alf/fonts'
export * as tokens from '#/alf/tokens'
export * from '#/alf/types'
export * from '#/alf/util/flatten'
export * from '#/alf/util/platform'
export * from '#/alf/util/themeSelector'
export * from '#/alf/util/useGutterStyles'
export * from '#/alf/util/useGutters'
export type Alf = {
themeName: ThemeName
@@ -142,14 +142,3 @@ export function useTheme(theme?: ThemeName) {
return theme ? alf.themes[theme] : alf.theme
}, [theme, alf])
}
export function useBreakpoints() {
const gtPhone = useMediaQuery({minWidth: 500})
const gtMobile = useMediaQuery({minWidth: 800})
const gtTablet = useMediaQuery({minWidth: 1300})
return {
gtPhone,
gtMobile,
gtTablet,
}
}
+4
View File
@@ -60,6 +60,7 @@ export function createThemes({
dim: Theme
} {
const color = {
like: '#ec4899',
trueBlack: '#000000',
gray_0: `hsl(${hues.primary}, 20%, ${defaultScale[14]}%)`,
@@ -124,6 +125,7 @@ export function createThemes({
const lightPalette = {
white: color.gray_0,
black: color.gray_1000,
like: color.like,
contrast_25: color.gray_25,
contrast_50: color.gray_50,
@@ -185,6 +187,7 @@ export function createThemes({
const darkPalette: Palette = {
white: color.gray_25,
black: color.trueBlack,
like: color.like,
contrast_25: color.gray_975,
contrast_50: color.gray_950,
@@ -246,6 +249,7 @@ export function createThemes({
const dimPalette: Palette = {
...darkPalette,
black: `hsl(${hues.primary}, 28%, ${dimScale[0]}%)`,
like: color.like,
contrast_25: `hsl(${hues.primary}, 28%, ${dimScale[1]}%)`,
contrast_50: `hsl(${hues.primary}, 28%, ${dimScale[2]}%)`,
+1
View File
@@ -12,6 +12,7 @@ export type ThemeName = 'light' | 'dim' | 'dark'
export type Palette = {
white: string
black: string
like: string
contrast_25: string
contrast_50: string
+1 -3
View File
@@ -110,9 +110,7 @@ export function renderChildrenWithEmoji(
return child.split(EMOJI).map((stringPart, index) => [
stringPart,
emojis[index] ? (
<UITextView
{...props}
style={[props?.style, {color: 'black', fontFamily: 'System'}]}>
<UITextView {...props} style={[props?.style, {fontFamily: 'System'}]}>
{emojis[index]}
</UITextView>
) : null,
+3
View File
@@ -1,4 +1,5 @@
import * as NavigationBar from 'expo-navigation-bar'
import * as SystemUI from 'expo-system-ui'
import {isAndroid} from '#/platform/detection'
import {Theme} from '../types'
@@ -9,10 +10,12 @@ export function setNavigationBar(themeType: 'theme' | 'lightbox', t: Theme) {
NavigationBar.setBackgroundColorAsync(t.atoms.bg.backgroundColor)
NavigationBar.setBorderColorAsync(t.atoms.bg.backgroundColor)
NavigationBar.setButtonStyleAsync(t.name !== 'light' ? 'light' : 'dark')
SystemUI.setBackgroundColorAsync(t.atoms.bg.backgroundColor)
} else {
NavigationBar.setBackgroundColorAsync('black')
NavigationBar.setBorderColorAsync('black')
NavigationBar.setButtonStyleAsync('light')
SystemUI.setBackgroundColorAsync('black')
}
}
}
+2 -2
View File
@@ -9,7 +9,7 @@ import {useFonts} from 'expo-font'
*/
export function DO_NOT_USE() {
return useFonts({
InterVariable: require('../../../assets/fonts/inter/InterVariable.ttf'),
'InterVariable-Italic': require('../../../assets/fonts/inter/InterVariable-Italic.ttf'),
InterVariable: require('../../../assets/fonts/inter/InterVariable.woff2'),
'InterVariable-Italic': require('../../../assets/fonts/inter/InterVariable-Italic.woff2'),
})
}
-21
View File
@@ -1,21 +0,0 @@
import React from 'react'
import {atoms as a, useBreakpoints, ViewStyleProp} from '#/alf'
export function useGutterStyles({
top,
bottom,
}: {
top?: boolean
bottom?: boolean
} = {}) {
const {gtMobile} = useBreakpoints()
return React.useMemo<ViewStyleProp['style']>(() => {
return [
a.px_lg,
top && a.pt_md,
bottom && a.pb_md,
gtMobile && [a.px_xl, top && a.pt_lg, bottom && a.pb_lg],
]
}, [gtMobile, top, bottom])
}
+66
View File
@@ -0,0 +1,66 @@
import React from 'react'
import {Breakpoint, useBreakpoints} from '#/alf/breakpoints'
import * as tokens from '#/alf/tokens'
type Gutter = 'compact' | 'base' | 'wide' | 0
const gutters: Record<
Exclude<Gutter, 0>,
Record<Breakpoint | 'default', number>
> = {
compact: {
default: tokens.space.sm,
gtPhone: tokens.space.sm,
gtMobile: tokens.space.md,
gtTablet: tokens.space.md,
},
base: {
default: tokens.space.lg,
gtPhone: tokens.space.lg,
gtMobile: tokens.space.xl,
gtTablet: tokens.space.xl,
},
wide: {
default: tokens.space.xl,
gtPhone: tokens.space.xl,
gtMobile: tokens.space._3xl,
gtTablet: tokens.space._3xl,
},
}
type Gutters = {
paddingTop: number
paddingRight: number
paddingBottom: number
paddingLeft: number
}
export function useGutters([all]: [Gutter]): Gutters
export function useGutters([vertical, horizontal]: [Gutter, Gutter]): Gutters
export function useGutters([top, right, bottom, left]: [
Gutter,
Gutter,
Gutter,
Gutter,
]): Gutters
export function useGutters([top, right, bottom, left]: Gutter[]) {
const {activeBreakpoint} = useBreakpoints()
if (right === undefined) {
right = bottom = left = top
} else if (bottom === undefined) {
bottom = top
left = right
}
return React.useMemo(() => {
return {
paddingTop: top === 0 ? 0 : gutters[top][activeBreakpoint || 'default'],
paddingRight:
right === 0 ? 0 : gutters[right][activeBreakpoint || 'default'],
paddingBottom:
bottom === 0 ? 0 : gutters[bottom][activeBreakpoint || 'default'],
paddingLeft:
left === 0 ? 0 : gutters[left][activeBreakpoint || 'default'],
}
}, [activeBreakpoint, top, right, bottom, left])
}
+5 -1
View File
@@ -131,7 +131,11 @@ function AccountItem({
(hovered || pressed || isPendingAccount) && t.atoms.bg_contrast_25,
]}>
<View style={a.p_md}>
<UserAvatar avatar={profile?.avatar} size={24} />
<UserAvatar
avatar={profile?.avatar}
size={24}
type={profile?.associated?.labeler ? 'labeler' : 'user'}
/>
</View>
<Text style={[a.align_baseline, a.flex_1, a.flex_row, a.py_sm]}>
<Text emoji style={[a.font_bold]}>
+1
View File
@@ -65,6 +65,7 @@ export function AvatarStack({
<UserAvatar
size={size - 2}
avatar={item.profile.avatar}
type={item.profile.associated?.labeler ? 'labeler' : 'user'}
moderation={item.moderation.ui('avatar')}
/>
)}
+4 -5
View File
@@ -7,7 +7,7 @@ import {
AtUri,
RichText as RichTextApi,
} from '@atproto/api'
import {msg, plural, Trans} from '@lingui/macro'
import {msg, Plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useQueryClient} from '@tanstack/react-query'
@@ -210,10 +210,9 @@ export function Likes({count}: {count: number}) {
const t = useTheme()
return (
<Text style={[a.text_sm, t.atoms.text_contrast_medium]}>
{plural(count || 0, {
one: 'Liked by # user',
other: 'Liked by # users',
})}
<Trans>
Liked by <Plural value={count || 0} one="# user" other="# users" />
</Trans>
</Text>
)
}
+4 -20
View File
@@ -6,7 +6,6 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {NavigationProp} from '#/lib/routes/types'
import {logEvent} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
@@ -16,7 +15,6 @@ import {FeedDescriptor} from '#/state/queries/post-feed'
import {useProfilesQuery} from '#/state/queries/profile'
import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows'
import {useSession} from '#/state/session'
import {useProgressGuide} from '#/state/shell/progress-guide'
import * as userActionHistory from '#/state/userActionHistory'
import {SeenPost} from '#/state/userActionHistory'
import {atoms as a, useBreakpoints, useTheme, ViewStyleProp, web} from '#/alf'
@@ -282,8 +280,8 @@ export function ProfileGrid({
profile={profile}
moderationOpts={moderationOpts}
logContext="FeedInterstitial"
color="secondary_inverted"
shape="round"
colorInverted
/>
</ProfileCard.Header>
<ProfileCard.Description profile={profile} numberOfLines={2} />
@@ -506,23 +504,9 @@ export function SuggestedFeeds() {
export function ProgressGuide() {
const t = useTheme()
const {isDesktop} = useWebMediaQueries()
const guide = useProgressGuide('like-10-and-follow-7')
if (isDesktop) {
return null
}
return guide ? (
<View
style={[
a.border_t,
t.atoms.border_contrast_low,
a.px_lg,
a.py_lg,
a.pb_lg,
]}>
return (
<View style={[t.atoms.border_contrast_low, a.px_lg, a.py_lg, a.pb_lg]}>
<ProgressGuideList />
</View>
) : null
)
}
+5 -3
View File
@@ -1,11 +1,13 @@
import {LinearGradient} from 'expo-linear-gradient'
import {atoms as a, tokens} from '#/alf'
import {atoms as a, tokens, ViewStyleProp} from '#/alf'
export function GradientFill({
gradient,
}: {
style,
}: ViewStyleProp & {
gradient:
| typeof tokens.gradients.primary
| typeof tokens.gradients.sky
| typeof tokens.gradients.midnight
| typeof tokens.gradients.sunrise
@@ -26,7 +28,7 @@ export function GradientFill({
}
start={{x: 0, y: 0}}
end={{x: 1, y: 1}}
style={[a.absolute, a.inset_0]}
style={[a.absolute, a.inset_0, style]}
/>
)
}
+1
View File
@@ -163,6 +163,7 @@ function KnownFollowersInner({
size={SIZE}
avatar={prof.avatar}
moderation={moderation.ui('avatar')}
type={prof.associated?.labeler ? 'labeler' : 'user'}
/>
</View>
))}
+5 -3
View File
@@ -83,7 +83,7 @@ export function RegionalNotice() {
)
}
export function LikeCount({count}: {count: number}) {
export function LikeCount({likeCount}: {likeCount: number}) {
const t = useTheme()
return (
<Text
@@ -93,7 +93,9 @@ export function LikeCount({count}: {count: number}) {
t.atoms.text_contrast_medium,
{fontWeight: '600'},
]}>
<Plural value={count} one="Liked by # user" other="Liked by # users" />
<Trans>
Liked by <Plural value={likeCount} one="# user" other="# users" />
</Trans>
</Text>
)
}
@@ -138,7 +140,7 @@ export function Default({
value={labeler.creator.description}
handle={labeler.creator.handle}
/>
{labeler.likeCount ? <LikeCount count={labeler.likeCount} /> : null}
{labeler.likeCount ? <LikeCount likeCount={labeler.likeCount} /> : null}
</Content>
</Outer>
)
+15 -17
View File
@@ -13,8 +13,9 @@ import {
platform,
TextStyleProp,
useBreakpoints,
useGutterStyles,
useGutters,
useTheme,
web,
} from '#/alf'
import {Button, ButtonIcon, ButtonProps} from '#/components/Button'
import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft} from '#/components/icons/Arrow'
@@ -29,27 +30,33 @@ import {Text} from '#/components/Typography'
export function Outer({
children,
noBottomBorder,
headerRef,
sticky = true,
}: {
children: React.ReactNode
noBottomBorder?: boolean
headerRef?: React.MutableRefObject<View | null>
sticky?: boolean
}) {
const t = useTheme()
const gutter = useGutterStyles()
const gutters = useGutters([0, 'base'])
const {gtMobile} = useBreakpoints()
const {isWithinOffsetView} = useContext(ScrollbarOffsetContext)
return (
<View
ref={headerRef}
style={[
a.w_full,
!noBottomBorder && a.border_b,
a.flex_row,
a.align_center,
a.gap_sm,
gutter,
sticky && web([a.sticky, {top: 0}, a.z_10, t.atoms.bg]),
gutters,
platform({
native: [a.pb_sm, a.pt_xs],
web: [a.py_sm],
native: [a.pb_xs, {minHeight: 48}],
web: [a.py_xs, {minHeight: 52}],
}),
t.atoms.border_contrast_low,
gtMobile && [a.mx_auto, {maxWidth: 600}],
@@ -85,17 +92,7 @@ export function Content({
}
export function Slot({children}: {children?: React.ReactNode}) {
return (
<View
style={[
a.z_50,
{
width: HEADER_SLOT_SIZE,
},
]}>
{children}
</View>
)
return <View style={[a.z_50, {width: HEADER_SLOT_SIZE}]}>{children}</View>
}
export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) {
@@ -175,7 +172,8 @@ export function TitleText({
gtMobile && a.text_xl,
style,
]}
numberOfLines={2}>
numberOfLines={2}
emoji>
{children}
</Text>
)
+3 -1
View File
@@ -21,6 +21,7 @@ export * as Header from '#/components/Layout/Header'
export type ScreenProps = React.ComponentProps<typeof View> & {
style?: StyleProp<ViewStyle>
noInsetTop?: boolean
}
/**
@@ -28,6 +29,7 @@ export type ScreenProps = React.ComponentProps<typeof View> & {
*/
export const Screen = React.memo(function Screen({
style,
noInsetTop,
...props
}: ScreenProps) {
const {top} = useSafeAreaInsets()
@@ -35,7 +37,7 @@ export const Screen = React.memo(function Screen({
<>
{isWeb && <WebCenterBorders />}
<View
style={[a.util_screen_outer, {paddingTop: top}, style]}
style={[a.util_screen_outer, {paddingTop: noInsetTop ? 0 : top}, style]}
{...props}
/>
</>
+4 -5
View File
@@ -237,7 +237,9 @@ export function Link({
}
export type InlineLinkProps = React.PropsWithChildren<
BaseLinkProps & TextStyleProp & Pick<TextProps, 'selectable'>
BaseLinkProps &
TextStyleProp &
Pick<TextProps, 'selectable' | 'numberOfLines'>
> &
Pick<ButtonProps, 'label'> & {
disableUnderline?: boolean
@@ -273,7 +275,6 @@ export function InlineLinkText({
onIn: onHoverIn,
onOut: onHoverOut,
} = useInteractionState()
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
const flattenedStyle = flatten(style) || {}
return (
@@ -284,7 +285,7 @@ export function InlineLinkText({
{...rest}
style={[
{color: t.palette.primary_500},
(hovered || focused) &&
hovered &&
!disableUnderline && {
...web({
outline: 0,
@@ -298,8 +299,6 @@ export function InlineLinkText({
role="link"
onPress={download ? undefined : onPress}
onLongPress={onLongPress}
onFocus={onFocus}
onBlur={onBlur}
onMouseEnter={onHoverIn}
onMouseLeave={onHoverOut}
accessibilityRole="link"

Some files were not shown because too many files have changed in this diff Show More