Compare commits

...

385 Commits

Author SHA1 Message Date
Samuel Newman 13ec071aab Update src/components/Link.tsx
Co-authored-by: Eric Bailey <git@esb.lol>
2025-06-09 09:50:44 -07:00
Samuel Newman b507b22d9e Update yarn.lock 2025-06-04 21:25:59 +03:00
Samuel Newman 90455c0c6f fix implicit poptotop in drawer 2025-06-04 21:22:37 +03:00
Samuel Newman 846c730d49 oops, upgrade react navigation one final time 2025-06-04 20:38:41 +03:00
Samuel Newman 490bfceded update yarn.lock 2025-06-04 20:38:41 +03:00
Samuel Newman a9322c8457 upgrade rns again 2025-06-04 20:38:41 +03:00
Samuel Newman a5b7b6f12f remove shadow prop (defaults to true anyway) 2025-06-04 20:38:41 +03:00
Samuel Newman 2c32e775df simplify screen options, use default animation duration 2025-06-04 20:38:41 +03:00
Samuel Newman cad7db56cf explicit initial routes, enable legacy implicit nested navigation 2025-06-04 20:38:41 +03:00
Samuel Newman 2e260be80c fix pop-to-top behaviour 2025-06-04 20:11:30 +03:00
Samuel Newman 571d16e8cf just use typeof 2025-06-04 20:11:30 +03:00
Samuel Newman 134c7b7427 fix yarn.lock 2025-06-04 20:11:30 +03:00
Samuel Newman e11f52ad96 fix external links in TextLink 2025-06-04 20:11:30 +03:00
Samuel Newman eb59bd3d9c upgrade useNavigationDeduped (had to ts-ignore 😭) 2025-06-04 20:11:30 +03:00
Samuel Newman 017a26164b attempt to upgrade Links 2025-06-04 20:11:30 +03:00
Samuel Newman 0e0110aa13 improve navigation types 2025-06-04 20:11:30 +03:00
Samuel Newman 4625c0bda1 upgrade createNativeStackNavigatorWithAuth with new internals 2025-06-04 20:11:30 +03:00
Samuel Newman 14047b78f6 upgrade deps off of RC versions 2025-06-04 20:11:30 +03:00
Samuel Newman 0eabdfe2b4 attempt to fix link component 2025-06-04 20:11:30 +03:00
Dan Abramov c999ff38f9 Fix prop name 2025-06-04 20:11:30 +03:00
Dan Abramov 1045b09592 Update react-navigation 2025-06-04 20:11:30 +03:00
Paul Frazee 1e620b19cc Release 1.103.0 prep (#8434)
* Add pt-PT mapping to crowdin config

* Pull latest translations from crowdin

* run intl extract
2025-05-30 16:58:23 -07:00
surfdude29 e2b842ad4e Add language: European Portuguese (pt-PT) (#8375)
* Update app.config.js

* Update lingui.config.js

* Update dates.ts

* Update helpers.ts

* Update i18n.ts

* Update i18n.web.ts

* Update languages.ts

* Create messages.po

* prettier
2025-05-30 16:38:09 -07:00
Paul Frazee bf7845339c Small test fix 2025-05-30 16:37:10 -07:00
hailey 45a3e6c0d5 tweak ordering of explore components (#8432)
* tweak ordering of explore components

* use better feed suggestions, metrics

* tweak default limit

* tweak

* remove unnecessary if
2025-05-30 15:29:00 -07:00
hailey ce7b9dc430 add metrics (#8426) 2025-05-30 13:54:58 -07:00
hailey 2a453cd9ca invert flag for sending to statsig (#8431) 2025-05-30 12:13:44 -07:00
Samuel Newman 4890648116 Fix link to like-via-repost (#8428) 2025-05-30 12:27:24 +03:00
pfrazee caf18daa6a Nightly source-language update 2025-05-30 02:39:47 +00:00
Samuel Newman 4c5a4e471f Make via-repost notifs groupable (#8429) 2025-05-30 01:43:56 +03:00
Samuel Newman 7b3916c8cc Share bandwidth estimate between video instances (#8377) 2025-05-30 00:24:01 +03:00
pfrazee bc42d26bc5 Nightly source-language update 2025-05-29 02:40:02 +00:00
Samuel Newman cf63c2ca07 Send FeedFeedback interactions in thread view (#8414) 2025-05-28 22:09:28 +03:00
pfrazee 665a0430a3 Nightly source-language update 2025-05-28 02:39:55 +00:00
Samuel Newman 4303bca860 Floating "Load more" makeover (#8420) 2025-05-28 00:33:19 +03:00
Eric Bailey 342f820ec0 Quiet some logs, fix a bug (#8404)
* Composer, 142k

* Log geolocation error at most once per session

* Clean thumb cache, 1.4m

* Quiet generic network errors

* Handle undefined notification payloads
2025-05-27 13:25:41 -05:00
Eric Bailey df2f62e94d Move SENTRY_DSN to secrets (#8096)
* Move SENTRY_DSN to secrets

* Disable without DSN

* Add to secondary build in android ci
2025-05-27 13:25:30 -05:00
pfrazee 0bb0a7616e Nightly source-language update 2025-05-24 02:37:51 +00:00
hailey 00596a2d2f bump 1.103.0 (#8407) 2025-05-24 02:19:35 +03:00
Samuel Newman c3f88e0a48 Share menu (#7840)
* move post ctrls to #/components

* restructure post controls, basic share menu

* add border radius to searchable people list for android

* Revert "add border radius to searchable people list for android"

This reverts commit 417449086e25b82f5683b12f6405d972f48ce50e.

* add copy link to native share menu

* reorg files again

* open native share menu on long press

* Translation comments

Thanks @surfdude29

* abs path

* update type imports, remove forwardRef

* rm react import

* equal spacing of buttons, extract disco debug

* add better icon

* add right offset to share button for visual alignment

* Add recent chats to share menu (#7853)

* add recent chats to share menu

* Update RecentChats.tsx

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

* Update RecentChats.tsx

* add fading edge on andriod

* tweak scrollview

* Add metrics and A/B alt icon to share menu (#8401)

* add metrics

* add a/b tested alt icon

---------

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

* More descriptive share text/icon on web (#7854)

* more descriptive share text on web

* revert dev mode changes

* add missing import

* use modified share icon everywhere

* Add back conflicting changes

---------

Co-authored-by: Eric Bailey <git@esb.lol>

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
2025-05-23 18:02:38 -05:00
pfrazee 5aadb9e41b Nightly source-language update 2025-05-22 02:39:43 +00:00
hailey 7ed2a4f388 silence geo log (#8400) 2025-05-21 15:35:28 -07:00
RetroSunstar 5253e688a0 Rectify a constant +1 to liked feeds (#8398)
Co-authored-by: Hailey <me@haileyok.com>
2025-05-21 12:36:18 -07:00
Samuel Newman a0ea634349 Speculative fix to Android camera roll issue (#8397) 2025-05-21 21:51:57 +03:00
hailey c16cd36b64 add reqId to feed feedback (#8396)
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-05-21 11:15:55 -07:00
pfrazee e6c867a961 Nightly source-language update 2025-05-21 02:40:00 +00:00
Samuel Newman fe73c13530 Improve select language prompt (#8391) 2025-05-20 18:49:47 +03:00
Samuel Newman a18b25d16c [Live] Add warning if link is missing image (#8393) 2025-05-20 18:49:20 +03:00
Samuel Newman c710187094 fix hover card width (#8392) 2025-05-20 18:48:56 +03:00
Samuel Newman 29de23bbae Fix emoji reaction expanded picker on web getting squished (#8245)
* ensure expanded emoji picker doesn't get squished

* reset expanded state on close
2025-05-19 10:03:01 -07:00
Samuel Newman ca6c96f509 fix view collapse on android (#8390) 2025-05-19 09:35:06 -07:00
hailey 4ef7a6b64c add reason to log (#8381) 2025-05-19 09:33:55 -07:00
hailey f3bc962494 temporary react-native-view-shot patch (#8383)
* temp patch

* fix
2025-05-17 12:19:37 -07:00
pfrazee 2fab992c04 Nightly source-language update 2025-05-17 02:38:01 +00:00
Samuel Newman 1cdbfc7092 Live via service config (#8378)
* add config (with temp config)

* only allow whitelisted domains in form

* move config to generic config

* use array-based config

* update deps

* rm expect-error
2025-05-16 15:38:34 -07:00
Eric Bailey 75ffb3d243 Don't show NUXs to brand new users (#8362)
* Ensure verification nux is only shown to older users

* Update comment
2025-05-10 13:08:42 -07:00
Paul Frazee d01b9ed441 Release 1.102.0 (#8360)
* Update tests

* Pull latest crowdin

* Run intl:extract
2025-05-09 20:09:02 -07:00
pfrazee 1b9448c6eb Nightly source-language update 2025-05-10 02:36:59 +00:00
surfdude29 a2365e08b4 Add language: Frisian (#8214)
* Update app.config.js

* Update lingui.config.js

* Update dates.ts

* Update helpers.ts

* Update i18n.ts

* Update i18n.web.ts

* Update languages.ts

* Create messages.po
2025-05-09 19:14:42 -07:00
Samuel Newman a0bd804262 Live (#8354) 2025-05-10 00:06:06 +03:00
Eric Bailey 2e80fa3dac Fix email dialog width on large phones (#8350)
* Fix email dialog width on large phones

* Do it Right™
2025-05-09 15:58:12 -05:00
Jerry Chen ce2fffc88c Fix notifications badge on web (#8347)
* Add notificationCountWeb style

* Apply styles.notificationCountWeb to BottomBarWeb NavItem
2025-05-09 11:17:39 -07:00
Samuel Newman 6c28d7d535 move and rename button (#8358) 2025-05-09 11:12:40 -07:00
pfrazee a7e0070b15 Nightly source-language update 2025-05-09 02:39:21 +00:00
Samuel Newman 207527f1d5 [Android] Save photos to "Bluesky" folder (#8018) 2025-05-08 23:50:12 +03:00
Samuel Newman 36697755c7 fix reply display name being clipped (#8315) 2025-05-08 23:17:44 +03:00
Samuel Newman 1c2a7b0b5a Fix some more warnings for web (#8316)
* export correct stub for web

* use default import for package.json
2025-05-08 11:58:32 -07:00
hailey a6455b3de3 fix crash (#8348) 2025-05-08 08:49:43 -07:00
pfrazee a260ecd307 Nightly source-language update 2025-05-08 02:39:40 +00:00
Samuel Newman 0b06a93833 add 10px more padding (#8345) 2025-05-07 21:49:49 +03:00
Samuel Newman f1372abec5 delete unused auth components (#8334) 2025-05-07 11:44:38 -07:00
Eric Bailey 0f96669f8c [APP-1158] Refactor email-related dialogs (#8296)
* WIP

* Update email

* Fire off confirmation email after change

* Verify step, integrate stateful control

* Remove tentative EnterCode step

* Handle token step

* Handle instructions and integrate into 2FA setting

* Fix load state when reusing same email

* Add new state

* Add 2FA screens

* Clean up state in Update step

* Clean up verify state, handle normal callback

* Normalize convetions

* Add verification reminder screen

* Improve session refresh

* Handle verification requirements for composer and convo

* Fix lint

* Do better

* Couple missing translations

* Format

* Use listeners for easier to grok logic

* Clean errors

* Move to global context

* [APP-1158] Gate features by email verification state (#8305)

* Use new hook in all locations

* Format

* Seems to work, not great duplication

* Wrap all open composer calls

* Remove unneeded spans

* Missed one

* Fix handler on Conversation

* Gate new chat in header

* Add comment

* Remove whoopsie

* Format

* add hackfix for dialog not showing

* add prompt to accept chat btn

* navigation not necessary

* send back one screen, rather than home

* Update comment

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

* Clear dialog state

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

* Update icon

* Check color

* Add 2FA warning

* Update instructions

* Fix X button

* Use an effect silly goose

* Update copy

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

* Update copy

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

* Update copy

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

* Update copy

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

* Update src/components/dialaUpdate copyogs/EmailDialog/screens/Update.tsx

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

* Update copy

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

* Update copy

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

* Update copy

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

* Update copy

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

* Update copy

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

* Update copy

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

* Update copy

* Update copy

* Update copy

* Update copy

* Update copy

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

* Update copy

* Add link back to update email from verify email dialog

* Handle token field validation

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2025-05-07 10:23:33 -05:00
Samuel Newman 0edd3bd3b4 fix select triggers on ios safari (#8343) 2025-05-07 07:06:49 -07:00
pfrazee e01b24702e Nightly source-language update 2025-05-07 02:39:23 +00:00
Samuel Newman d1ec73a289 hide footer when lists list is empty (#8337) 2025-05-06 23:07:48 +03:00
Samuel Newman 433fa33b27 bump hls.js (#8336) 2025-05-06 23:07:21 +03:00
Samuel Newman 4c8fd006f6 New Edit Profile dialog on web, use new Edit Image dialog everywhere (#8220) 2025-05-06 22:50:28 +03:00
bnewbold 3f7dc9a8e5 use legally registered name for company (#8338) 2025-05-06 12:09:50 -07:00
hailey 0d02a076d9 bump cropper version (#8339)
* mostly implement

* type errors

* unused import

* rm comment

* stop accidentally deleting the image while compressing

* upgrade

* type fixes

* upgrade, remove timeout

* bump

* rm mock

* bump

* bump

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-05-06 11:13:15 -07:00
hailey 521ec8e044 swap out cropper library (#8327)
* mostly implement

* type errors

* unused import

* rm comment

* stop accidentally deleting the image while compressing

* upgrade

* type fixes

* upgrade, remove timeout

* bump

* rm mock

* bump

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-05-06 10:54:08 -07:00
Samuel Newman 973538d246 New Select component (#8323)
* radix select component on web

* native implementation (wip)

* fix sheet height/padding

* tone down web styles

* react 19 cleanup

* replace primary language select

* change style on native

* get auto placeholder working

* more style tweaks

* replace app language dropdown

* replace rnpickerselect with native select

* rm react-native-picker-select dependency

* rm placeholder, since a value is always selected

* docblock for renderItem

* add more docblocks

* add style prop to item

* pass selectedValue through renderItem

* fix context

* Style overflow buttons

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-05-06 10:27:05 -07:00
Samuel Newman 25f8506c41 Remove post from feed after pressing show less (#8333)
* remove post from feed after pressing show less

* fix text overflow on android

* move state up so it won't get recycled away

* make type optional
2025-05-06 07:34:50 -07:00
Samuel Newman 04dc6dc9ca add internal topic misclassification report button (#8332) 2025-05-06 17:03:48 +03:00
hailey e7fe9ab553 revert changes to scroll forwarder (#8328) 2025-05-05 00:20:34 -07:00
pfrazee abbdeb4f28 Nightly source-language update 2025-05-03 02:36:58 +00:00
hailey 544f7befe0 bump it bop it upgrade it (rn 79/expo 53) (#8281)
* basic bumps

* more tweaking

* fix rn patch

* fix crop picker patch

* fix media library patch

* rm unnecessary patch

* fix notifications patch

* update bottomsheet

* Update withAppDelegateReferrer.js

* Delete withNoBundleCompression.js

* rm withNoBundleCompression plugin

* rm findLast shim

* metro package exports is enabled by default

* update react/react-dom/react-compiler

* fix reanimated issue

* vendor expo-ized emoji popup

* fix types

* hackfix view full thread

* Update EmojiPickerModule.podspec

* more upgrades

* fix multiformats package version

* add baseurl

* bump mmkv

* bumps

* update react-keyed-flatten-children

* bump locale packages

* fix emoji picker dark mode

* rn upgrades

* Revert "bump locale packages"

This reverts commit fc82f0f173.

* upgrade testing-library

* rm test renderer

* update patch name minors

* rm findNodeHandle from tabbar

* only do scrollview tag thing on ios

* disable package exports

* update expo notifications handler

* memoize emoji picker styles

* fix tests, mock multiformats

* bump some dev deps with RC versions

* completely rearchitect toasts

* rm logs

* layout animation config for composer footer

* disable autolinking for patched libs

* undo lingui changes

* version bump from release candidate to 0.1

* update atproto deps

* rm @did-plc/server

* fix key issue (maybe)

* move URL polyfill to the polyfill file

* fix yarn lock

* upgrade to 53.0.3

* reanimated layout anim bug patch

* workletize a function that wasn't getting autoworkletized anymore (#8309)

* bump to expo 53.0.4

* bump RN to 0.79.2

* fix yarn lock ci

* Revert "completely rearchitect toasts"

This reverts commit 2e2fcaeeed.

* final upgrades

* chore: cleanup yarn lock

* prettier

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-05-02 13:23:39 -07:00
Paul Frazee 46ea3fdbee Merge branch 'demo' into main 2025-05-02 10:36:43 -07:00
Samuel Newman 077fd843f0 don't await deleting temp files (#8287) 2025-04-26 11:26:42 -07:00
Kae 1eb678cabd Optimize compressImage method to also use binary search (#7490)
* use binary search for compressImage

* use binary search for doResize (mobile version)

* use binary search for doResize (web version)

* use safeDeleteAsync in compressImage

---------

Co-authored-by: nguyen <nguyensvo123@gmail.com>
2025-04-26 11:10:32 -07:00
Samuel Newman ea718190ca Update mention of MobX in README (#8286) 2025-04-26 19:47:34 +03:00
Paul Frazee 2aa30f5279 Update third post in demo 2025-04-25 11:51:33 -07:00
Paul Frazee 7b245935ea Remove demo-mode spacing tweak 2025-04-25 10:49:10 -07:00
Paul Frazee 55795dc262 Updated demo copy 2025-04-25 10:42:35 -07:00
pfrazee 1470223480 Nightly source-language update 2025-04-25 02:38:31 +00:00
Samuel Newman 8ec8a64472 Modernize in-app browser consent dialog (#8191)
* add stateful dialog control hook

* add new alf'd consent

* make secondary_inverted buttons clearer

* contingency for opening a link from another dialog

* rm old modal

* Differentiate buttons more

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-04-24 16:41:11 -05:00
Samuel Newman 69f656f283 cleanup mod screens (#8199) 2025-04-24 16:36:39 -05:00
Samuel Newman 278a54850b Keep all radix dependencies aligned by using single package (#8219)
* keep all radix deps aligned by using single package

* import directly from `radix-ui` or `radix-ui/internal`

* prevent radix leaking into native build
2025-04-24 16:15:46 -05:00
Samuel Newman b6a6b1bab4 fix pwi at 1300px (#8238) 2025-04-24 16:07:56 -05:00
Samuel Newman 686f15a62b fix skeleton height (#8221) 2025-04-24 16:05:48 -05:00
Eric Bailey d992b27716 Ota docs update (#8279)
* Begin edits

* Add alert

* Add new assets

* Refactor OTA docs

* Format
2025-04-24 16:04:48 -05:00
Eric Bailey 6f44abee35 Verification UI tweaks (#8276)
* Prevent issuing verifications for users without display names

* Wait for success before closing, show errors

* Update icons

* WIP adjust size

* Adjust check size in feeds

* Add back unused icon

* Format
2025-04-24 11:46:23 -05:00
Paul Frazee ba002d8252 Tune spacing for demo mode 2025-04-24 09:31:04 -07:00
pfrazee e1e936068a Nightly source-language update 2025-04-24 02:38:23 +00:00
Eric Bailey 9a7f6ad638 Moar demo 2025-04-23 18:30:25 -05:00
Eric Bailey 6a8dd353ee Update bottom bar avi 2025-04-23 16:36:27 -05:00
Eric Bailey c1e090e9e3 Better data 2025-04-23 16:36:27 -05:00
Eric Bailey 9f66b7fe67 Delete unused fake data, update bottom bar avi 2025-04-23 16:36:27 -05:00
Eric Bailey eb2008cd8e Update data 2025-04-23 16:36:27 -05:00
Samuel Newman f3edd6dfd2 add more posts 2025-04-23 16:36:27 -05:00
Samuel Newman 91f9bc7ccb demo mode 2025-04-23 16:36:27 -05:00
Samuel Newman c34c67e4df add demo storage 2025-04-23 16:36:27 -05:00
Samuel Newman 70dbc94766 Modernise change email flow (#8106)
* use new verify email dialog in 2fa flow

* alf change email flow

* Fallback change email dialog

* Update ChangeEmailDialog.tsx

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

* Update ChangeEmailDialog.tsx

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

* Update ChangeEmailDialog.tsx

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

* Update ChangeEmailDialog.tsx

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

* Update ChangeEmailDialog.tsx

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

* Update ChangeEmailDialog.tsx

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

* Update ChangeEmailDialog.tsx

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

* Update ChangeEmailDialog.tsx

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

* Update Email2FAToggle.tsx

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

* don't use existing email as default value

* increase max width of email dialogs

* Use ALF verify email dialog for reminder (#5924)

* use new verify email dialog for reminder

* style tweaks, improve web

* add a lil toast

* Apply suggestions from code review

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

* Ditch close and push up image

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>

* delete old change/verify email modals (#8122)

(cherry picked from commit fceb655b3b)

* Translate email placeholder

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

* Align copy

* Clean up error handling

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
2025-04-23 11:22:08 -05:00
Samuel Newman 118d385b10 make handles lowercase (#8233) 2025-04-23 17:16:46 +03:00
Samuel Newman 54e5ea0aff rm vision-camera (#8273) 2025-04-23 17:14:41 +03:00
natalie 555dd6a4db Sanitize handle in header (#8272)
* Sanitize handle in header

* use prefix param correctly
2025-04-23 05:54:41 -07:00
pfrazee 1fe94ba290 Nightly source-language update 2025-04-23 02:37:50 +00:00
hailey e27134c7f1 bump 1.102.0 (#8271) 2025-04-22 11:54:17 -07:00
Samuel Newman b1550f9c02 fix first sheet height change not registering (#8267) 2025-04-22 11:49:20 -07:00
Samuel Newman dba0bd8379 move dev mode hook (#8270) 2025-04-22 11:13:13 -07:00
Mathieu Acthernoene a770f5635b Edge to edge support (#7497) 2025-04-22 19:16:50 +03:00
pfrazee 6e80b340c8 Nightly source-language update 2025-04-22 02:37:34 +00:00
Eric Bailey 0a7734f9ed Refactor search history (#8260) 2025-04-21 19:16:59 -05:00
Eric Bailey 8a602bf9f6 Tweak alignment (#8258) 2025-04-21 18:08:06 -05:00
Eric Bailey 3f47c8cf06 Improve display name in Settings (#8256) 2025-04-21 17:05:14 -05:00
Eric Bailey aa3ee8db4e Align handling (#8255) 2025-04-21 16:59:46 -05:00
Eric Bailey 8fdefb7e94 Add check to composer user autocomplete (#8253)
* Add check to composer autocomplete web

* Add check to composer autocomplete mobile
2025-04-21 16:32:29 -05:00
Eric Bailey 4aaf81fedd Show date in verifications dialog (#8257) 2025-04-21 15:41:15 -05:00
Eric Bailey b3c3ee5541 Tweak dialog copy (#8254) 2025-04-21 15:34:20 -05:00
Samuel Newman 13884b0a1c fix composer reply line height (#8241) 2025-04-21 15:29:46 -05:00
Eric Bailey 873ba16d2d Use normal spaces around check (#8252) 2025-04-21 14:58:15 -05:00
Eric Bailey d5dc065a83 Make whole verifier clickable, no nested interactives (#8249) 2025-04-21 12:08:05 -05:00
Eric Bailey 0278c7a0b4 Make notifications clickable (#8251) 2025-04-21 12:07:55 -05:00
Samuel Newman a091def512 rm other close (#8250) 2025-04-21 09:53:01 -07:00
Eric Bailey b800334ebc Center handle in verifier dialog (#8247)
* Center handle in verifier dialog

* do the same for the other dialog

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-04-21 11:28:35 -05:00
Samuel Newman 9363ff6f48 rm double close (#8246) 2025-04-21 11:00:38 -05:00
Paul Frazee 35daa5a343 Release 1.101.0 (#8229)
* Update tests

* Localization import from crowdin
2025-04-18 21:19:01 -07:00
surfdude29 03c50f07a1 change UK country code to GB in additional-moderation-authorities.ts (#8211) 2025-04-18 20:04:57 -07:00
pfrazee de7b63e67d Nightly source-language update 2025-04-19 02:19:33 +00:00
Eric Bailey 0ac15920a4 Verification (#8226)
* WIP

* Alignment with icon

* Add create/remove prompts

* Fill out check dialog a bit

* Reorg

* Handle was verified state

* Add warning to edit profile

* Add warning to handle dialog

* Decent alignment in posts on all platforms

* Refactor alignment for posts, chatlist, hover card

* Disable on profile

* Convo header

* Compute simple verification state

* Add other icon, rename, integrate

* Swap in simple state for profile edits

* Clean up utility hooks

* Add verifications UI to dialog

* Add edu nux

* Revert change

* Fix wrapping of check on profile

* Rename

* Fix gap under PostMeta

* Update check dialogs

* Handle takendown verifiers in check dialog

* alf composer reply to

* Refactor verification state

* Add create/remove mutations, non-functional for now

* Fix up post-rebase

* Add check to first author noty

* Do cache updates after mutations

* DRY up hook, add to profile updates too

* Add to drawer

* Update account list

* Adapt to new types

* Hook up mutations

* Use profile shadow in feeds

* Add to settings

* Shadow currentAccountProfile

* Add invalid state to verifications

* Fix alignment and overflow in Settings and Drawer

* Re-integrate post rebase

* Remove debug code

* Update copy

* Add unverified notification support

* Remove link

* Make sure dialog closes

* Update URL

* Add settings screen

* Integrate new setting into verification states

* Add metrics, bump package, fix bad import

* NUX fixes

* Update copy

* Fixes

* Update types

* fix search autocomplete

* fix lint

* add display name warning to new dialog

* update default prefs

* Add parsing support for notifications

* Bump pkg

* Tweak noty styles

* Adjust check alignment

* Tweak check alignment

* Fix badge for verifier

* Modify copy

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2025-04-18 19:15:32 -07:00
pfrazee f1e44ee12e Nightly source-language update 2025-04-18 02:36:32 +00:00
Samuel Newman cf6c8dc331 Clear image cache button (#8190) 2025-04-17 23:41:15 +03:00
Samuel Newman 719d7b7a57 Use SearchablePeopleList for add user to list dialog, replace old modal (#8212)
* move to dialogs dir

* make searchable people list more generic

* new list-add-remove-users dialog

* update header text

* fix header on android

* delete old modal

* reduce spacing on items
2025-04-17 11:11:46 -05:00
pfrazee 4f316538fb Nightly source-language update 2025-04-17 02:37:35 +00:00
Eric Bailey faab49bd9e ALF search cards (#8210) 2025-04-16 18:42:41 -05:00
Samuel Newman fb8ab9f26d ALF Notifications screen (#8208)
* alf notifs page

* Stop propagation

* Ok safari wants preventDefault too

* Fix lint

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-04-16 14:14:33 -05:00
pfrazee fa0b1bc1bb Nightly source-language update 2025-04-16 02:37:56 +00:00
Eric Bailey 16462b08a7 Standarize on shields (#8204) 2025-04-15 15:30:03 -05:00
Samuel Newman c5a22ffd97 [Embed] Fix 3-image grid on Safari (#8198)
* fix 3-image grid for safari

* match 4-grid aspect ratio to app
2025-04-15 07:33:36 -07:00
Eric Bailey f46336e341 Replace old ProfileCard with new (#8195)
* Replace usages of old ProfileCard

* Replace Pills with Labels component

* Replace impl of ProfileCardWithFollowButton

* Remove never-used LikesDialog

* Handle missing mod opts

* Add missing profile hover

* use modern button in listmembers

* remove follow button from muted accounts list

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-04-15 06:13:20 -07:00
pfrazee 32c2b69b84 Nightly source-language update 2025-04-15 02:38:00 +00:00
Eric Bailey 9ae0cf60af Don't re-use profile-specific components in Settings (#8193) 2025-04-14 17:18:06 -05:00
Samuel Newman 2ff5f2fb9b bump version (v1.101) (#8189) 2025-04-14 22:42:32 +03:00
Samuel Newman 62c4293adc Fix end of feed border thickness (#8187) 2025-04-14 10:15:47 -07:00
Samuel Newman ff7407c8e2 Use consistent hosting provider height (#8186) 2025-04-14 10:14:09 -07:00
Samuel Newman d899d09e60 [Embed] Fix up post embeds, and other tweaks (#8185)
* fix eslint

* Update .eslintrc.cjs

* fix 3 and 4 image aspect ratios

* round embeds more

* fix line height
2025-04-14 10:13:35 -07:00
Samuel Newman 2e73464fd1 change chat settings icon to a gear icon (#8192) 2025-04-14 10:13:09 -07:00
Samuel Newman f8bd850465 Fix labeler header scroll and loading/error states (#8088)
* add forwardRef to Layout.Content

* lift scrollview up out of inner component

* fix scrolling on android (#8188)
2025-04-14 11:00:39 -05:00
Eric Bailey 238b00d193 Configure moderation 2025-04-10 17:05:11 -05:00
Paul Frazee bf69672674 Update translations from crowdin (#8172) 2025-04-09 16:25:16 -07:00
Eric Bailey 5371114609 Add translate metrics (#8171)
* Add translate metrics

* Format
2025-04-09 15:00:40 -07:00
surfdude29 4c0213b3e9 update crowdin links to point to public page (#8100) 2025-04-09 12:28:06 -07:00
Eric Bailey 02a05d9948 Pass in Sentry vars to prod android build (#8170) 2025-04-09 11:29:37 -07:00
pfrazee 4c142a86b4 Nightly source-language update 2025-04-09 02:37:13 +00:00
Paul Frazee f3153b8acb Release 1.100 (#8168)
* Tests fix

* Move the hosting provider text in account creation into the inside of the button to improve translation handling (close #8166)

* Pull latest translations

* Revert the 'you are creating an account' change entirely; it doesnt work
2025-04-08 18:16:04 -07:00
Paul Frazee a59fb91a99 Increase suggested follows in the new user progress guide modal (#8162)
* Increase number of accounts suggested in the follow dialog progress guide

* Increase the bottom pad on the dialog flatlist component

* Format

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-04-08 18:16:13 -05:00
Eric Bailey c8568e3004 [Explore] Reduced experience (#8160)
* Only show suggested users for non-english users

* Fall back to searching for users for non-english speakers

* Disable other queries if full experience is disabled

* Bump package

* If no content langs, use full exp
2025-04-08 17:08:09 -05:00
Eric Bailey 09111ef272 Tweak performance settings on Android (#8158) 2025-04-08 11:20:03 -07:00
pfrazee b9ed94c7f4 Nightly source-language update 2025-04-08 02:36:28 +00:00
Eric Bailey 872fcd1d20 Update patches (#8151)
* Update patches after #8133

* Bump deps

* Revert @react-native-picker/picker downgrade

* Migrate RN patch
2025-04-07 18:29:41 -07:00
Eric Bailey d496b5bdbf Add in new suggested accounts endpoint into FollowDialog (#8147)
* Add in new suggested accounts endpoint into FollowDialog

* Fix lint

---------

Co-authored-by: Hailey <me@haileyok.com>
2025-04-07 18:29:04 -07:00
Eric Bailey 4879a07701 Rm sticky headers (#8154) 2025-04-07 17:41:20 -07:00
Eric Bailey 28876a4b23 Slice 'For You' results (#8152) 2025-04-07 17:40:31 -07:00
surfdude29 1e8a96e297 Align copy in Your interests toasts (#8138)
* update copy in toasts

* prettier
2025-04-07 18:42:29 -05:00
Eric Bailey 815a1e4c44 Center the selected tab in the sugg follows tabbar (#8146)
Co-authored-by: Hailey <me@haileyok.com>
2025-04-07 16:34:05 -07:00
Eric Bailey 4013855c10 [Explore] Small fixes (#8145)
* Hover on sugg account

* Add subtle hover to all components except feed

* Use skeleton states for refetch on focus

* Empty results state for sugg users

* Filter out pinned posts from feed previews

* Add trending header if not top module

* Tighten up spacing

* Fetch 10 profiles

* Update interests copy

* Remove refetch on focus

* Add PTR

* use a map

* Update src/screens/Search/modules/ExploreInterestsCard.tsx

* fix web double border

---------

Co-authored-by: Hailey <me@haileyok.com>
2025-04-07 16:32:30 -07:00
Eric Bailey e46b78eb85 Remove unused index to fix lint (#8148) 2025-04-07 16:06:28 -07:00
pfrazee 94fd12ff49 Nightly source-language update 2025-04-05 02:35:03 +00:00
Paul Frazee a181b0b935 Rework the visual design of the interests card in explore (#8135) 2025-04-04 18:10:13 -07:00
Paul Frazee a301e31f76 Fix the 'seen' metric in explore (#8134) 2025-04-04 17:28:02 -07:00
Eric Bailey 502d660eb4 [Explore] Invalidate queries post-interests edit (#8128)
* Insert fresh interests and reset relevant queries

* reset suggested users

---------

Co-authored-by: Hailey <me@haileyok.com>
2025-04-04 17:16:39 -07:00
Paul Frazee 6840fbb237 Update deps to support ios 18.4 (#8133) 2025-04-04 17:04:57 -07:00
Eric Bailey 0b08128e4a [Explore] Design tweaks (#8131)
* Fix interests card spacing

* Space out AvatarStack

* SP icon size

* Visual alignment of tab bar and headers

* Tweak spacing around search input

* Drop text size in sp card overflow count

* Tweak
2025-04-04 16:55:30 -07:00
Eric Bailey aca89d4aea [Explore] New suggested follows endpoint (#8130)
* Bump SDK

* Integrate new endpoint, add profile shadow, For You tab

* Format
2025-04-04 16:44:02 -07:00
Eric Bailey a0ff9b52aa [Explore] Add interests card (#8125)
* Add interests card to top of Explore

* Add tip to add interests if they have none or deselect

* Format

* Copy
2025-04-04 14:08:16 -05:00
Samuel Newman 5c59ec14c2 Match placeholder color with other skeletons (#8129) 2025-04-04 11:00:38 -07:00
Eric Bailey 94bc677ef5 Rename search to explore in titles and links (#8116)
* Rename search to explore in titles and links

* Conditionally use Explore
2025-04-04 08:30:12 -07:00
Eric Bailey 148bfa803d Content interests (#8114)
* Content prefs screen

* Handle debounce, rename

* Fix format

* Let's just use interests

* Reuse hook
2025-04-04 10:26:48 -05:00
Samuel Newman 0004e27427 [Explore] Add index to view metric (#8124)
* add index to view metric

* supply index

* always return a number
2025-04-04 08:24:26 -07:00
Samuel Newman ceb51c7e8f [Explore] Add flatlist perf-related props (#8120)
* Add flatlist perf-related props

* Make keys more unique

* Small gap

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-04-04 08:15:56 -07:00
Samuel Newman 22a7199436 remove use of sticky topBorder, add border to feed footer (#8121) 2025-04-04 17:30:46 +03:00
Samuel Newman fa08428428 [Explore] Moderate trending topic avis (#8123)
* moderate trending topic avis

* filter blurs too
2025-04-04 07:24:43 -07:00
Samuel Newman 93af013210 log views of starter packs header (#8118) 2025-04-04 07:15:59 -07:00
Samuel Newman a0c644acfe [Explore] Add shadow cache (#8119)
* enable shadowcache for feed previews

* extract keyextractor

* dedupe feeds
2025-04-04 07:15:40 -07:00
pfrazee a15658cb66 Nightly source-language update 2025-04-04 02:36:04 +00:00
Samuel Newman 898065d0a2 memoize each module individually (#8111) 2025-04-03 16:02:20 -05:00
Eric Bailey faa5f40c53 Wait for preferences before fetching trending data (#8109) 2025-04-03 13:32:35 -05:00
pfrazee b6185039f7 Nightly source-language update 2025-04-03 02:36:31 +00:00
Samuel Newman 87da619aaa [Explore] Base (#8053)
* migrate to #/screens

* rm unneeded import

* block drawer gesture on recent profiles

* rm recommendations (#8056)

* [Explore] Disable Trending videos (#8054)

* remove giant header

* disable

* [Explore] Dynamic module ordering (#8066)

* Dynamic module ordering

* [Explore] New headers, metrics (#8067)

* new sticky headers

* improve spacing between modules

* view metric on modules

* update metrics names

* [Explore] Suggested accounts module (#8072)

* use modern profile card, update load more

* add tab bar

* tabbed suggested accounts

* [Explore] Discover feeds module (#8073)

* cap number of feeds to 3

* change feed pin button

* Apply suggestions from code review

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

* restore statsig to log events

* filter out followed profiles, make suer enough are loaded (#8090)

* [Explore] Trending topics (#8055)

* redesigned trending topics

* rm borders on web

* get post count / age / ranking from api

* spacing tweaks

* fetch more topics then slice

* use api data for avis/category

* rm top border

* Integrate new SDK, part out components

* Clean up

* Use status field

* Bump SDK

* Send up interests and langs

---------

Co-authored-by: Eric Bailey <git@esb.lol>

* Clean up module spacing and borders

(cherry picked from commit 63d19b6c2d67e226e0e14709b1047a1f88b3ce1c)
(cherry picked from commit 62d7d394ab1dc31b40b9c2cf59075adbf94737a1)

* Switch back border ordering

(cherry picked from commit 34e3789f8b410132c1390df3c2bb8257630ebdd9)

* [Explore] Starter Packs (#8095)

* Temp WIP

(cherry picked from commit 43b5d7b1e64b3adb1ed162262d0310e0bf026c18)

* New SP card

* Load state

* Revert change

* Cleanup

* Interests and caching

* Count total

* Format

* Caching

* [Explore] Feed previews module (#8075)

* wip new hook

* get fetching working, maybe

* get feed previews rendering!

* fix header height

* working pin button

* extract out FeedLink

* add loader

* only make preview:header sticky

* Fix headers

* Header tweaks

* Fix moderation filter

* Fix threading

---------

Co-authored-by: Eric Bailey <git@esb.lol>

* Space it out

* Fix query key

* Mock new endpoint, filter saved feeds

* Make sure we're pinning, lower cache time

* add news category

* Remove log

* Improve suggested accounts load state

* Integrate new app view endpoint

* fragment

* Update src/screens/Search/modules/ExploreTrendingTopics.tsx

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

* Update src/screens/Search/modules/ExploreTrendingTopics.tsx

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

* lint

* maybe fix this

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Hailey <me@haileyok.com>
2025-04-02 17:21:15 -07:00
surfdude29 8d1f97b5ff Tweak copy to remove remaining uses of sign up (#7987)
* tweak copy in Deactivated.tsx

* tweak copy in Policies.tsx

* tweak comment in createNativeStackNavigatorWithAuth.tsx

* tweak copy in LoginForm.tsx

* tweak copy in StarterPackLandingScreen.tsx

* format

* Apply suggestions from code review

Co-authored-by: Hailey <hailey@blueskyweb.xyz>

* Update src/screens/StarterPack/StarterPackLandingScreen.tsx

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

* Update src/screens/StarterPack/StarterPackLandingScreen.tsx

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

---------

Co-authored-by: Hailey <hailey@blueskyweb.xyz>
2025-04-02 16:22:06 -07:00
surfdude29 4a7fa07e87 Add plural formatting, translate and tweak some accessibility strings in composer (#7997)
* add plural formatting and translate accessibility strings

* tweak accessibility label and add comments for translators

* fix

* tweak comments

* make label conditionally plural

* rm stray bracket

* try to fix prettier

* nope

* lint

* more lint

* prettier

---------

Co-authored-by: Hailey <me@haileyok.com>
2025-04-02 15:44:03 -07:00
Samuel Newman 0897a692da fix bg color (#8102) 2025-04-02 15:25:56 -07:00
surfdude29 c5900034a4 Simplify content warning dialog text (#7943)
* simplify content warning dialog text

* tweak copy

* Update src/view/com/composer/labels/LabelsBtn.tsx

Co-authored-by: Hailey <hailey@blueskyweb.xyz>

---------

Co-authored-by: Hailey <hailey@blueskyweb.xyz>
2025-04-02 14:51:10 -07:00
aryiu 0874d9602a Update languages.ts (#7996) 2025-04-02 10:15:02 -05:00
pfrazee 1289707b17 Nightly source-language update 2025-04-02 02:36:32 +00:00
surfdude29 758cb731f0 Add plural formatting for alt text truncated string (#7994)
* add plural formatting in GifAltText.tsx

* add plural formatting in ImageAltTextDialog.tsx

* import Plural

* format
2025-04-01 16:09:53 -07:00
surfdude29 5130f932ed Make Posts and People tabs translatable for user lists (#7982)
* mark Posts and People as translatable in lists

* tweak labels
2025-04-01 16:01:44 -07:00
Minseo Lee 8dfdee80bb Reapply "Modify hosting provider text for better localization" (#7928)
* Update HostingProvider.tsx

* Update src/components/forms/HostingProvider.tsx

---------

Co-authored-by: Hailey <hailey@blueskyweb.xyz>
2025-04-01 16:00:14 -07:00
surfdude29 df9909baa3 Translate number joined starter pack string and add plural formatting (#7984)
* translate number joined starter pack string

* also add plural formatting in StarterPackScreen.tsx

* import Plural

* tweak

* tweak
2025-04-01 15:59:53 -07:00
surfdude29 7a041da3a8 Add plural formatting for STARTER_PACK_MAX_SIZE toast (#8000)
* add plural formatting for starter pack max size toast

* tweak

* try again
2025-04-01 15:51:57 -07:00
surfdude29 ffbcbf814e add plural formatting for too long handle error (#7999) 2025-04-01 15:51:39 -07:00
surfdude29 98fe7edbc8 Add plural formatting for "too long" error messages when editing profile info (#7998)
* add plural formatting for profile max graphemes errors

* add missing tag

* simplify
2025-04-01 15:50:58 -07:00
Samuel Newman 5cb49314d0 [Reactions] Get reactions in chat list working again with new lexicon (#8093)
* get chat list reactions working again with new lexicon

* fix weird android bug where background wasn't clipped
2025-04-01 15:45:29 -07:00
Samuel Newman 318b29d3fd Fix loading jumps and footer on feeds tab (#8063)
* Fix loading jumps and footer on feeds tab

* same for lists/starter packs
2025-04-01 14:19:59 -07:00
Eric Bailey 4db3ccbec7 Fix suggested follows scrolling (#8036) 2025-04-01 11:33:31 -05:00
surfdude29 3d7fce563e add msg macro in EmojiPopup.android.tsx (#8091) 2025-04-01 09:36:46 -05:00
Samuel Newman fffcb609c6 fix warnings (#8092) 2025-04-01 17:27:40 +03:00
Samuel Newman 07d667dba8 Fix broken error screen in DMs (#8071) 2025-04-01 17:22:59 +03:00
pfrazee a9675b372e Nightly source-language update 2025-03-29 02:34:59 +00:00
Jason Culverhouse 036bbfbaf9 Remove double decode of URI (#8068)
At this point the URI is already decoded and decoding again will alter the uri 

```
      let link = req.query.u
```

example  of a link that has `%` encoding... the initial redirect link is properly encoded.

```
curl -vv "https://go.bsky.app/redirect?u=https%3A%2F%2Fsurf.social%2Ffeed%2Fsurf%252Fcustom%252F01jpz5vyjwvw5yaa8bfkha5xn4" 
```
The result is "double decoded", the proper link in this case should be `https://surf.social/feed/surf%2Fcustom%2F01jpz5vyjwvw5yaa8bfkha5xn4`

```
<html><head><meta http-equiv="refresh" content="0; URL='https://surf.social/feed/surf/custom/01jpz5vyjwvw5yaa8bfkha5xn4'" /><style>:root { color-scheme: light dark; }</style></head></html>
```

After changes:

```
curl -s "http://localhost:3000/redirect?u=https%3A%2F%2Fsurf.social%2Ffeed%2Fsurf%252Fcustom%252F01jpz5vyjwvw5yaa8bfkha5xn4"
<html><head><meta http-equiv="refresh" content="0; URL='https://surf.social/feed/surf%2Fcustom%2F01jpz5vyjwvw5yaa8bfkha5xn4'" /><style>:root { color-scheme: light dark; }</style></head></html>
```
2025-03-28 16:50:16 -07:00
Eric Bailey 7c124a8705 Preload emoji picker data for reactions on web (#8079)
* Preload emoji picker data for reactions on web

* Sort imports
2025-03-28 17:01:21 -05:00
Eric Bailey 78220e29d9 Put applied reactions inside context menu wrapper on native (#8078) 2025-03-28 16:56:32 -05:00
Eric Bailey c2d6fb82f3 Design tweaks to applied reactions (#8077)
* Adjust styles of applied reactions

* Tweaks for applied reactions styles
2025-03-28 16:38:41 -05:00
Eric Bailey a84ba121fa Some design tweaks to web emoji picker (#8076)
* Tighten up and reverse action items on web

* Tweak web styles for emoji bar

* Might as well make disabled more obvious

* Format
2025-03-28 16:38:24 -05:00
Samuel Newman 152bc3c1ec [DMs] Reactions - link up API (attempt 2) (#8074)
* update package

* wire up APIs

* get reactions to display

* allow removing emoji

* handle limits better

* listen to reactions in log

* update convo list with reactions

* tweaks to reaction display

* Handle empty message fallback case

* update package

* shift reacts up by 2px

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-03-28 07:34:07 -07:00
Samuel Newman 55a40c2436 [DMs] Emoji reaction picker (#8023) 2025-03-28 08:43:40 +02:00
pfrazee ac2c2a9a1d Nightly source-language update 2025-03-28 02:36:35 +00:00
Samuel Newman 5ceaee5793 Instrument signup (#8037) 2025-03-27 20:17:07 +02:00
Samuel Newman 7d1ebf6a02 Allow selecting ContextMenu options via press-and-hold (#8020)
* save locations of menu items

* enable panning to select items

* rm unused type

* fix haptic overfiring
2025-03-27 09:53:42 -07:00
Eric Bailey 1e688dee24 Make sure Sentry's auth token is set on process (#8040)
* Make sure Sentry's auth token is set on process

* Pass in token explicitly
2025-03-27 09:43:59 -05:00
Samuel Newman c265e0fb96 fix people list footer (#8039) 2025-03-27 10:18:02 +02:00
pfrazee 5dc4f0450c Nightly source-language update 2025-03-25 02:35:58 +00:00
Samuel Newman a48e64e72a make the sidebar smaller when offset, reduce total offset (#8052) 2025-03-24 22:23:27 +02:00
Samuel Newman 412b107420 Extract center column offset, reduce by 20px (#7974)
* extract offset, reduce by 20px

* move constant to `Layout/const.ts`
2025-03-24 12:55:05 -07:00
omar0404 1b8719293c fix:Conversations don't refresh when going offline and back online (#7985) 2025-03-24 12:45:43 -07:00
Samuel Newman dba6f4bb1f Revert "Small revert to be on the safe side (#7932)" (#7958)
This reverts commit 0014b8b9cd.
2025-03-24 12:11:13 -07:00
Bas van den Wollenberg 6a5770ee89 change touch device detection method (#5919) 2025-03-24 12:07:56 -07:00
Samuel Newman 7daf7a703e haptics on external link card (#8049) 2025-03-24 10:17:35 -07:00
pfrazee 6fcf97979b Nightly source-language update 2025-03-22 02:33:52 +00:00
Samuel Newman 951a8cff3c bump version to 1.100.0 (#8038) 2025-03-21 18:51:29 +02:00
Samuel Newman c4785ef96e New ContextMenu menu type for DM messages (#8014)
* get context menu somewhat working ish

* take screenshot rather than double rendering

* get animations somewhat working

* get transform animation working

* rm log

* upwards safe area

* get working on android

* get android working once and for all

* fix positioning on both platforms

* use dark blur on ios always, fix dark mode

* allow closing with hardware back press

* try and fix type error

* add note about ts-ignore

* round post

* add image capture error handling

* extract magic numbers

* set explicit embed width, rm top margin

* Message embed width tweaks

* Format

* fix position of embeds

* same as above for web

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-03-21 09:29:14 -07:00
Samuel Newman f6f253b4c9 Add eslint consistent type import rules (#8035)
* add eslint-plugin-import

* turn off eslint/no-usused-vars
2025-03-21 08:43:10 -07:00
pfrazee 3cfac98f95 Nightly source-language update 2025-03-21 02:35:41 +00:00
Hailey 52429b651f blink: use meta for redirect (#8031)
* try using meta

* color scheme

* revert test change

* escape
2025-03-20 15:08:54 -07:00
Hailey 0e658dbdfd blink: redirect on root route (#8029)
* make root route redirect to 301

* use config

* end

* add a comment
2025-03-20 14:50:15 -07:00
Samuel Newman d3c44ebc5b Fix post thread item hider line height crop (#8028) 2025-03-20 23:33:19 +02:00
pfrazee 950e2e5f74 Nightly source-language update 2025-03-20 02:34:32 +00:00
Samuel Newman 57d91373f7 rm bad ref in render usage (#8024) 2025-03-19 11:26:09 -07:00
pfrazee 6d8124c7ea Nightly source-language update 2025-03-18 02:35:37 +00:00
Hailey aa86a8619c remove from iab (#8017) 2025-03-17 15:13:34 -07:00
Hailey c612fca32a remove .parse usage (#8016)
* remove .parse usage

* add one more usage
2025-03-17 15:06:26 -07:00
Eric Bailey 4b7bda705e Don't poll for latest for Discover (#7993) 2025-03-17 12:18:59 -05:00
Paul Frazee 799205e6c2 Update i18n (#7992)
* Pull latest from crowdin

* Run intl:extract:all
2025-03-14 13:36:01 -07:00
Eric Bailey 5bff031e72 A few good metrics (#7897)
* Align dist and release tags on all platforms

* Upload web sourcemaps

* Debug code

* Send debug and error logging to Sentry

* Let .env do the work

* Try straight env

* Try copy in Dockerfile

* Ok ok ok

* Debug Dockerfile

* Proper setup

* See where we're at

* Reference var correctly

* Fall back to package version

* Verbose force env

* Should be working native builds

* Comments

* Remove unused deps

* Revert unneeded changes

* Remove debug code

* Clarify intent

* Remove deprecated files

* Add sentry vars to OTA

* Debug

* Revert "Debug"

This reverts commit 2d5857fb0fb0858ac3e2f98bc56bde913078d0a7.

* Use included CLI to upload native source maps post-OTA build

* Use included bin script

See https://github.com/getsentry/sentry-react-native/commit/0d87adb516b2a5ea61353e25098c31f9aeb7e503

* Bump sentry, update script

* Comment

* fix failing CI

* Pin sentry, update patch, update lock

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-03-14 12:08:19 -05:00
Eric Bailey 9cea7f0393 Fix missing RecordWithMedia media embed preview in notifications view (#7988) 2025-03-14 10:28:02 -05:00
Eric Bailey dcc8b35146 Add checks for invalid syntax post-i18n builds (#7935) 2025-03-14 10:27:45 -05:00
pfrazee cb54c9833e Nightly source-language update 2025-03-14 02:33:55 +00:00
Samuel Newman 1f1c1cfbcd Filter deleted convos from inbox (#7944)
* filter deleted convos from inbox

* fix logic
2025-03-13 08:50:26 -07:00
Samuel Newman 6cbd9fbc45 Fix lists tab appearing when user has a starterpack but no lists (#7952)
* Fix list tab showing up when no lists

* tweak code
2025-03-13 08:46:24 -07:00
Samuel Newman c7ba0e4f66 fix newskie dialog width (#7949) 2025-03-13 08:44:14 -07:00
surfdude29 4b94a8a8f2 fix typo (#7970) 2025-03-13 08:35:13 -07:00
Samuel Newman c402ae741f Restore hardcoded DIDs for Discover debug (#7977) 2025-03-13 16:59:21 +02:00
pfrazee b2a6281b36 Nightly source-language update 2025-03-13 02:35:07 +00:00
surfdude29 597e3c1abd tweak label (#7937) 2025-03-12 06:59:21 -07:00
omar0404 5e1c262edc fix: Account switcher shows outdated profile name (#7969) 2025-03-12 06:58:57 -07:00
pfrazee 810e85c073 Nightly source-language update 2025-03-12 02:34:05 +00:00
surfdude29 d16c80d928 Update VideoTooLargeError strings (#7923) 2025-03-12 00:56:40 +02:00
Samuel Newman e7212f9904 clean up logic for showing request buttons (#7964) 2025-03-11 13:12:49 -07:00
Hailey 490e381270 encode url (#7968) 2025-03-11 12:50:17 -07:00
Samuel Newman 26fb0a7f17 fix iframe transparency by unspecifying color-scheme (#7967) 2025-03-11 12:21:27 -07:00
Samuel Newman 94d7bc986f Fix color theme for embed (#7965)
* fix embed default theme

* use correct dataset string
2025-03-11 11:04:06 -07:00
Samuel Newman 8cb55adf8c fix submit behaviour (#7959) 2025-03-11 09:37:53 -07:00
Paul Frazee d155b718b5 Run intl:extract:all 2025-03-07 10:32:10 -08:00
Eric Bailey 166c56c4cb Fix translation def (#7934) 2025-03-07 12:07:04 -06:00
Paul Frazee 131578ca3a Run intl:pull 2025-03-07 08:41:50 -08:00
Eric Bailey 0014b8b9cd Small revert to be on the safe side (#7932)
* Revert "fix autocomplete (#7930)"

This reverts commit f06a78017a.

* Revert "#6861: Use available space to make focus on Composer TextInput easier (copy) (#7836)"

This reverts commit e40656128d.
2025-03-07 10:34:14 -06:00
Samuel Newman f06a78017a fix autocomplete (#7930) 2025-03-07 10:20:55 -06:00
Eric Bailey 27ae829698 Add plugin to bump gradle jvm heap size (#7922) 2025-03-06 20:21:54 -08:00
Paul Frazee ada2ac8b91 Release 1.99 prep (#7925)
* Revert #7847 (was causing layout issues)

* Test fixes

* Pull latest translations from crowdin

* Run intl:extract:all
2025-03-06 19:45:29 -08:00
Eric Bailey fd8ac1da7d Catch thrown error for autoplay in Safari (#7921) 2025-03-06 19:14:00 -08:00
pfrazee beb0fce56c Nightly source-language update 2025-03-07 02:34:14 +00:00
Samuel Newman ac43b666cb Fix text not wrapping in social proof (#7920)
* Fix text not wrapping in social proof

* fix web too

* add max_w_full atom
2025-03-06 15:54:40 -08:00
Hailey 618c4e4a56 add some metrics for labelers (#7747)
* add some metrics

* add label pref switch metric

* Update src/screens/Profile/Header/ProfileHeaderLabeler.tsx

* Use new logger.metric

* Fix conflicting types

* Remove duplicate toasts

* Move metric to try body

* Move metric to try body

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-03-06 14:20:48 -06:00
Samuel Newman 153fc17676 tweak ci (#7916) 2025-03-06 11:49:51 -08:00
Eric Bailey 8eb1f8f1fc Merge #7903 (#7917)
* Add missing msg macro calls for i18n (#7903)

* Add missing msg macro calls for i18n

* Update src/screens/Settings/AppIconSettings/useAppIconSets.ts

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

* Apply suggestions from code review

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

* Apply surfdude29's suggestions from code review

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

---------

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

* Format

---------

Co-authored-by: Stanislas Signoud <signez@stanisoft.net>
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
2025-03-06 12:14:58 -06:00
Seth Wood da2b6f4797 fixing moderation blur gap when replying via the thread feed (#7783) 2025-03-06 12:10:39 -06:00
Samuel Newman 1c16c6ef0a fix cancel button on search posts screen (#7912) 2025-03-06 10:06:13 -08:00
Minseo Lee a7db0bac6f Add context for toast messages (#7902)
* add context for toast

* add
2025-03-06 11:46:09 -06:00
Samuel Newman 29eef6188a Filter searchable people list by accepted (#7915) 2025-03-06 08:34:59 -08:00
pfrazee ba3cff62f1 Nightly source-language update 2025-03-06 02:33:59 +00:00
Eric Bailey 3be87fbf3b Add report dialog e2e tests (#7913) 2025-03-05 16:31:55 -08:00
Samuel Newman 9fde3957e7 ota helper in dev mode (#7911) 2025-03-05 16:01:17 -08:00
surfdude29 dae152da85 Add language: Esperanto (#7863)
* Create messages.po

* Update app.config.js

* Update lingui.config.js

* Update dates.ts

* Update helpers.ts

* Update i18n.ts

* Update i18n.web.ts

* Update languages.ts
2025-03-05 15:57:09 -08:00
surfdude29 a42efd15d7 Add language: Scottish Gaelic (#7864)
* Create messages.po

* Update app.config.js

* Update lingui.config.js

* Update dates.ts

* Update helpers.ts

* Update i18n.ts

* Update i18n.web.ts

* Update languages.ts
2025-03-05 15:56:13 -08:00
surfdude29 d0c2003cc7 Add language: Welsh (#7866)
* Create messages.po

* Update app.config.js

* Update lingui.config.js

* Update dates.ts

* Update helpers.ts

* Update i18n.ts

* Update i18n.web.ts

* Update languages.ts
2025-03-05 15:55:29 -08:00
Paul Frazee 1cfdd2a7a0 Merge branch 'main' of github.com:bluesky-social/social-app into main 2025-03-05 14:39:28 -08:00
Paul Frazee 663f16dfc2 Add initial test for post report flow 2025-03-05 14:39:20 -08:00
surfdude29 947c876fdb mark label for translation (#7908) 2025-03-05 14:32:29 -08:00
Samuel Newman a62fe855c3 skeletons for chat list (#7907) 2025-03-05 09:55:55 -08:00
Samuel Newman c5d9e282e5 fix layout shift in profile feed header (#7906) 2025-03-05 09:54:14 -08:00
Samuel Newman f5f02aa4b3 Add dark mode option to in-app embed snippet dialog (#7377)
* add color theme selection

* change chevron direction

* change chevron direction again

* rm unused ref
2025-03-05 09:50:20 -08:00
Samuel Newman 2d854091b9 enhance(embed): add ability to pin color mode (#7186)
* enhance(embed): add ability to pin color mode

* fix: Move color mode dropdown to the root section

* auto -> system

* style tweaks

* default to light theme

* try and fix eslint

* fix dropdown styles on other browsers

* rm unnecessary eslintrc change

* more explicit color mode select

* make light explicit

---------

Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-03-05 09:24:59 -08:00
pfrazee 01a51c3275 Nightly source-language update 2025-03-05 02:33:32 +00:00
Hailey dda0db9963 use latest macos/xcode (#7893) 2025-03-04 09:24:07 -08:00
Samuel Newman 67c394bc82 Prioritise language codes with regions (#7731)
* prioritise chinese and portugese

* more language name cleanup

* skip ast to fix false positive
2025-03-04 06:03:11 -08:00
Samuel Newman c995eb2f2f DMs inbox (#7778)
* improve error screen

* add chat request prompt

* mock up inbox

* bigger button

* use two-button layout

* get inbox working somewhat

* fix type errors

* fetch both pages for badge

* don't include read convos in preview

* in-chat ui for non-accepted convos (part 1)

* add chatstatusinfo

* fix status info not disappearing

* get chat status info working

* change min item height

* move files around

* add updated sdk

* improve badge behaviour

* mock up mark all as read

* update sdk to 0.14.4

* hide chat status info if initiating convo

* fix unread count for deleted accounts

* add toasts after rejection

* add prompt to delete

* adjust badge on desktop

* requests -> chat requests

* fix height flicker

* add mark as read button to header

* add mark all as read APIs

* separate avatarstack into two components (#7845)

* fix messages being hidden behind chatstatusinfo

* show inbox preview on empty state

* fix empty state again

* Use new convo availability API (#7812)

* [Inbox] Accept button on convo screen (#7795)

* accept button on convo screen

* fix types

* fix type error

* improve spacing

* [DMs] Implement new log types (#7835)

* optimise badge state

* add read message log

* add isLogAcceptConvo

* mute/unmute convo logs

* use setqueriesdata

* always show label on button

* optimistically update badge

* change incorrect unread count change

* Update src/screens/Messages/Inbox.tsx

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

* Update src/screens/Messages/components/RequestButtons.tsx

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

* Update src/screens/Messages/components/RequestButtons.tsx

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

* Update src/screens/Messages/components/RequestListItem.tsx

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

* fix race condition with accepting convo

* fix back button on web

* filter left convos from badge

* update atproto to fix CI

* Add accept override external to convo (#7891)

* Add accept override external to convo

* rm log

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
2025-03-04 05:54:19 -08:00
Samuel Newman 5c14f69566 Modernize search page (take 2) (#7642) 2025-03-04 10:12:34 +00:00
pfrazee 66c09d9953 Nightly source-language update 2025-03-04 02:33:23 +00:00
Samuel Newman c82f768374 fix progress guide location breakpoints (#7887) 2025-03-03 18:57:47 -06:00
Samuel Newman 7222d6fe52 init log using getLog (#7886) 2025-03-03 15:41:13 -08:00
pfrazee 8b6dde17fd Nightly source-language update 2025-03-02 02:34:39 +00:00
Eric Bailey 07dd57d1ea Add metrics to reporting flow (#7871)
* Add metrics to reporting flow

* Remove vestigial state
2025-03-01 13:34:12 -06:00
pfrazee 1c582c59f0 Nightly source-language update 2025-03-01 02:34:56 +00:00
Eric Bailey 84fcbe398b Fix missed logger tests (#7872) 2025-02-28 18:25:49 -06:00
Eric Bailey 3be9dde92d New reporting flow (#7832)
* Add option to align web dialogs to top

* Add new wait util

* Pipe through feed view to feed components

* Reset unneeded change to main

* Copy over fresh report dialog based on old

* Hack in temp testing data

* Swap in new dialog in all cases but chat

* Cleanup

* Add load and initial error state

* Fill in states

* Add copyright link

* Handle single labeler case

* Comment out debug code

* Improve centering of type in circles

* Open details if Other is selected

* Remove debug code

* Tweak colors

* Bump SDK

* Tweak Admonition for better x-platform styles

* Add retry button

* Add close button

* Remove todo not covered in this PR

* Translate Retry
2025-02-28 17:14:02 -06:00
Eric Bailey 96f4f6359a Logger metrics (#7867)
* Adjust datalake abstraction

(cherry picked from commit 8ba6a8d45b1bd5698afbd06d9e858a91789f0ea6)

* Just be really really specific

(cherry picked from commit 920198959659329a7f7f7282a1293aaad198d8e3)

* Add metric method to logger, replace datalake calls with new method

(cherry picked from commit 7a026bbeae75514b64f928d7ff59707c518fd5e5)

* Clarify types

(cherry picked from commit 422b150deb158a70ef37e8a456d91bf26cd0b1bc)
2025-02-28 17:13:49 -06:00
Samuel Newman 9e59a2eef2 Fix starter pack layout (#7869) 2025-02-28 14:50:44 -08:00
bnewbold 462708e207 bskyweb: add robots disallow and 'canonical' config flags (#4760) 2025-02-28 16:09:48 -05:00
Eric Bailey 36a7a8d8c6 Colocate bitdrift in logger, use logger for transport (#7868)
* Colocate bitdrift in logger, use logger for transport

(cherry picked from commit cdd6941fd7)

* Fix mocks, format

(cherry picked from commit 9de88660c6)

* Ok I guess mocks dir doesn't work

(cherry picked from commit 9f37e52011)
2025-02-28 12:46:27 -06:00
Eric Bailey 7c36ea1158 Logger improvements (#7729)
* Remove enablement

* Refactor context and filtering

* Fix imports, simplify transports config

* Migrate usages of debug context

* Re-org, add colors and grouping to console logging

* Remove temp default context

* Remove manual prefix

* Move colorizing out of console transport body

* Reduce reuse

* Pass through context

* Ensure bitdrift is enabled in dev

* Enable Sentry on web only

* Clean up types

* Docs

* Format

* Update tests

* Clean up tests

* No positional args

* Revert Sentry changes

* Clean up context, use it, pass metadata through to Bitdrift

* Fix up debugging

* Clean up metadata before passing to Bitdrift

* Correct transports

* Reserve context prop on metadata and include in transports

* Update tests
2025-02-28 12:09:36 -06:00
surfdude29 9e9ffd5c6e fix label (#7856) 2025-02-28 09:49:01 -08:00
pfrazee 3f963cfed7 Nightly source-language update 2025-02-28 02:33:23 +00:00
Hailey a2b71e3a4b tweak link handling (#7857) 2025-02-27 13:18:30 -08:00
pfrazee a3d36393a1 Nightly source-language update 2025-02-27 02:33:08 +00:00
surfdude29 b996b304c3 Tweak accessibility label and add translation comment (#7843)
* make label clearer

* add translation comment
2025-02-26 07:36:53 -08:00
Minseo Lee ec75cbc01f Modify hosting provider text for better localization (#7847)
* Update HostingProvider.tsx

* Update src/components/forms/HostingProvider.tsx

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2025-02-26 07:36:31 -08:00
Seth Wood b924c53b23 Fix for avatar preloading (#7816)
* mobile avatar profile preloading fix

* updating fix to include moderation

* removing comments, adding disableNavigation to PreviewableUserAvatarProps
2025-02-26 07:33:27 -08:00
Samuel Newman c5b831d5d8 Bump version (#7846) 2025-02-26 06:24:19 -08:00
pfrazee 3795d85591 Nightly source-language update 2025-02-26 02:32:31 +00:00
Samuel Newman 7dc8ba8e4e label pref alignment (#7844) 2025-02-25 19:50:01 -06:00
Samuel Newman 22aee9704c improve toasts on oled dark mode (#7842) 2025-02-25 11:12:38 -08:00
Samuel Newman 3409a72548 Add soft reset to chat list (#7771)
* add soft reset to chat list

* refresh when soft resetting
2025-02-25 10:27:11 -08:00
surfdude29 595a894551 translate hosting provider text (#7834) 2025-02-25 09:54:20 -08:00
Samuel Newman 0d1373bb71 Remove moderatePost_wrapped (#7188)
* rm `moderatePost_wrapped`

* Handle display in app

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2025-02-25 11:21:00 -06:00
Samuel Newman cc8369e868 Better tablet layout (#7656)
* better tablet layout

* adjust left nav spacing

* add right nav to pwi

* clearer logic

* fix a couple screens that don't need the tablet layout

* fix horiz scroll bar

* fix double trending

* fix ts-ignore

* fix labeller screen

* don't offset things within dialogs

* fix load latest button (and add scale animation)

* center loader on home screen

* adjust break points

* adjust left nav spacing

* fix load latest btn (again)

* add lang select to right nav if left nav is minimal

* fix double scrollbar on tiny screens

* fix scrollbar

* fix type errors
2025-02-25 09:20:37 -08:00
Eric Bailey 0437838649 Fix max height of dialog flatlists (#7839)
* Fix max height of dialog flatlists

* Remove unneeded wrapper to fix Close positioning

* Add wrapper back and fix with position static
2025-02-25 11:12:56 -06:00
Samuel Newman 23f0092440 hackfix likes tab (#7770) 2025-02-25 09:02:08 -08:00
Samuel Newman 9c5d92088d Constrain dropdown height to fit in the screen (#7730)
* constrain dropdown height with css variable

* fix duplicated dependency

* fix pendantic lockfile
2025-02-25 08:08:30 -08:00
Samuel Newman e40656128d #6861: Use available space to make focus on Composer TextInput easier (copy) (#7836)
* 6861: Use available space to make focus on Composer TextInput easier

* Undo web

* bluesky-social#6861: Adjust focus area for native platforms taking Embeds into consideration

* use atoms

* remove empty div

* remove debug atom, whoopsie

---------

Co-authored-by: GrizliK1988 <dgrachikov@gmail.com>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2025-02-25 08:07:45 -08:00
pfrazee d76cd88d91 Nightly source-language update 2025-02-25 02:32:46 +00:00
Samuel Newman 6254cf020a Dedupe profile labels (#7833)
* dedupe labels

* apply to postalerts
2025-02-24 14:17:59 -08:00
Hailey 61a14043e5 add to blink (#7788) 2025-02-24 13:59:57 -08:00
surfdude29 3fc4c32ac6 Plural formatting for accessibility unread items strings (#7743) 2025-02-24 13:11:01 -08:00
surfdude29 a383b9ba28 Plural formatting for TimeIndicator accessibilityLabel (#7826) 2025-02-24 13:10:53 -08:00
surfdude29 bf4d3e89c2 Add plural formatting for months in narrow form (#7744) 2025-02-24 13:10:40 -08:00
surfdude29 1fd3af3c46 Tweak app language string in Settings (#7825) 2025-02-24 13:10:00 -08:00
surfdude29 3f879f0315 Tweak prompt title text when removing a feed (#7824) 2025-02-24 13:04:01 -08:00
Samuel Newman 7c14b54ab2 Fix DMs input automatically accepting autocomplete suggestion instead of clearing (#7796)
* fix input not clearing when autocomplete suggestion active

* fix up storybook

* restore web focus hack
2025-02-24 13:03:01 -08:00
surfdude29 9c739912a3 Tweak accessibility strings (#7822) 2025-02-24 12:59:55 -08:00
surfdude29 c4dec63960 Suggested updates to localization doc (#7828)
* update localization doc

* tweak wording order

---------

Co-authored-by: Hailey <me@haileyok.com>
2025-02-24 12:52:39 -08:00
surfdude29 a7e1913e22 move translation tags (#7823) 2025-02-24 12:49:26 -08:00
surfdude29 a1699da1a9 separate strings for translation in ListHiddenScreen.tsx (#7827) 2025-02-24 12:48:42 -08:00
Samuel Newman ae9176c9c2 Basic minimum password requirements, plus field-specific errors (#7811)
* add min password requirement

* add field specific errors

* move email tld check to after other email checks

* add password length check to change password dialog

* Update src/view/com/modals/ChangePassword.tsx

Co-authored-by: Hailey <me@haileyok.com>

* Update src/screens/Signup/StepInfo/index.tsx

Co-authored-by: Hailey <me@haileyok.com>

* fix lint

---------

Co-authored-by: Hailey <me@haileyok.com>
2025-02-24 12:44:21 -08:00
Samuel Newman 3d954a00e0 precache recent profile click (#7831) 2025-02-24 12:39:41 -08:00
Samuel Newman f9392d4a96 Fix optimistic rendering of profile page (#7830)
* don't hold up rendering on starter packs

* add tab based on profile.associated

* move query into component, fix pending states
2025-02-24 11:50:52 -08:00
Paul Frazee bdcddee7a5 Update localization.md to change crowdin links 2025-02-24 08:06:15 -08:00
pfrazee 5c3576dee7 Nightly source-language update 2025-02-24 02:33:53 +00:00
gpp 7a3a1a2bd0 make composer pills tappable when keyboard is active (#7717) 2025-02-23 05:19:58 -08:00
pfrazee e6193d7036 Nightly source-language update 2025-02-22 02:28:50 +00:00
Nicolas Borlet cb85768e9c fix: click on our profile when seeing someone's profile (#7732)
Co-authored-by: Stanislas Signoud <signez@stanisoft.net>
Co-authored-by: Hailey <me@haileyok.com>
2025-02-21 11:39:57 -08:00
Samuel Newman ca7116ec3b connect inputs together in signup (#7809) 2025-02-21 11:25:42 -08:00
Samuel Newman 80e59d31d0 npx update-browserslist-db@latest (#7677) 2025-02-21 11:13:21 -08:00
Samuel Newman ca70aacb8a Mute account from post (#7712)
* mute account from post

* move options around
2025-02-21 11:12:51 -08:00
Samuel Newman e6bfeb1bab Fix android datepicker height (#7804)
* fix datepicker height

* fix suffixtext clipping
2025-02-21 11:10:51 -08:00
Samuel Newman 3b4f1e91e3 consistent sentence case captialisation (#7749) 2025-02-21 11:10:33 -08:00
Samuel Newman fff625167f set minimum birthday to 13 years ago (#7808) 2025-02-21 10:59:27 -08:00
Samuel Newman 5d30111b78 Get sheet padding working consistently (#7798)
* tweak height/padding of iOS

* tweak android ratio calculation

* add a bit of extra padding to full height iOS to account for the bit below the safe area
2025-02-21 10:59:08 -08:00
Samuel Newman 798bf47827 fix handle length error message (#7802) 2025-02-21 08:42:21 -08:00
Paul Frazee b0f7f51b04 Set branch to main on crowdin nightly push 2025-02-20 22:15:11 -08:00
Paul Frazee ea9f2dfbdd Fix bad indent 2025-02-20 22:02:26 -08:00
Paul Frazee 1fda7d0553 Add crowdin nightly push (#7799)
* Update crowdin.yml to point to new enterprise endpoint

* Update nightly crowdin action to push source strings to crowdin
2025-02-20 22:00:32 -08:00
pfrazee 7ff65df417 Nightly source-language update 2025-02-20 02:28:35 +00:00
bnewbold f8f88878dc makefile: bump nvm to use node 20 (#7324) 2025-02-19 16:12:51 -08:00
Paul Frazee 8f63cb86b1 Update intl:build to extract for all languages (#7787) 2025-02-19 12:52:58 -08:00
Samuel Newman ed4add7072 improve car dialog styles (#7786) 2025-02-19 12:35:33 -08:00
pfrazee 48fd397d46 Nightly source-language update 2025-02-19 02:28:13 +00:00
Eric Bailey f23a621c7e Remove shadowed follow gate handling (#7774) 2025-02-18 17:25:59 -06:00
Eric Bailey da45c42b6f [APP-1049] show label expiration in frontend (#7738)
* Add support for label exp to LabelsOnMeDialog

* Add exp to PostAlerts, align with LabelsOnMe UI

* Bump weight

* Improve translations

* Expiry should round up

* Add a little visual alignment hack
2025-02-18 09:45:46 -06:00
Eric Bailey 63ba0a436b [APP-1054] Add option to align web dialogs to top (#7760)
* Add option to align web dialogs to top

* Format

* Align all dialogs to top, with relative spacing on larger screens for better balance
2025-02-18 09:45:37 -06:00
Eric Bailey a51fc8e434 @atproto/api@next integration (#7344)
* Bump SDK

* Use consistent type in profile query

* Omit  from constraint for profile shadow

* Replace isRecord with isValidRecord in QuoteEmbed

* Omit type from constraint for old ProfileCard

* Omit type from constraint in profile queries where appropriate

* Use correct type for update profile mutation

* Conslidate and fix check for isValidRecord in Post.tsx

* Replace isRecord with isValidRecord in PostThreadItem

* Remove redundant cast in PostThreadFollowBtn

* Ignore errors in DebugMod screen

* Use matching type in ProfileFollows screen

* Use matching type in ProfileFollowers screen

* Migrate to isValidRecord in PostFeedItem

* Use matching type if PostRepostedBy

* Omit type from constraint in avatar props

* Use matching types in NotificationFeedItem

* Todo

* Use isValidRecord in NotfyFeedItem

* Improve MediaPreview types

* Migrate another isValidRecord in NotificationFeedItem

* Migrate to isValidView in queries/util

* Migrate to isValidRecord in threadgate/util

* Fix types in threadgates

* Fix up types in starter-packs queries

* Todo

* Specify exact types in search-posts

* Use internal type util to align types

* Ditto last

* Migrate postgate/index

* Specify exact types in post-thread

* Use correct type in post-quotes

* FIX potential bug in post-thread

* Use correct type in post-feed

* Add correct type guards to notifications/feed

* Migrate a guard in notifications/util

* Migrate guard in Wizard/State

* [@next] Profile handling, migrate `ProfileCard` (#7347)

* Introduce new utils for profiles, migrate old ProfileCard

* Rename, reorg

* Add parseEmbed utils

* Expand AnyProfileView to include chat profile view, update post shadow to reflect this

* Cast for perf reasons

* Tighten up types now that we have AnyProfileView

* Add fastIsType util

* Use `assertDid`

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>

* Use util types

* Comment

* Use fastIsType where no validation was happening before

* suggestions (#7382)

* suggestions

* Revert unneeded changes

---------

Co-authored-by: Eric Bailey <git@esb.lol>

* Use new util

* Rename to dangerousIsType

* Convert object shape

* Use dangerous util

* Use dangerous util

* Use dangerous util, we can trust post records

* Use dangerous util

* Use AnyProfileVIew

* Convert object shape

* Clean up handling

* Patch moderateProfile to accept known profile views, to discuss

* Add AnyStarterPackView and related, implement in first usage

* Remove validation, fix type, fix ref

* Migrate over list-conversations

* Clarify intent behind precacheProfile and its unstable query cache

* Clean up unstable profile cache

* Fix types during label creation in PwiOptOut (#7346)

* Tighten types in queries/list

* Chat: use correct profile views

* Chat: fix log type check

* Chat: construct lexically correct shape, even though it's only internal usage

* Chat: use correct profile types

* Chat: fix type check in logs

* Starter: use correct profile types

* Starter: use correct profile types

* Starter: tighten types to match lex

* Any profile type will work in blocked-and-muted

* Use dangerous util

* Use dangerousIsType

* Update new ProfileCard to use AnyProfileView

* Use dangerousIsType

* Remove outdated todo

* Use correct profile type

* Use correct profile types

* Tighten up types

* Use dangerousIsType

* Chat: more type fixes

* Remove unused file

* Add a few  utils

* Remove unused file

* Ignore feedPost.__source

* Clean up types, leave validation in critical path

* Use dangerousIstype

* Use ANyProfileView

* Use isValidRecord

* Use dangerousIsType

* Fix types in ListCard

* Fix FeedInterstitials types

* Fix types in FeedCard

* Fix types in dms ReportDialog

* Fix types in SearchablePeopleList

* Fix bad type in composer opts

* Starter: ok these need to be loose too

* Clarify docs

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>

* Less code

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>

* Use package exports

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>

* Use package exports

* Bump sdk, update $Typed imports

* Format

* Format

* Fix weird TS error

* Remove patch

* Beter name

* It's memo, can validate

* Tighten up parseEmbed, dogfood

* Bump sdk

* Use asPredicate

* Loosen types a bit

* use asPredicate

* Fix types

* Use asPredicate

* Use asPredicate

* Use asPredicate

* Clean up upsertProfile types

* Use asPredicate

* Use Un util

* Fix types

* Use new AnyProfileView

* Use dangerousIsType

* Use asPredicate

* Use asPredicate

* Add fallback content-type to pass typecheck

* Clean up upsertProfile types

* Align types

* Use dangerousIsType

* Use dangerousIsType

* Use asPredicate

* Align types

* Convert findLast

* Align types

* Just ignore type errors and use findLast

* Rename atproto -> bsky

* Add validate util

* Fix type error

* Loosen types

* Export post

* rename atp bsky

* Remove unused code

* minor changes

* Bump deps

* Fix types

* Tighten back up loose check

* Tighten back up loose check

* Fix small bug

* Update comment

* Revert change

---------

Co-authored-by: Matthieu Sieben <matthieusieben@users.noreply.github.com>
Co-authored-by: Matthieu Sieben <matthieu.sieben@gmail.com>
2025-02-18 08:54:25 -06:00
Paul Frazee e2c0f78719 Fix mapping (#7767) 2025-02-17 19:55:40 -08:00
Paul Frazee 4146f9fe02 Update i18n release process to solve missing translations (#7766)
* Update release process to avoid untranslated strings

* Run intl:extract:all
2025-02-17 19:52:17 -08:00
pfrazee a28791680f Nightly source-language update 2025-02-18 02:27:08 +00:00
Minseo Lee d805dec08f Fix "log in", "log out" to "sign in", "sign out" (#7739)
* log to sign

* logged to signed
2025-02-17 10:52:06 -06:00
Marc Rousavy 326445d3af Make Android app start faster by disabling JS bundle compression (#7751)
* perf: Disable Android  compression to speed up app startup

* fix: Fix the gradle plugin
2025-02-17 07:31:40 -08:00
pfrazee 40d05ac866 Nightly source-language update 2025-02-15 02:26:52 +00:00
716 changed files with 207003 additions and 93239 deletions
+12 -13
View File
@@ -15,6 +15,7 @@ module.exports = {
'simple-import-sort',
'bsky-internal',
'eslint-plugin-react-compiler',
'import',
],
rules: {
'react/no-unescaped-entities': 0,
@@ -32,6 +33,8 @@ module.exports = {
'H6',
'P',
'Admonition',
'Admonition.Admonition',
'Span',
],
impliedTextProps: [],
suggestedTextWrappers: {
@@ -80,20 +83,16 @@ module.exports = {
],
'simple-import-sort/exports': 'error',
'react-compiler/react-compiler': 'warn',
'no-restricted-imports': [
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
paths: [
{
name: '@atproto/api',
importNames: ['moderatePost'],
message:
'Please use `moderatePost_wrapped` from `#/lib/moderatePost_wrapped` instead.',
},
],
},
{argsIgnorePattern: '^_', varsIgnorePattern: '^_'},
],
'@typescript-eslint/ban-ts-comment': 'warn',
'@typescript-eslint/consistent-type-imports': [
'warn',
{prefer: 'type-imports', fixStyle: 'inline-type-imports'},
],
'import/consistent-type-specifier-style': ['warn', 'prefer-inline'],
},
ignorePatterns: [
'**/__mocks__/*.ts',
@@ -105,9 +104,9 @@ module.exports = {
'*.lock',
'.husky',
'patches',
'bskyweb',
'*.html',
'bskyweb',
'bskyembed',
'src/locale/locales/_build/',
'src/locale/locales/**/*.js',
],
@@ -45,7 +45,10 @@ jobs:
- name: Set outputs
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
run: |
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
- name: Build and push Docker image
id: build-and-push
@@ -60,3 +63,7 @@ jobs:
cache-to: type=gha,mode=max
build-args: |
EXPO_PUBLIC_BUNDLE_IDENTIFIER=${{ steps.vars.outputs.sha_short }}
SENTRY_DIST=${{ steps.vars.outputs.SENTRY_DIST }}
SENTRY_RELEASE=${{ steps.vars.outputs.SENTRY_RELEASE }}
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_DSN=${{ secrets.SENTRY_DSN }}
+12 -3
View File
@@ -56,7 +56,10 @@ jobs:
run: yarn install
- name: 🔤 Compile translations
run: yarn intl:build
run: yarn intl:build 2>&1 | tee i18n.log
- name: Check for i18n compilation errors
run: if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compilation errors!\n\n"; fi
- name: ✏️ Write environment variables
run: |
@@ -67,8 +70,14 @@ jobs:
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "$json" > google-services.json
- name: Setup Sentry vars for build-time injection
id: sentry
run: |
echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
- name: 🏗️ EAS Build
run: yarn use-build-number-with-bump eas build -p android --profile ${{ inputs.profile || 'testflight-android' }} --local --output build.aab --non-interactive
run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} yarn use-build-number-with-bump eas build -p android --profile ${{ inputs.profile || 'testflight-android' }} --local --output build.aab --non-interactive
- name: ✍️ Rename Testflight bundle
if: ${{ inputs.profile != 'production' }}
@@ -130,7 +139,7 @@ jobs:
- name: 🏗️ Build Production APK
if: ${{ inputs.profile == 'production' }}
run: yarn use-build-number-with-bump eas build -p android --profile production-apk --local --output build.apk --non-interactive
run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} yarn use-build-number-with-bump eas build -p android --profile production-apk --local --output build.apk --non-interactive
- name: 🚀 Upload Production APK Artifact
id: upload-artifact-production-apk
+13 -4
View File
@@ -14,7 +14,7 @@ on:
jobs:
build:
name: Build and Submit iOS
runs-on: macos-14
runs-on: macos-15
steps:
- name: Check for EXPO_TOKEN
run: >
@@ -52,7 +52,7 @@ jobs:
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '15.3'
xcode-version: '16.2'
- name: ☕️ Setup Cocoapods
uses: maxim-lobanov/setup-cocoapods@v1
@@ -69,7 +69,10 @@ jobs:
key: ${{ runner.os }}-pods-${{ hashFiles('yarn.lock') }}
- name: 🔤 Compile translations
run: yarn intl:build
run: yarn intl:build 2>&1 | tee i18n.log
- name: Check for i18n compilation errors
run: if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compilation errors!\n\n"; fi
- name: ✏️ Write environment variables
run: |
@@ -79,8 +82,14 @@ jobs:
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "${{ secrets.GOOGLE_SERVICES_TOKEN }}" > google-services.json
- name: Setup Sentry vars for build-time injection
id: sentry
run: |
echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
- name: 🏗️ EAS Build
run: yarn use-build-number-with-bump eas build -p ios --profile ${{ inputs.profile || 'testflight' }} --local --output build.ipa --non-interactive
run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} yarn use-build-number-with-bump eas build -p ios --profile ${{ inputs.profile || 'testflight' }} --local --output build.ipa --non-interactive
- name: 🚀 Deploy
run: eas submit -p ios --non-interactive --path build.ipa
+14 -5
View File
@@ -75,8 +75,11 @@ jobs:
- name: Prettier check
run: yarn prettier --check .
- name: Check & compile i18n
run: yarn intl:build
- name: 🔤 Compile translations
run: yarn intl:build 2>&1 | tee i18n.log
- name: Check for i18n compilation errors
run: if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compilation errors!\n\n"; fi
- name: Type check
run: yarn typecheck
@@ -107,9 +110,15 @@ jobs:
echo "BITDRIFT_API_KEY=${{ secrets.BITDRIFT_API_KEY }}" >> .env
echo "$json" > google-services.json
- name: Setup Sentry vars for build-time injection
id: sentry
run: |
echo "SENTRY_DIST=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
echo "SENTRY_RELEASE=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
- name: 🏗️ Create Bundle
if: ${{ !steps.fingerprint.outputs.includes-changes }}
run: EXPO_PUBLIC_ENV="${{ inputs.channel || 'testflight' }}" yarn export
run: SENTRY_DIST=${{ steps.sentry.outputs.SENTRY_DIST }} SENTRY_RELEASE=${{ steps.sentry.outputs.SENTRY_RELEASE }} SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_DSN=${{ secrets.SENTRY_DSN }} EXPO_PUBLIC_ENV="${{ inputs.channel || 'testflight' }}" yarn export
- name: 📦 Package Bundle and 🚀 Deploy
if: ${{ !steps.fingerprint.outputs.includes-changes }}
@@ -134,7 +143,7 @@ jobs:
# GitHub actions are horrible so let's just copy paste this in
buildIfNecessaryIOS:
name: Build and Submit iOS
runs-on: macos-14
runs-on: macos-15
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}-build-ios
cancel-in-progress: true
@@ -176,7 +185,7 @@ jobs:
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '15.3'
xcode-version: '16.2'
- name: ☕️ Setup Cocoapods
uses: maxim-lobanov/setup-cocoapods@v1
@@ -36,3 +36,14 @@ jobs:
with:
commit_message: Nightly source-language update
file_pattern: ./src/locale/locales/en/messages.po
- name: Push source lang to Crowdin
uses: crowdin/github-action@v2
with:
upload_sources: true
upload_sources_args: "-b main"
upload_translations: false
push_translations: false
push_sources: false
create_pull_request: false
env:
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
+29 -2
View File
@@ -4,21 +4,47 @@ WORKDIR /usr/src/social-app
ENV DEBIAN_FRONTEND=noninteractive
#
# Node
#
ENV NODE_VERSION=20
ENV NVM_DIR=/usr/share/nvm
#
# Go
#
ENV GODEBUG="netdns=go"
ENV GOOS="linux"
ENV GOARCH="amd64"
ENV CGO_ENABLED=1
ENV GOEXPERIMENT="loopvar"
#
# Expo
#
ARG EXPO_PUBLIC_BUNDLE_IDENTIFIER
ENV EXPO_PUBLIC_BUNDLE_IDENTIFIER=${EXPO_PUBLIC_BUNDLE_IDENTIFIER:-dev}
# The latest git hash of the preview branch on render.com
ARG RENDER_GIT_COMMIT
#
# Sentry
#
ARG SENTRY_AUTH_TOKEN
ENV SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN:-unknown}
# Will fall back to package.json#version, but this is handled elsewhere
ARG SENTRY_RELEASE
ENV SENTRY_RELEASE=$SENTRY_RELEASE
ARG SENTRY_DIST
# Default to RENDER_GIT_COMMIT if not set by GitHub workflows
ENV SENTRY_DIST=${SENTRY_DIST:-$RENDER_GIT_COMMIT}
ARG SENTRY_DSN
ENV SENTRY_DSN=$SENTRY_DSN
#
# Copy everything into the container
#
COPY . .
#
@@ -38,8 +64,9 @@ RUN \. "$NVM_DIR/nvm.sh" && \
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env && \
npm install --global yarn && \
yarn && \
yarn intl:build && \
EXPO_PUBLIC_BUNDLE_IDENTIFIER=$EXPO_PUBLIC_BUNDLE_IDENTIFIER EXPO_PUBLIC_BUNDLE_DATE=$() yarn build-web
yarn intl:build 2>&1 | tee i18n.log && \
if grep -q "invalid syntax" "i18n.log"; then echo "\n\nFound compilation errors!\n\n" && exit 1; else echo "\n\nNo compile errors!\n\n"; fi && \
EXPO_PUBLIC_BUNDLE_IDENTIFIER=$EXPO_PUBLIC_BUNDLE_IDENTIFIER EXPO_PUBLIC_BUNDLE_DATE=$() SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN SENTRY_RELEASE=$SENTRY_RELEASE SENTRY_DIST=$SENTRY_DIST SENTRY_DSN=$SENTRY_DSN yarn build-web
# DEBUG
RUN find ./bskyweb/static && find ./web-build/static
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 20232025 Bluesky PBC
Copyright 20232025 Bluesky Social PBC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+2 -2
View File
@@ -37,6 +37,6 @@ deps: ## Installs dependent libs using 'yarn install'
.PHONY: nvm-setup
nvm-setup: ## Use NVM to install and activate node+yarn
nvm install 18
nvm use 18
nvm install 20
nvm use 20
npm install --global yarn
+1 -1
View File
@@ -42,7 +42,7 @@ The Bluesky Social application encompasses a set of schemas and APIs built in th
- Open an issue and give some time for discussion before submitting a PR.
- Stay away from PRs like...
- Changing "Post" to "Skeet."
- Refactoring the codebase, e.g., to replace MobX with Redux or something.
- Refactoring the codebase, e.g., to replace React Query with Redux Toolkit or something.
- Adding entirely new features without prior discussion.
Remember, we serve a wide community of users. Our day-to-day involves us constantly asking "which top priority is our top priority." If you submit well-written PRs that solve problems concisely, that's an awesome contribution. Otherwise, as much as we'd love to accept your ideas and contributions, we really don't have the bandwidth. That's what forking is for!
+1 -1
View File
@@ -1,2 +1,2 @@
flows:
- "flows/*"
- "flows/**"
-1
View File
@@ -18,7 +18,6 @@ appId: xyz.blueskyweb.app
- tapOn:
id: "openGalleryBtn"
- tapOn: "Content warnings"
- tapOn: "Content warnings"
- tapOn: "Porn"
- tapOn:
label: "Tap on confirm"
+3 -4
View File
@@ -24,12 +24,11 @@ appId: xyz.blueskyweb.app
- inputText: "example@test.com"
- tapOn:
id: "passwordInput"
- inputText: "hunter2"
- pressKey: Enter
- inputText: "hunter22"
- hideKeyboard
- tapOn:
id: "nextBtn"
- tapOn:
id: "handleInput"
- tapOn: "Not now"
- inputText: "e2e-test"
- tapOn:
id: "nextBtn"
+7 -21
View File
@@ -98,20 +98,13 @@ appId: xyz.blueskyweb.app
- tapOn: "People"
- tapOn: "Start adding people"
- assertVisible:
id: "listAddUserModal"
- tapOn:
id: "searchInput"
- tapOn: "Search"
- inputText: "b"
- pressKey: Enter
- tapOn:
id: "user-bob.test-addBtn"
- tapOn:
id: "doneBtn"
- assertNotVisible:
id: "listAddUserModal"
- assertVisible:
id: "user-bob.test"
- tapOn: "Add user to list"
- swipe:
direction: DOWN
- assertVisible: "View Bob's profile"
- tapOn: "Posts"
- assertVisible:
@@ -142,23 +135,16 @@ appId: xyz.blueskyweb.app
id: "e2eGotoLists"
- tapOn: "Good Ppl"
- tapOn: "People"
- assertVisible:
label: "Removes users on curatelists from the list"
id: "user-bob.test"
# - tapOn: "People"
- assertVisible: "View Bob's profile"
- tapOn:
point: "90%,43%"
- assertVisible:
id: "userAddRemoveListsModal"
- tapOn:
id: "user-bob.test-addBtn"
- tapOn:
id: "doneBtn"
- assertNotVisible:
id: "userAddRemoveListsModal"
- tapOn:
label: "Adds and removes users on curatelists from the profile"
id: "bottomBarSearchBtn"
- tapOn: "Search for posts, users, or feeds"
- inputText: "bob"
+1
View File
@@ -23,4 +23,5 @@ appId: xyz.blueskyweb.app
id: "loginPasswordInput"
- inputText: "hunter2"
- pressKey: Enter
- tapOn: "Not now"
- assertVisible: "Following"
+2 -1
View File
@@ -12,10 +12,11 @@ appId: xyz.blueskyweb.app
id: "e2eStartOnboarding"
- tapOn: "Select an avatar"
- waitForAnimationToEnd
- assertVisible: "Search your library…"
- tapOn:
point: "50%,22%"
- waitForAnimationToEnd
- tapOn: "Choose"
- tapOn: "Done"
- waitForAnimationToEnd
- tapOn: "Continue to next step"
- assertVisible: "What are your interests?"
+20
View File
@@ -0,0 +1,20 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&follows&posts"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "postDropdownBtn"
index: 0
- tapOn:
id: "postDropdownReportBtn"
- tapOn: "Create report for Misleading Post"
- tapOn: "Send report to Dev-env Moderation"
- tapOn:
point: "50%,90%"
+2 -2
View File
@@ -78,13 +78,13 @@ appId: xyz.blueskyweb.app
id: "changeBannerBtn"
- tapOn: "Upload from Library"
- waitForAnimationToEnd
- tapOn: "Choose"
- tapOn: "Done"
- waitForAnimationToEnd
- tapOn:
id: "changeAvatarBtn"
- tapOn: "Upload from Library"
- waitForAnimationToEnd
- tapOn: "Choose"
- tapOn: "Done"
- waitForAnimationToEnd
- tapOn:
id: "editProfileSaveBtn"
@@ -0,0 +1,24 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../../setupServer.js
env:
SERVER_PATH: ?users&follows&posts&feeds
- runFlow:
file: ../../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn: "Carla's avatar"
- tapOn:
id: "profileHeaderDropdownBtn"
- tapOn:
id: "profileHeaderDropdownReportBtn"
- tapOn:
id: "report:option:com.atproto.moderation.defs#reasonSpam"
- assertVisible:
id: "report:labeler:mod-authority.test"
- tapOn:
id: "report:submit"
- assertNotVisible:
id: "report:dialog"
@@ -0,0 +1,24 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../../setupServer.js
env:
SERVER_PATH: ?users&follows&posts&feeds
- runFlow:
file: ../../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "postDropdownBtn"
index: 0
- tapOn:
id: "postDropdownReportBtn"
- tapOn:
id: "report:option:com.atproto.moderation.defs#reasonSpam"
- assertVisible:
id: "report:labeler:mod-authority.test"
- tapOn:
id: "report:submit"
- assertNotVisible:
id: "report:dialog"
@@ -0,0 +1,35 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../../setupServer.js
env:
SERVER_PATH: ?users&follows&posts&feeds
- runFlow:
file: ../../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "postDropdownBtn"
index: 0
- tapOn:
id: "postDropdownReportBtn"
- tapOn:
id: "report:option:com.atproto.moderation.defs#reasonOther"
- assertVisible:
id: "report:labeler:mod-authority.test"
# reason "other" defaults with details open
- assertVisible:
id: "report:details"
- tapOn:
id: "report:clearOption"
- assertNotVisible:
id: "report:details"
- tapOn:
id: "report:option:com.atproto.moderation.defs#reasonSpam"
- assertVisible:
id: "report:labeler:mod-authority.test"
- tapOn:
id: "report:submit"
- assertNotVisible:
id: "report:dialog"
@@ -0,0 +1,30 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../../setupServer.js
env:
SERVER_PATH: ?users&follows&posts&feeds
- runFlow:
file: ../../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "postDropdownBtn"
index: 0
- tapOn:
id: "postDropdownReportBtn"
- tapOn:
id: "report:option:com.atproto.moderation.defs#reasonOther"
- assertVisible:
id: "report:labeler:mod-authority.test"
# reason "other" defaults with details open
- assertVisible:
id: "report:details"
- tapOn:
id: "report:details"
- inputText: "This is a test report"
- tapOn:
id: "report:submit"
- assertNotVisible:
id: "report:dialog"
+3
View File
@@ -0,0 +1,3 @@
export const CID = jest.fn().mockImplementation(() => {
return {}
})
+7
View File
@@ -0,0 +1,7 @@
export const from = jest.fn().mockImplementation(() => {
return {
digest: jest.fn().mockImplementation(() => {
return Promise.resolve('')
}),
}
})
-9
View File
@@ -1,9 +0,0 @@
export const openPicker = jest
.fn()
.mockImplementation(() => Promise.resolve({uri: ''}))
export const openCamera = jest
.fn()
.mockImplementation(() => Promise.resolve({uri: ''}))
export const openCropper = jest
.fn()
.mockImplementation(() => Promise.resolve({uri: ''}))
+2 -2
View File
@@ -1,11 +1,11 @@
import {RichText} from '@atproto/api'
import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player'
import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player'
import {
createStarterPackGooglePlayUri,
createStarterPackLinkFromAndroidReferrer,
parseStarterPackUri,
} from 'lib/strings/starter-pack'
} from '#/lib/strings/starter-pack'
import {cleanError} from '../../src/lib/strings/errors'
import {createFullHandle, makeValidHandle} from '../../src/lib/strings/handles'
import {enforceLen} from '../../src/lib/strings/helpers'
+15 -39
View File
@@ -1,8 +1,6 @@
const pkg = require('./package.json')
const DARK_SPLASH_ANDROID_BACKGROUND = '#0f141b'
module.exports = function (config) {
module.exports = function (_config) {
/**
* App version number. Should be incremented as part of a release cycle.
*/
@@ -36,9 +34,6 @@ module.exports = function (config) {
const UPDATES_ENABLED = !!UPDATES_CHANNEL
const USE_SENTRY = Boolean(process.env.SENTRY_AUTH_TOKEN)
const SENTRY_DIST = `${PLATFORM}.${VERSION}.${IS_TESTFLIGHT ? 'tf' : ''}${
IS_DEV ? 'dev' : ''
}`
return {
expo: {
@@ -75,14 +70,18 @@ module.exports = function (config) {
'an',
'ast',
'ca',
'cy',
'da',
'de',
'el',
'eo',
'es',
'eu',
'fi',
'fr',
'fy',
'ga',
'gd',
'gl',
'hi',
'hu',
@@ -96,6 +95,7 @@ module.exports = function (config) {
'nl',
'pl',
'pt-BR',
'pt-PT',
'ro',
'ru',
'sv',
@@ -140,12 +140,10 @@ module.exports = function (config) {
},
androidStatusBar: {
barStyle: 'light-content',
backgroundColor: '#00000000',
},
// Dark nav bar in light mode is better than light nav bar in dark mode
androidNavigationBar: {
barStyle: 'light-content',
backgroundColor: DARK_SPLASH_ANDROID_BACKGROUND,
},
android: {
icon: './assets/app-icons/android_icon_default_light.png',
@@ -197,13 +195,17 @@ module.exports = function (config) {
plugins: [
'expo-video',
'expo-localization',
'expo-web-browser',
[
'react-native-edge-to-edge',
{android: {enforceNavigationBarContrast: false}},
],
USE_SENTRY && [
'@sentry/react-native/expo',
{
organization: 'blueskyweb',
project: 'react-native',
release: VERSION,
dist: SENTRY_DIST,
project: 'app',
url: 'https://sentry.io',
},
],
[
@@ -237,14 +239,14 @@ module.exports = function (config) {
},
],
'./plugins/starterPackAppClipExtension/withStarterPackAppClip.js',
'./plugins/withGradleJVMHeapSizeIncrease.js',
'./plugins/withAndroidManifestPlugin.js',
'./plugins/withAndroidManifestFCMIconPlugin.js',
'./plugins/withAndroidStylesAccentColorPlugin.js',
'./plugins/withAndroidSplashScreenStatusBarTranslucentPlugin.js',
'./plugins/withAndroidDayNightThemePlugin.js',
'./plugins/withAndroidNoJitpackPlugin.js',
'./plugins/shareExtension/withShareExtensions.js',
'./plugins/notificationsExtension/withNotificationsExtension.js',
'./plugins/withAppDelegateReferrer.js',
[
'expo-font',
{
@@ -356,16 +358,6 @@ module.exports = function (config) {
},
],
['expo-screen-orientation', {initialOrientation: 'PORTRAIT_UP'}],
[
'react-native-vision-camera',
{
enableLocation: false,
cameraPermissionText: 'Bluesky needs access to your camera.',
enableMicrophonePermission: true,
microphonePermissionText:
'Bluesky needs access to your microphone.',
},
],
].filter(Boolean),
extra: {
eas: {
@@ -402,22 +394,6 @@ module.exports = function (config) {
projectId: '55bd077a-d905-4184-9c7f-94789ba0f302',
},
},
hooks: {
postPublish: [
/*
* @see https://docs.expo.dev/guides/using-sentry/#app-configuration
*/
{
file: './postHooks/uploadSentrySourcemapsPostHook',
config: {
organization: 'blueskyweb',
project: 'react-native',
release: VERSION,
dist: SENTRY_DIST,
},
},
],
},
},
}
}
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M20 13.75a1 1 0 0 1 1 1V18a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3v-3.25a1 1 0 1 1 2 0V18a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-3.25a1 1 0 0 1 1-1ZM12 3a1 1 0 0 1 .707.293l4.5 4.5a1 1 0 1 1-1.414 1.414L13 6.414v8.836a1 1 0 1 1-2 0V6.414L8.207 9.207a1 1 0 1 1-1.414-1.414l4.5-4.5A1 1 0 0 1 12 3Z"/></svg>

After

Width:  |  Height:  |  Size: 381 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M11.839 4.744c0-1.488 1.724-2.277 2.846-1.364l.107.094 7.66 7.256.128.134c.558.652.558 1.62 0 2.272l-.128.135-7.66 7.255c-1.115 1.057-2.953.267-2.953-1.27v-2.748c-3.503.055-5.417.41-6.592.97-.997.474-1.525 1.122-2.084 2.14l-.243.46c-.558 1.088-2.09.583-2.08-.515l.015-.748c.111-3.68.777-6.5 2.546-8.415 1.83-1.98 4.63-2.771 8.438-2.884V4.744Zm2 3.256c0 .79-.604 1.41-1.341 1.494l-.149.01c-3.9.057-6.147.813-7.48 2.254-.963 1.043-1.562 2.566-1.842 4.79.38-.327.826-.622 1.361-.877 1.656-.788 4.08-1.14 7.938-1.169l.153.007A1.5 1.5 0 0 1 13.839 16v2.675L20.884 12l-7.045-6.676V8Z"/></svg>

After

Width:  |  Height:  |  Size: 680 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M11 20V6.164l-4.293 4.293a1 1 0 1 1-1.414-1.414l5.293-5.293.151-.138a2 2 0 0 1 2.677.138l5.293 5.293.068.076a1 1 0 0 1-1.406 1.406l-.076-.068L13 6.164V20a1 1 0 0 1-2 0Z"/></svg>

After

Width:  |  Height:  |  Size: 271 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M20.494 2.13a1 1 0 0 1 .375 1.364l-4.658 8.2.263.095c1.52.554 2.737 2.062 2.484 3.864-.336 2.393-1.358 4.12-3.245 6.047a1 1 0 0 1-1.102.222l-9.5-4a1 1 0 0 1-.166-1.754c1.458-.971 2.623-1.923 3.498-3.3 1.057-1.662 3.154-2.854 5.281-2.08l.58.212 4.827-8.494a1 1 0 0 1 1.363-.375ZM13.04 12.669c-.983-.358-2.19.142-2.91 1.273-.737 1.16-1.628 2.054-2.601 2.828l1.708.72a.2.2 0 0 0 .177-.011l2.13-1.218a.2.2 0 0 1 .29.237l-.551 1.653a.2.2 0 0 0 .112.247l3.353 1.413c1.359-1.494 1.994-2.76 2.23-4.435.094-.675-.359-1.405-1.188-1.707l-2.75-1ZM4.407 7.184a.5.5 0 0 1-.224.224l-1.29.645a.5.5 0 0 0 0 .894l1.29.645a.5.5 0 0 1 .224.224l.645 1.29a.5.5 0 0 0 .894 0l.645-1.29a.5.5 0 0 1 .224-.224l1.29-.645a.5.5 0 0 0 0-.894l-1.29-.645a.5.5 0 0 1-.224-.224l-.645-1.29a.5.5 0 0 0-.894 0l-.645 1.29ZM9.559 3.72a.36.36 0 0 0 .16-.16l.46-.921a.357.357 0 0 1 .64 0l.46.921q.054.106.16.16l.921.46a.357.357 0 0 1 0 .64l-.921.46a.36.36 0 0 0-.16.16l-.46.921a.357.357 0 0 1-.64 0l-.46-.921a.36.36 0 0 0-.16-.16l-.921-.46a.357.357 0 0 1 0-.64l.921-.46Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M18.535 5.465a5.003 5.003 0 0 0-7.076 0l-.005.005-.752.742a1 1 0 1 1-1.404-1.424l.749-.74a7.003 7.003 0 0 1 9.904 9.905l-.002.003-.737.746a1 1 0 1 1-1.424-1.404l.747-.757a5.003 5.003 0 0 0 0-7.076ZM6.202 9.288a1 1 0 0 1 .01 1.414l-.747.757a5.003 5.003 0 1 0 7.076 7.076l.005-.005.752-.742a1 1 0 1 1 1.404 1.424l-.746.737-.003.002a7.003 7.003 0 0 1-9.904-9.904l.74-.75a1 1 0 0 1 1.413-.009Zm8.505.005a1 1 0 0 1 0 1.414l-4 4a1 1 0 0 1-1.414-1.414l4-4a1 1 0 0 1 1.414 0Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 610 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16ZM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12Zm13.633-3.274a1 1 0 0 1 .141 1.407l-4.5 5.5a1 1 0 0 1-1.481.074l-2-2a1 1 0 1 1 1.414-1.414l1.219 1.219 3.8-4.645a1 1 0 0 1 1.407-.141Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 384 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16ZM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12Zm6.293-3.707a1 1 0 0 1 1.414 0L12 10.586l2.293-2.293a1 1 0 1 1 1.414 1.414L13.414 12l2.293 2.293a1 1 0 0 1-1.414 1.414L12 13.414l-2.293 2.293a1 1 0 0 1-1.414-1.414L10.586 12 8.293 9.707a1 1 0 0 1 0-1.414Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 454 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M11.158 2.879c.584-.835 1.757-1.137 2.673-.507.951.654 2.597 1.92 4.013 3.694S20.5 10.194 20.5 13c0 4.997-3.752 9-8.5 9s-8.5-4.003-8.5-9c0-2.035.874-4.636 2.578-6.712.746-.91 2.034-.855 2.786-.133l2.294-3.276Zm-3.04 15.758C6.538 17.386 5.5 15.37 5.5 13c0-1.511.666-3.616 2.042-5.342.87.797 2.254.653 2.939-.325l2.286-3.265c.871.606 2.299 1.723 3.514 3.246C17.53 8.879 18.5 10.804 18.5 13c0 2.369-1.038 4.386-2.618 5.637q.117-.518.118-1.061c0-2.601-2.038-4.382-2.911-5.04a1.8 1.8 0 0 0-2.177 0C10.038 13.195 8 14.976 8 17.577q0 .543.118 1.061ZM12 14.222c-.825.648-2 1.859-2 3.354C10 19.043 11.016 20 12 20s2-.957 2-2.424c0-1.495-1.175-2.706-2-3.354Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 791 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M2 12a9.97 9.97 0 0 1 2.929-7.07l.076-.068a1 1 0 0 1 1.407 1.406l-.07.076A7.97 7.97 0 0 0 4 12a7.97 7.97 0 0 0 2.078 5.38l.265.277.07.076a1 1 0 0 1-1.408 1.407l-.076-.07-.331-.346A9.97 9.97 0 0 1 2 12Zm18 0a7.97 7.97 0 0 0-2.078-5.379l-.265-.278-.07-.076a1 1 0 0 1 1.408-1.406l.076.068.331.347A9.97 9.97 0 0 1 22 12a9.97 9.97 0 0 1-2.929 7.07 1 1 0 1 1-1.414-1.413A7.97 7.97 0 0 0 20 12ZM6 12c0-1.656.673-3.158 1.758-4.243a1 1 0 0 1 1.414 1.414A4 4 0 0 0 8 12.001a3.98 3.98 0 0 0 1.04 2.689l.132.138.068.077a1 1 0 0 1-1.407 1.406l-.075-.069-.2-.208A5.98 5.98 0 0 1 6 12Zm10 0a3.98 3.98 0 0 0-1.04-2.69l-.132-.139-.068-.075a1 1 0 0 1 1.407-1.407l.075.068.2.208A5.98 5.98 0 0 1 18 12a6 6 0 0 1-1.758 4.243 1 1 0 0 1-1.414-1.415A4 4 0 0 0 16 12Zm-6 0a2 2 0 1 1 4 0 2 2 0 0 1-4 0Z"/></svg>

After

Width:  |  Height:  |  Size: 879 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M12.325 2.054a1 1 0 0 0-.65 0l-8 2.75A1 1 0 0 0 3 5.75v6.162c0 2.807 1.149 4.83 2.813 6.405 1.572 1.488 3.632 2.6 5.555 3.636l.157.085a1 1 0 0 0 .95 0l.157-.085c1.923-1.037 3.983-2.148 5.556-3.636C19.85 16.742 21 14.719 21 11.912V5.75a1 1 0 0 0-.675-.946l-8-2.75ZM5 11.912V6.464l7-2.407 7 2.407v5.448c0 2.166-.851 3.687-2.188 4.952-1.276 1.209-2.964 2.158-4.812 3.157-1.848-1-3.536-1.948-4.813-3.157C5.851 15.6 5 14.078 5 11.912Zm10.207-1.205a1 1 0 0 0-1.414-1.414L11 12.086l-.793-.793a1 1 0 0 0-1.414 1.414l1.5 1.5a1 1 0 0 0 1.414 0l3.5-3.5Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 685 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M12 2a1 1 0 0 1 1 1c0 3.188.669 5.256 1.882 6.536C16.084 10.805 18.01 11.5 21 11.5a1 1 0 1 1 0 2c-2.99 0-4.916.695-6.118 1.964C13.67 16.744 13 18.812 13 22a1 1 0 1 1-2 0c0-3.188-.669-5.256-1.882-6.536C7.916 14.195 5.99 13.5 3 13.5a1 1 0 1 1 0-2c2.99 0 4.916-.695 6.118-1.964C10.33 8.256 11 6.188 11 3a1 1 0 0 1 1-1Zm0 6.734a7.6 7.6 0 0 1-1.43 2.178A7.3 7.3 0 0 1 8.349 12.5a7.3 7.3 0 0 1 2.22 1.588A7.6 7.6 0 0 1 12 16.267a7.6 7.6 0 0 1 1.43-2.179 7.3 7.3 0 0 1 2.221-1.588 7.3 7.3 0 0 1-2.22-1.588A7.6 7.6 0 0 1 12 8.734Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 665 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M15 7a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0V9.414L14.414 15a2 2 0 0 1-2.828 0L9 12.414l-5.293 5.293a1 1 0 0 1-1.414-1.414L7.586 11a2 2 0 0 1 2.828 0L13 13.586 18.586 8H16a1 1 0 0 1-1-1Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 336 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle cx="12" cy="12" r="11.5" fill="#1183FE"/><path fill="#fff" fill-rule="evenodd" d="M17.659 8.175a1.36 1.36 0 0 1 0 1.925l-6.224 6.223a1.36 1.36 0 0 1-1.925 0L6.4 13.212a1.361 1.361 0 0 1 1.925-1.925l2.149 2.148 5.26-5.26a1.36 1.36 0 0 1 1.925 0Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 354 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#1185FE" d="M8.792 1.615a4.154 4.154 0 0 1 6.416 0 4.15 4.15 0 0 0 3.146 1.515 4.154 4.154 0 0 1 4 5.017 4.15 4.15 0 0 0 .777 3.404 4.154 4.154 0 0 1-1.427 6.255 4.15 4.15 0 0 0-2.177 2.73 4.154 4.154 0 0 1-5.781 2.784 4.15 4.15 0 0 0-3.492 0 4.154 4.154 0 0 1-5.78-2.784 4.15 4.15 0 0 0-2.178-2.73A4.154 4.154 0 0 1 .87 11.551a4.15 4.15 0 0 0 .776-3.404 4.154 4.154 0 0 1 4-5.017 4.15 4.15 0 0 0 3.146-1.515Z"/><path fill="#fff" fill-rule="evenodd" d="M17.861 8.26a1.44 1.44 0 0 1 0 2.033l-6.571 6.571a1.437 1.437 0 0 1-2.033 0L5.97 13.58a1.438 1.438 0 0 1 2.033-2.033l2.27 2.269 5.554-5.555a1.437 1.437 0 0 1 2.033 0Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

+1 -5
View File
@@ -17,7 +17,7 @@ module.exports = function (api) {
],
plugins: [
'macros',
['babel-plugin-react-compiler', {target: '18'}],
['babel-plugin-react-compiler', {target: '19'}],
[
'module:react-native-dotenv',
{
@@ -37,10 +37,6 @@ module.exports = function (api) {
alias: {
// This needs to be mirrored in tsconfig.json
'#': './src',
lib: './src/lib',
platform: './src/platform',
state: './src/state',
view: './src/view',
crypto: './src/platform/crypto.ts',
},
},
-21
View File
@@ -1,21 +0,0 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "simple-import-sort"],
"extends": [
"eslint:recommended",
"preact",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking"
],
"rules": {
"simple-import-sort/imports": "warn",
"simple-import-sort/exports": "warn",
'no-else-return': 'off'
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": "latest",
"project": "./bskyembed/tsconfig.json"
}
}
+22
View File
@@ -0,0 +1,22 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'simple-import-sort'],
extends: [
'eslint:recommended',
'preact',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
rules: {
'simple-import-sort/imports': 'warn',
'simple-import-sort/exports': 'warn',
'no-else-return': 'off',
},
parserOptions: {
sourceType: 'module',
ecmaVersion: 'latest',
project: ['./tsconfig.json'],
tsconfigRootDir: __dirname,
},
}
+3
View File
@@ -68,6 +68,9 @@ function scan(node = document) {
if (ref_url.startsWith('http')) {
searchParams.set('ref_url', encodeURIComponent(ref_url))
}
if (embed.dataset.blueskyEmbedColorMode) {
searchParams.set('colorMode', embed.dataset.blueskyEmbedColorMode)
}
const iframe = document.createElement('iframe')
iframe.setAttribute('data-bluesky-id', id)
+7 -1
View File
@@ -1,9 +1,15 @@
export type ColorModeValues = 'system' | 'light' | 'dark'
export function assertColorModeValues(value: string): value is ColorModeValues {
return ['system', 'light', 'dark'].includes(value)
}
export function applyTheme(theme: 'light' | 'dark') {
document.documentElement.classList.remove('light', 'dark')
document.documentElement.classList.add(theme)
}
export function initColorMode() {
export function initSystemColorMode() {
applyTheme(
window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
+20 -18
View File
@@ -78,7 +78,7 @@ export function Embed({
return (
<Link
href={`/profile/${record.author.did}/post/${getRkey(record)}`}
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">
className="transition-colors hover:bg-neutral-100 dark:hover:bg-slate-700 border dark:border-slate-600 rounded-xl 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 dark:bg-slate-700 shrink-0">
<img
@@ -207,7 +207,7 @@ export function Embed({
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">
<div className="w-full rounded-xl 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 dark:text-textDimmed">{children}</p>
</div>
@@ -231,12 +231,12 @@ function ImageEmbed({
<img
src={content.images[0].thumb}
alt={content.images[0].alt}
className="w-full rounded-lg overflow-hidden object-cover h-auto max-h-[1000px]"
className="w-full rounded-xl overflow-hidden object-cover h-auto max-h-[1000px]"
/>
)
case 2:
return (
<div className="flex gap-1 rounded-lg overflow-hidden w-full aspect-[2/1]">
<div className="flex gap-1 rounded-xl overflow-hidden w-full aspect-[2/1]">
{content.images.map((image, i) => (
<img
key={i}
@@ -249,19 +249,21 @@ function ImageEmbed({
)
case 3:
return (
<div className="flex gap-1 rounded-lg overflow-hidden w-full aspect-[2/1]">
<img
src={content.images[0].thumb}
alt={content.images[0].alt}
className="flex-[3] object-cover rounded-sm"
/>
<div className="flex flex-col gap-1 flex-[2]">
<div className="flex gap-1 rounded-xl overflow-hidden w-full aspect-[2/1]">
<div className="flex-1 aspect-square">
<img
src={content.images[0].thumb}
alt={content.images[0].alt}
className="w-full h-full object-cover rounded-sm"
/>
</div>
<div className="flex flex-col gap-1 flex-1">
{content.images.slice(1).map((image, i) => (
<img
key={i}
src={image.thumb}
alt={image.alt}
className="w-full h-full object-cover rounded-sm"
className="flex-1 object-cover rounded-sm min-h-0"
/>
))}
</div>
@@ -269,13 +271,13 @@ function ImageEmbed({
)
case 4:
return (
<div className="grid grid-cols-2 gap-1 rounded-lg overflow-hidden">
<div className="grid grid-cols-2 gap-1 rounded-xl overflow-hidden">
{content.images.map((image, i) => (
<img
key={i}
src={image.thumb}
alt={image.alt}
className="aspect-square w-full object-cover rounded-sm"
className="aspect-[3/2] w-full object-cover rounded-sm"
/>
))}
</div>
@@ -308,7 +310,7 @@ function ExternalEmbed({
return (
<Link
href={content.external.uri}
className="w-full rounded-lg overflow-hidden border dark:border-slate-600 flex flex-col items-stretch"
className="w-full rounded-xl overflow-hidden border dark:border-slate-600 flex flex-col items-stretch"
disableTracking>
{content.external.thumb && (
<img
@@ -345,7 +347,7 @@ function GenericWithImageEmbed({
return (
<Link
href={href}
className="w-full rounded-lg border dark:border-slate-600 py-2 px-3 flex flex-col gap-2">
className="w-full rounded-xl border dark:border-slate-600 py-2 px-3 flex flex-col gap-2">
<div className="flex gap-2.5 items-center">
{image ? (
<img
@@ -383,7 +385,7 @@ function VideoEmbed({content}: {content: AppBskyEmbedVideo.View}) {
return (
<div
className="w-full overflow-hidden rounded-lg aspect-square relative"
className="w-full overflow-hidden rounded-xl aspect-square relative"
style={{aspectRatio: `${aspectRatio} / 1`}}>
<img
src={content.thumbnail}
@@ -412,7 +414,7 @@ function StarterPackEmbed({
return (
<Link
href={starterPackHref}
className="w-full rounded-lg overflow-hidden border dark:border-slate-600 flex flex-col items-stretch">
className="w-full rounded-xl 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">
+1 -1
View File
@@ -173,7 +173,7 @@ function PostContent({record}: {record: AppBskyFeedPost.Record | null}) {
}
return (
<p className="min-[300px]:text-lg leading-6 break-word break-words whitespace-pre-wrap">
<p className="min-[300px]:text-lg leading-6 min-[300px]:leading-6 break-word break-words whitespace-pre-wrap">
{richText}
</p>
)
+12 -1
View File
@@ -6,6 +6,17 @@
word-break: break-word;
}
:root {
#app {
color-scheme: light dark;
}
select {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='14px' width='14px' fill='none' viewBox='0 0 24 24'><path fill='black' fill-rule='evenodd' d='M3.293 8.293a1 1 0 0 1 1.414 0L12 15.586l7.293-7.293a1 1 0 1 1 1.414 1.414l-8 8a1 1 0 0 1-1.414 0l-8-8a1 1 0 0 1 0-1.414Z' clip-rule='evenodd'/></svg>");
background-repeat: no-repeat;
background-position: calc(100% - 0.75rem) center;
padding-right: 2rem;
@media (prefers-color-scheme: dark) {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='14px' width='14px' fill='none' viewBox='0 0 24 24'><path fill='white' fill-rule='evenodd' d='M3.293 8.293a1 1 0 0 1 1.414 0L12 15.586l7.293-7.293a1 1 0 1 1 1.414 1.414l-8 8a1 1 0 0 1-1.414 0l-8-8a1 1 0 0 1 0-1.414Z' clip-rule='evenodd'/></svg>");
}
}
+1
View File
@@ -13,6 +13,7 @@ export function labelsToInfo(
return 'Adult Content'
case 'nudity':
return 'Non-sexual Nudity'
case 'gore':
case 'graphic-media':
return 'Graphic Media'
default:
+58 -19
View File
@@ -1,12 +1,16 @@
import '../index.css'
import {AppBskyFeedDefs, AppBskyFeedPost, AtUri, BskyAgent} from '@atproto/api'
import {AppBskyFeedDefs, AppBskyFeedPost, AtpAgent, AtUri} from '@atproto/api'
import {h, render} from 'preact'
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 {
assertColorModeValues,
ColorModeValues,
initSystemColorMode,
} from '../color-mode'
import {Container} from '../components/container'
import {Link} from '../components/link'
import {Post} from '../components/post'
@@ -22,9 +26,9 @@ export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js`
const root = document.getElementById('app')
if (!root) throw new Error('No root element')
initColorMode()
initSystemColorMode()
const agent = new BskyAgent({
const agent = new AtpAgent({
service: 'https://public.api.bsky.app',
})
@@ -32,6 +36,7 @@ render(<LandingPage />, root)
function LandingPage() {
const [uri, setUri] = useState('')
const [colorMode, setColorMode] = useState<ColorModeValues>('system')
const [error, setError] = useState<string | null>(null)
const [loading, setLoading] = useState(false)
const [thread, setThread] = useState<AppBskyFeedDefs.ThreadViewPost | null>(
@@ -120,24 +125,50 @@ function LandingPage() {
<h1 className="text-4xl font-bold text-center">Embed a Bluesky Post</h1>
<input
type="text"
value={uri}
onInput={e => setUri(e.currentTarget.value)}
className="border rounded-lg py-3 w-full max-w-[600px] px-4 dark:bg-dimmedBg dark:border-slate-500"
placeholder={DEFAULT_POST}
/>
<div className="flex flex-col w-full max-w-[600px] gap-6">
<input
type="text"
value={uri}
onInput={e => setUri(e.currentTarget.value)}
className="border rounded-lg py-3 px-4 dark:bg-dimmedBg dark:border-slate-500"
placeholder={DEFAULT_POST}
/>
<div className="flex flex-col gap-1.5">
<label className="text-sm font-medium" for="colorModeSelect">
Theme
</label>
<select
value={colorMode}
onChange={e => {
const value = e.currentTarget.value
if (assertColorModeValues(value)) {
setColorMode(value)
}
}}
id="colorModeSelect"
className="appearance-none bg-white border w-full rounded-lg text-sm px-3 py-2 dark:bg-dimmedBg dark:border-slate-500">
<option value="system">System</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</div>
</div>
<img src={arrowBottom} className="w-6 dark:invert" />
{loading ? (
<div className="w-full max-w-[600px]">
<div className={`${colorMode} 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 && thread && uri && (
<Snippet thread={thread} colorMode={colorMode} />
)}
<div className={colorMode}>
{!error && thread && <Post thread={thread} key={thread.post.uri} />}
</div>
{error && (
<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>
@@ -168,7 +199,13 @@ function Skeleton() {
)
}
function Snippet({thread}: {thread: AppBskyFeedDefs.ThreadViewPost}) {
function Snippet({
thread,
colorMode,
}: {
thread: AppBskyFeedDefs.ThreadViewPost
colorMode: ColorModeValues
}) {
const ref = useRef<HTMLInputElement>(null)
const [copied, setCopied] = useState(false)
@@ -204,9 +241,11 @@ function Snippet({thread}: {thread: AppBskyFeedDefs.ThreadViewPost}) {
// x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x
return `<blockquote class="bluesky-embed" data-bluesky-uri="${escapeHtml(
thread.post.uri,
)}" data-bluesky-cid="${escapeHtml(thread.post.cid)}"><p lang="${escapeHtml(
lang,
)}">${escapeHtml(record.text)}${
)}" data-bluesky-cid="${escapeHtml(
thread.post.cid,
)}" data-bluesky-embed-color-mode="${escapeHtml(
colorMode,
)}"><p lang="${escapeHtml(lang)}">${escapeHtml(record.text)}${
record.embed
? `<br><br><a href="${escapeHtml(href)}">[image or embed]</a>`
: ''
@@ -217,7 +256,7 @@ function Snippet({thread}: {thread: AppBskyFeedDefs.ThreadViewPost}) {
)}</a>) <a href="${escapeHtml(href)}">${escapeHtml(
niceDate(thread.post.indexedAt),
)}</a></blockquote><script async src="${EMBED_SCRIPT}" charset="utf-8"></script>`
}, [thread])
}, [thread, colorMode])
return (
<div className="flex gap-2 w-full">
+18 -2
View File
@@ -4,7 +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 {applyTheme, initSystemColorMode} from '../color-mode'
import {Container} from '../components/container'
import {Link} from '../components/link'
import {Post} from '../components/post'
@@ -22,7 +22,23 @@ if (!uri) {
throw new Error('No uri in path')
}
initColorMode()
const query = new URLSearchParams(window.location.search)
// theme - default to light mode
const colorMode = query.get('colorMode')
switch (colorMode) {
case 'dark':
applyTheme('dark')
break
case 'system':
initSystemColorMode()
break
case 'light':
default:
applyTheme('light')
break
}
agent
.getPostThread({
+2
View File
@@ -9,8 +9,10 @@
},
"dependencies": {
"@atproto/common": "^0.4.0",
"@types/escape-html": "^1.0.4",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"escape-html": "^1.0.3",
"express": "^4.19.2",
"http-terminator": "^3.2.0",
"kysely": "^0.27.3",
+7 -3
View File
@@ -1,9 +1,11 @@
import {Express} from 'express'
import {AppContext} from '../context.js'
import {default as create} from './create.js'
import {default as createShortLink} from './createShortLink.js'
import {default as health} from './health.js'
import {default as redirect} from './redirect.js'
import {default as root} from './root.js'
import {default as shortLink} from './shortLink.js'
import {default as siteAssociation} from './siteAssociation.js'
export * from './util.js'
@@ -11,7 +13,9 @@ export * from './util.js'
export default function (ctx: AppContext, app: Express) {
app = health(ctx, app) // GET /_health
app = siteAssociation(ctx, app) // GET /.well-known/apple-app-site-association
app = create(ctx, app) // POST /link
app = redirect(ctx, app) // GET /:linkId (should go last due to permissive matching)
app = redirect(ctx, app) // GET /redirect
app = createShortLink(ctx, app) // POST /link
app = root(ctx, app) // GET / (redirect to bsky.app on root)
app = shortLink(ctx, app) // GET /:linkId (should go last due to permissive matching)
return app
}
+31 -33
View File
@@ -1,54 +1,52 @@
import assert from 'node:assert'
import {DAY, SECOND} from '@atproto/common'
import escapeHTML from 'escape-html'
import {Express} from 'express'
import {AppContext} from '../context.js'
import {handler} from './util.js'
const INTERNAL_IP_REGEX = new RegExp(
'(^127.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$)|(^10.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$)|(^172.1[6-9]{1}[0-9]{0,1}.[0-9]{1,3}.[0-9]{1,3}$)|(^172.2[0-9]{1}[0-9]{0,1}.[0-9]{1,3}.[0-9]{1,3}$)|(^172.3[0-1]{1}[0-9]{0,1}.[0-9]{1,3}.[0-9]{1,3}$)|(^192.168.[0-9]{1,3}.[0-9]{1,3}$)|^localhost',
'i',
)
export default function (ctx: AppContext, app: Express) {
return app.get(
'/:linkId',
'/redirect',
handler(async (req, res) => {
const linkId = req.params.linkId
const contentType = req.accepts(['html', 'json'])
let link = req.query.u
assert(
typeof linkId === 'string',
'express guarantees id parameter is a string',
typeof link === 'string',
'express guarantees link query parameter is a string',
)
const found = await ctx.db.db
.selectFrom('link')
.selectAll()
.where('id', '=', linkId)
.executeTakeFirst()
if (!found) {
// potentially broken or mistyped link
let url: URL | undefined
try {
url = new URL(link)
} catch {}
if (
!url ||
(url.protocol !== 'http:' && url.protocol !== 'https:') || // is a http(s) url
(ctx.cfg.service.hostnames.includes(url.hostname.toLowerCase()) &&
url.pathname === '/redirect') || // is a redirect loop
INTERNAL_IP_REGEX.test(url.hostname) // isn't directing to an internal location
) {
res.setHeader('Cache-Control', 'no-store')
if (contentType === 'json') {
return res
.status(404)
.json({
error: 'NotFound',
message: 'Link not found',
})
.end()
}
// send the user to the app
res.setHeader('Location', `https://${ctx.cfg.service.appHostname}`)
return res.status(302).end()
}
// build url from original url in order to preserve query params
const url = new URL(
req.originalUrl,
`https://${ctx.cfg.service.appHostname}`,
)
url.pathname = found.path
res.setHeader('Cache-Control', `max-age=${(7 * DAY) / SECOND}`)
if (contentType === 'json') {
return res.json({url: url.href}).end()
}
res.setHeader('Location', url.href)
return res.status(301).end()
res.type('html')
res.status(200)
const escaped = escapeHTML(url.href)
return res.send(
`<html><head><meta http-equiv="refresh" content="0; URL='${escaped}'" /><style>:root { color-scheme: light dark; }</style></head></html>`,
)
}),
)
}
+14
View File
@@ -0,0 +1,14 @@
import {Express} from 'express'
import {AppContext} from '../context.js'
import {handler} from './util.js'
export default function (ctx: AppContext, app: Express) {
return app.get(
'/',
handler(async (_req, res) => {
res.setHeader('Location', `https://${ctx.cfg.service.appHostname}`)
return res.status(301).end()
}),
)
}
+54
View File
@@ -0,0 +1,54 @@
import assert from 'node:assert'
import {DAY, SECOND} from '@atproto/common'
import {Express} from 'express'
import {AppContext} from '../context.js'
import {handler} from './util.js'
export default function (ctx: AppContext, app: Express) {
return app.get(
'/:linkId',
handler(async (req, res) => {
const linkId = req.params.linkId
const contentType = req.accepts(['html', 'json'])
assert(
typeof linkId === 'string',
'express guarantees id parameter is a string',
)
const found = await ctx.db.db
.selectFrom('link')
.selectAll()
.where('id', '=', linkId)
.executeTakeFirst()
if (!found) {
// potentially broken or mistyped link
res.setHeader('Cache-Control', 'no-store')
if (contentType === 'json') {
return res
.status(404)
.json({
error: 'NotFound',
message: 'Link not found',
})
.end()
}
// send the user to the app
res.setHeader('Location', `https://${ctx.cfg.service.appHostname}`)
return res.status(302).end()
}
// build url from original url in order to preserve query params
const url = new URL(
req.originalUrl,
`https://${ctx.cfg.service.appHostname}`,
)
url.pathname = found.path
res.setHeader('Cache-Control', `max-age=${(7 * DAY) / SECOND}`)
if (contentType === 'json') {
return res.json({url: url.href}).end()
}
res.setHeader('Location', url.href)
return res.status(301).end()
}),
)
}
+6 -1
View File
@@ -69,6 +69,11 @@
dependencies:
"@types/node" "*"
"@types/escape-html@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-1.0.4.tgz#dc7c166b76c7b03b27e32f80edf01d91eb5d9af2"
integrity sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==
"@types/node@*":
version "20.14.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.2.tgz#a5f4d2bcb4b6a87bffcaa717718c5a0f208f4a18"
@@ -276,7 +281,7 @@ es-errors@^1.3.0:
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
escape-html@~1.0.3:
escape-html@^1.0.3, escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+1
View File
@@ -97,6 +97,7 @@ const hideAvatarLabels = new Set([
'nudity',
'sexual-figurative',
'graphic-media',
'gore',
'self-harm',
'sensitive',
'security',
+14
View File
@@ -94,6 +94,20 @@ func run(args []string) {
Value: "",
EnvVars: []string{"STATIC_CDN_HOST"},
},
&cli.BoolFlag{
Name: "bsky-canonical-instance",
Usage: "Enable if this is the canonical deployment (bsky.app)",
Value: false,
Required: false,
EnvVars: []string{"BSKY_CANONICAL_INSTANCE"},
},
&cli.BoolFlag{
Name: "robots-disallow-all",
Usage: "Crawling is allowed by default. Enable this flag to Disallow all",
Value: false,
Required: false,
EnvVars: []string{"ROBOTS_DISALLOW_ALL"},
},
},
},
}
+21 -7
View File
@@ -63,6 +63,8 @@ func serve(cctx *cli.Context) error {
corsOrigins := cctx.StringSlice("cors-allowed-origins")
staticCDNHost := cctx.String("static-cdn-host")
staticCDNHost = strings.TrimSuffix(staticCDNHost, "/")
canonicalInstance := cctx.Bool("bsky-canonical-instance")
robotsDisallowAll := cctx.Bool("robots-disallow-all")
// Echo
e := echo.New()
@@ -204,13 +206,23 @@ func serve(cctx *cli.Context) error {
return http.FS(fsys)
}())
e.GET("/robots.txt", echo.WrapHandler(staticHandler))
e.GET("/ips-v4", echo.WrapHandler(staticHandler))
e.GET("/ips-v6", echo.WrapHandler(staticHandler))
e.GET("/.well-known/*", echo.WrapHandler(staticHandler))
e.GET("/security.txt", func(c echo.Context) error {
return c.Redirect(http.StatusMovedPermanently, "/.well-known/security.txt")
})
// enable some special endpoints for the "canonical" deployment (bsky.app). not having these enabled should *not* impact regular operation
if canonicalInstance {
e.GET("/ips-v4", echo.WrapHandler(staticHandler))
e.GET("/ips-v6", echo.WrapHandler(staticHandler))
e.GET("/security.txt", func(c echo.Context) error {
return c.Redirect(http.StatusMovedPermanently, "/.well-known/security.txt")
})
e.GET("/.well-known/*", echo.WrapHandler(staticHandler))
}
// default to permissive, but Disallow all if flag set
if robotsDisallowAll {
e.File("/robots.txt", "static/robots-disallow-all.txt")
} else {
e.GET("/robots.txt", echo.WrapHandler(staticHandler))
}
e.GET("/iframe/youtube.html", echo.WrapHandler(staticHandler))
e.GET("/static/*", echo.WrapHandler(http.StripPrefix("/static/", staticHandler)), func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
@@ -251,6 +263,7 @@ func serve(cctx *cli.Context) error {
e.GET("/moderation/modlists", server.WebGeneric)
e.GET("/moderation/muted-accounts", server.WebGeneric)
e.GET("/moderation/blocked-accounts", server.WebGeneric)
e.GET("/moderation/verification-settings", server.WebGeneric)
e.GET("/settings", server.WebGeneric)
e.GET("/settings/language", server.WebGeneric)
e.GET("/settings/app-passwords", server.WebGeneric)
@@ -263,6 +276,7 @@ func serve(cctx *cli.Context) error {
e.GET("/settings/account", server.WebGeneric)
e.GET("/settings/privacy-and-security", server.WebGeneric)
e.GET("/settings/content-and-media", server.WebGeneric)
e.GET("/settings/interests", server.WebGeneric)
e.GET("/settings/about", server.WebGeneric)
e.GET("/settings/app-icon", server.WebGeneric)
e.GET("/sys/debug", server.WebGeneric)
+3
View File
@@ -0,0 +1,3 @@
# This is an development or self-hosted instance of the bsky web app, and crawling has been disallowed by the operator team.
User-Agent: *
Disallow: /
+3 -1
View File
@@ -1,5 +1,6 @@
{
"project_id": "664276",
"project_id": "1",
"base_url": "https://bluesky.api.crowdin.com",
"base_path": ".",
"preserve_hierarchy": true,
"files": [
@@ -8,6 +9,7 @@
"translation": "/src/locale/locales/%two_letters_code%/messages.po",
"languages_mapping": {
"two_letters_code": {
"pt": "pt-PT",
"pt-BR": "pt-BR",
"en-GB": "en-GB",
"zh-CN": "zh-CN",
+5 -2
View File
@@ -15,7 +15,7 @@ This is NOT required when developing for web.
- Set up your environment [using the expo instructions](https://docs.expo.dev/guides/local-app-development/).
- make sure that the JAVA_HOME points to the zulu-17 directory in your `.zshrc` or `.bashrc` file: `export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home`. DO NOT use another JDK or you will encounter build errors.
- If you're running macOS, make sure you are running the correct versions of Ruby and Cocoapods:-
- If you're running macOS, make sure you are running the correct versions of Ruby and Cocoapods:-
- If you are using Apple Silicon and this is the first time you are building for RN 0.74+, you may need to run:
- `arch -arm64 brew install llvm`
- `sudo gem install ffi`
@@ -33,7 +33,7 @@ This is NOT required when developing for web.
- After initial setup:
- Copy `google-services.json.example` to `google-services.json` or provide your own `google-services.json`. (A real firebase project is NOT required)
- `npx expo prebuild` -> you will also need to run this anytime `app.json` or native `package.json` deps change
### Running the Native App
- iOS: `yarn ios`
@@ -162,6 +162,9 @@ See [testing.md](./testing.md).
`./platform/polyfills.*.ts` adds polyfills to the environment. Currently, this includes:
- TextEncoder / TextDecoder
- react-native-url-polyfill
- Array#findLast (on web)
- atob (on native)
### Sentry sourcemaps
+120 -77
View File
@@ -1,95 +1,138 @@
# OTA Deployments
## Overview
## Automatic internal OTAs
![OTA Deployment](./img/ota-flow.png)
## Internal Deployments
Internal OTA deployments should be performed automatically upon all merges into main. In cases where the fingerprint
diff results in incompatible native changes, a new client build will automatically be ran and deployed to TestFlight
OTA deployments to TestFlight/APK installs happen automatically upon all merges
into main. In cases where the fingerprint diff shows incompatible native
changes, a new client build will automatically be ran and deployed to TestFlight
(iOS) or delivered in Slack (Android).
## Production Deployments
## Production OTAs
### Prerequisites
Production OTAs can only update the JavaScript bundle. Changes to native modules
must be done as a full release cycle through the app stores.
- Find the latest production build number for both iOS and Android in Slack. These are listed in #client-builds
- Production builds always send the Version Number and Build Number in the Slack message. Search for the latest
production version number, and you should find the correct information.
![slack-build-info](./img/slack-build-info.png)
> [!TIP]
> If you're using a TestFlight build, in order to reference the correct build
> number and to verify the success of an OTA, you will need to delete the
> TestFlight app itself, delete the Bluesky app entirely, and re-install from
> the App Store.
- It may also be useful to check the current production clients for these values. This will also help for testing. Note
that you will need to _fully_ remove the existing internal client build from your device, otherwise the given values in
the app may differ from the actual production values.
### 1. Find the build numbers
![app-build-number](./img/app-build-number.png)
Find the latest production build numbers for iOS and Android in Slack. These are
spit out into `#bot-client-builds` after each release. You can also find this
information under the `About` section in app settings.
- You should have signed in to EAS locally through npx eas login. You will need to modify the build number in a
subsequent step.
- Ensure that the commit the initial client was cut from is properly tagged in git. The tag should be in the format of 1.X.0
- Note: If the commit is not properly tagged, then the OTA deployment will simply fail since the GitHub Action will
not be able to find a commit to fingerprint and diff against.
| Slack | In app |
| ----- | ------ |
| ![slack](./img/slack_client_builds.jpeg) | ![slack](./img/ios_settings_about.jpeg) |
### Preparation
### 2. Ensure the release is tagged
- Create a new branch from the git tag that the initial release was cut from if no OTA deployment has been made yet for this
client. Name this branch `1.X.0-ota-1`
- If a deployment has been made previously for this release, increment the branch name, i.e. `1.x.0-ota-2`
- If necessary, cherry-pick the commit(s) that you wish to deploy
- Ensure that the package.jsons version field is set to the appropriate value. As long as used the correct git tag
to create your branch from, this should be properly set.
You need to ensure that the latest release was properly tagged using the format
`1.X.0`. If the commit is not properly tagged, then the OTA deployment will
simply fail since the GitHub Action will not be able to find a commit to
fingerprint and diff against.
### Deployment
### 3. Create an OTA branch
- Update the build number through EAS to match the build numbers of the
production iOS/Android apps
- Note: This isnt strictly necessary, but having a step that takes you off of GitHub and into the terminal provides
a little “friction” to avoid fat fingering a release. Since there are legitimate reasons to just “click and deploy”
for internal builds, I felt it useful to make sure it doesnt accidentally become a prod deployment.
- Set the build numbers to the values found in the prerequisite steps. Again, this should be the
build number for the current production release you want to deploy for.
- `npx eas build:version:set -p ios`
- `npx eas build:version:set -p android`
- These steps should spit out what the current build number is, save those values
for later too
- Run the deployment
- Navigate to https://github.com/bluesky-social/social-app/actions/workflows/bundle-deploy-eas-update.yml
- Select the “Run Workflow” dropdown
![run-workflow](./img/run-workflow.png)
- Select the branch for the deployment you are releasing.
![branch-selection](./img/branch-selection.png)
- Double check the branch selection.
- Select the production channel
- Enter the version for the client you are releasing to, i.e. 1.80.0
- Note: If you do enter an incorrect version here, the deployment will either:
- Fail because the action cannot find a commit with your misentered version
- Succeed - but with no users receiving the update. This is because the version you entered will not properly
correlate to a _build number_ as well, so no clients in the wild will be able to receive the update.
![other-ota-options](./img/other-ota-options.png)
- Triple check the branch selection.
- You selected the correct branch
- You selected the "Production" channel
- You entered the correct version in the format of `1.X.0`.
- Press “Run Workflow”
Create a branch based off the last commit that was deployed in the most recent
release. This could be the commit that was tagged `1.x.0`, or a later commit,
but it **needs to be the tip of the latest production release** in any case.
Double check yourself by ensuring that the `version` in `package.json` matches
what's in the latest release.
In about five minutes, the new deployment should be available for download. To test:
This new OTA branch should follow the format `1.X.0-ota-1`. If one or more OTAs
have already been deployed for this release, incremement the branch name e.g.
`1.x.0-ota-2`.
- Remove the internal build of the app from your device
- Download the app from the App Store/Google Play
- Launch the app once and wait approximately 15 seconds
- Relaunch the app
- Check the Settings page and scroll to the bottom. The commit hash should now be the latest commit on your deployed branch.
### 4. Add commits to the OTA branch
### Post Deployment
Cherry pick in the commits that need to be deployed on top of the most recent
release or OTA.
- Reset both platforms build numbers to what they were before the OTA
deployment. These values should have been logged by the EAS CLI when you
reset them to the production values prior to OTA.
### 5. Manually set build numbers
Log in to the EAS CLI with `eas login` and manually set the build numbers to the
values you found in **Step 1**.
```sh
> npx eas build:version:set -p ios
>
> Project @blueskysocial/bluesky with bundle identifier "xyz.blueskyweb.app" is configured with buildNumber 1011.
> ✔ What version would you like to set? … 1009
>
> npx eas build:version:set -p android
>
> Project @blueskysocial/bluesky with application ID "xyz.blueskyweb.app" is configured with versionCode 641.
> ✔ What version would you like to set? … 639
```
👉 **Save the previous values,** in this case `1011` and `641`, so you can reset
them after the OTA completes.
### 6. Run the GitHub actions
You'll need to run two separate actions: one to deploy the iOS/Android OTA
itself, and one to build the web Docker container.
**For the iOS/Android OTA,** head to [Actions > Bundle and Deploy EAS
Update](https://github.com/bluesky-social/social-app/actions/workflows/bundle-deploy-eas-update.yml)
and run the action.
| Steps | |
| ----- | --- |
| Select your OTA branch `1.x.0-ota-x`, select `production` in the dropdown, enter the git tag of the latest release `1.x.0`, and click "Run workflow" | ![workflow](./img/ota_action.png) |
> [!NOTE]
> If you do enter an incorrect version here, the deployment will either:
> - Fail, because the action cannot find a commit with your misentered version
> - Succeed, but with no users receiving the update. This is because the version
> you entered will not properly correlate to a _build number_ as well, so no
> clients in the wild will be able to receive the update.
**For web,** head to [Actions >
build-and-push-bskyweb-aws](https://github.com/bluesky-social/social-app/actions/workflows/build-and-push-bskyweb-aws.yaml)
and run the action.
| Steps | |
| ----- | --- |
| Select your OTA branch `1.x.0-ota-x` and click "Run workflow" | ![workflow](./img/web_action.png) |
### 7. Deploy web
Once the web Docker container build finishes, go to your `1.x.0-ota-x` branch,
copy the most recent commit hash. Post this hash in `#ops-deploys` and request
someone with web deploy access deploy the built container.
### 8. Confirm successful deployment
In about five minutes, the new deployment should be deployed and devices will
begin downloading and installing in the background.
To confirm this, as mentioned above, you must completely clear the TestFlight
build from your device and re-install from the App Store. Then, you'll need to:
- Launch the app (or quit and reopen) and wait ~15s for the download to complete
- Quit and reopen the app
- Check the `Settings > About` page and confirm the has matches the most recent has on your OTA branch
### 9. Reset build numbers
Grab the build numbers you saved in **Step 5** and reverse the EAS CLI commands
to reset the build numbers.
```sh
> npx eas build:version:set -p ios
>
> Project @blueskysocial/bluesky with bundle identifier "xyz.blueskyweb.app" is configured with buildNumber 1009.
> ✔ What version would you like to set? … 1011
>
> npx eas build:version:set -p android
>
> Project @blueskysocial/bluesky with application ID "xyz.blueskyweb.app" is configured with versionCode 639.
> ✔ What version would you like to set? … 641
```
## Overview diagram
![OTA Deployment](./img/ota-flow.png)
Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+7 -6
View File
@@ -1,13 +1,13 @@
# Internationalization
We want the official Bluesky app to be supported in as many languages as possible. If you want to help us translate the app, please open a PR or issue on the [Bluesky app repo on GitHub](https://github.com/bluesky-social/social-app)
We want the official Bluesky app to be supported in as many languages as possible. If you want to help us translate the app, please get involved on [Crowdin](https://bluesky.crowdin.com/bluesky-social) or open an issue on the [Bluesky app repo on GitHub](https://github.com/bluesky-social/social-app).
## Tools
- We use Lingui to implement translations. You can find the documentation [here](https://lingui.dev/).
- We use Crowdin to manage translations.
- Bluesky Crowdin: https://crowdin.com/project/bluesky-social
- Bluesky Crowdin: https://bluesky.crowdin.com/bluesky-social
- Introduction to Crowdin: https://support.crowdin.com/for-translators/
- We use Lingui to implement translations. You can find the documentation [here](https://lingui.dev/).
## Translators
@@ -15,7 +15,7 @@ Much of the app is translated by community contributions. (We <3 our translators
### Using Crowdin
[Crowdin](https://crowdin.com/project/bluesky-social) is our primary tool for managing translations. There are two roles:
[Crowdin](https://bluesky.crowdin.com/bluesky-social) is our primary tool for managing translations. There are two roles:
- **Proof-readers**. Can create new translations and approve submitted translations.
- **Translators**. Can create new translations.
@@ -32,7 +32,7 @@ Please treat everyone with respect. Proof-readers are given final say on transla
### Adding a new language
Create a new [Crowdin discussion](https://crowdin.com/project/bluesky-social/discussions) or [GitHub issue](https://github.com/bluesky-social/social-app/issues) requesting the new language be added to the project.
You can request a new language be added to the project by clicking **Request New Language** on [Crowdin](https://bluesky.crowdin.com/bluesky-social) or you can create a [GitHub issue](https://github.com/bluesky-social/social-app/issues).
Please only request a new language when you are certain you will be able to contribute a substantive portion of translations for the language.
@@ -47,7 +47,8 @@ Every night, a GitHub action will run `yarn intl:extract` to update the english
### Release process
1. Pull main and create a branch.
1. Run `yarn intl:pull` to fetch all translation updates from Crowdin.
1. Run `yarn intl:pull` to fetch all translation updates from Crowdin. Commit.
1. Run `yarn intl:extract:all` to ensure all `.po` files are synced with the current state of the code. Commit.
1. Create a PR, ensure the translations all look correct, and merge.
1. If needed:
1. Merge all approved translation PRs (contributions from outside crowdin).
+1 -1
View File
@@ -119,5 +119,5 @@ jest.mock('statsig-react-native-expo', () => ({
},
}))
jest.mock('../src/lib/bitdrift', () => ({}))
jest.mock('../src/logger/bitdrift/lib', () => ({}))
jest.mock('../src/lib/statsig/statsig', () => ({}))
+5
View File
@@ -5,15 +5,19 @@ module.exports = {
'an',
'ast',
'ca',
'cy',
'da',
'de',
'el',
'en-GB',
'eo',
'es',
'eu',
'fi',
'fr',
'fy',
'ga',
'gd',
'gl',
'hi',
'hu',
@@ -27,6 +31,7 @@ module.exports = {
'nl',
'pl',
'pt-BR',
'pt-PT',
'ro',
'ru',
'sv',
+7 -8
View File
@@ -1,6 +1,6 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const {getDefaultConfig} = require('expo/metro-config')
const cfg = getDefaultConfig(__dirname)
const {getSentryExpoConfig} = require('@sentry/react-native/metro')
const cfg = getSentryExpoConfig(__dirname)
cfg.resolver.sourceExts = process.env.RN_SRC_EXT
? process.env.RN_SRC_EXT.split(',').concat(cfg.resolver.sourceExts)
@@ -16,22 +16,21 @@ if (process.env.BSKY_PROFILE) {
cfg.resolver.assetExts = [...cfg.resolver.assetExts, 'woff2']
// Enabled by default in RN 0.79+, but this breaks Lingui + others
cfg.resolver.unstable_enablePackageExports = false
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.
if (moduleName.startsWith('multiformats/hashes/hasher')) {
return context.resolveRequest(
context,
'multiformats/dist/src/hashes/hasher',
'multiformats/cjs/src/hashes/hasher',
platform,
)
}
if (moduleName.startsWith('multiformats/cid')) {
return context.resolveRequest(
context,
'multiformats/dist/src/cid',
platform,
)
return context.resolveRequest(context, 'multiformats/cjs/src/cid', platform)
}
if (moduleName === '@ipld/dag-cbor') {
return context.resolveRequest(context, '@ipld/dag-cbor/src', platform)
@@ -31,9 +31,13 @@ class BottomSheetView(
private lateinit var dialogRootViewGroup: DialogRootViewGroup
private var eventDispatcher: EventDispatcher? = null
private val screenHeight =
context.resources.displayMetrics.heightPixels
.toFloat()
private val rawScreenHeight = context.resources.displayMetrics.heightPixels.toFloat()
private val safeScreenHeight = (rawScreenHeight - getNavigationBarHeight()).toFloat()
private fun getNavigationBarHeight(): Int {
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
return if (resourceId > 0) resources.getDimensionPixelSize(resourceId) else 0
}
private val onAttemptDismiss by EventDispatcher()
private val onSnapPointChange by EventDispatcher()
@@ -63,12 +67,12 @@ class BottomSheetView(
}
}
var maxHeight = this.screenHeight
var maxHeight = this.safeScreenHeight
set(value) {
val px = dpToPx(value)
field =
if (px > this.screenHeight) {
this.screenHeight
if (px > this.safeScreenHeight) {
this.safeScreenHeight
} else {
px
}
@@ -153,6 +157,19 @@ class BottomSheetView(
// Presentation
private fun getHalfExpandedRatio(contentHeight: Float): Float {
return when {
// Full height sheets
contentHeight >= safeScreenHeight -> 0.99f
// Medium height sheets (>50% but <100%)
contentHeight >= safeScreenHeight / 2 ->
this.clampRatio(this.getTargetHeight() / safeScreenHeight)
// Small height sheets (<50%)
else ->
this.clampRatio(this.getTargetHeight() / rawScreenHeight)
}
}
private fun present() {
if (this.isOpen || this.isOpening || this.isClosing) return
@@ -172,12 +189,12 @@ class BottomSheetView(
val behavior = BottomSheetBehavior.from(it)
behavior.state = BottomSheetBehavior.STATE_HIDDEN
behavior.isFitToContents = true
behavior.halfExpandedRatio = this.clampRatio(this.getTargetHeight() / this.screenHeight)
behavior.halfExpandedRatio = getHalfExpandedRatio(contentHeight)
behavior.skipCollapsed = true
behavior.isDraggable = true
behavior.isHideable = true
if (contentHeight >= this.screenHeight || this.minHeight >= this.screenHeight) {
if (contentHeight >= this.safeScreenHeight || this.minHeight >= this.safeScreenHeight) {
behavior.state = BottomSheetBehavior.STATE_EXPANDED
this.selectedSnapPoint = 2
} else {
@@ -227,11 +244,11 @@ class BottomSheetView(
bottomSheet?.let {
val behavior = BottomSheetBehavior.from(it)
behavior.halfExpandedRatio = this.clampRatio(this.getTargetHeight() / this.screenHeight)
behavior.halfExpandedRatio = getHalfExpandedRatio(contentHeight)
if (contentHeight > this.screenHeight && behavior.state != BottomSheetBehavior.STATE_EXPANDED) {
if (contentHeight > this.safeScreenHeight && behavior.state != BottomSheetBehavior.STATE_EXPANDED) {
behavior.state = BottomSheetBehavior.STATE_EXPANDED
} else if (contentHeight < this.screenHeight && behavior.state != BottomSheetBehavior.STATE_HALF_EXPANDED) {
} else if (contentHeight < this.safeScreenHeight && behavior.state != BottomSheetBehavior.STATE_HALF_EXPANDED) {
behavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
}
}
@@ -300,6 +317,9 @@ class BottomSheetView(
// View overrides to pass to DialogRootViewGroup instead
override fun dispatchProvideStructure(structure: ViewStructure?) {
if (structure == null) {
return
}
dialogRootViewGroup.dispatchProvideStructure(structure)
}
@@ -139,19 +139,7 @@ class DialogRootViewGroup(
return super.onHoverEvent(event)
}
@Deprecated("Deprecated in Java")
override fun onChildStartedNativeGesture(ev: MotionEvent?) {
eventDispatcher?.let {
if (ev != null) {
jSTouchDispatcher.onChildStartedNativeGesture(ev, it)
}
}
}
override fun onChildStartedNativeGesture(
childView: View,
ev: MotionEvent,
) {
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
eventDispatcher?.let { jSTouchDispatcher.onChildStartedNativeGesture(ev, it) }
jSPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher)
}
+10 -3
View File
@@ -144,7 +144,8 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
}
func updateLayout() {
if self.prevLayoutDetentIdentifier == self.selectedDetentIdentifier,
// Allow updates either when identifiers match OR when prevLayoutDetentIdentifier is nil (first real content update)
if self.prevLayoutDetentIdentifier == self.selectedDetentIdentifier || self.prevLayoutDetentIdentifier == nil,
let contentHeight = self.innerView?.subviews.first?.frame.size.height {
self.sheetVc?.updateDetents(contentHeight: self.clampHeight(contentHeight),
preventExpansion: self.preventExpansion)
@@ -154,9 +155,15 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate {
}
func dismiss() {
guard let sheetVc = self.sheetVc else {
return
}
self.isClosing = true
self.sheetVc?.dismiss(animated: true) { [weak self] in
self?.destroy()
DispatchQueue.main.async {
sheetVc.dismiss(animated: true) { [weak self] in
self?.destroy()
}
}
}
@@ -1,15 +1,21 @@
import * as React from 'react'
import {
Dimensions,
NativeSyntheticEvent,
type LayoutChangeEvent,
type NativeSyntheticEvent,
Platform,
StyleProp,
type StyleProp,
View,
ViewStyle,
type ViewStyle,
} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {requireNativeModule, requireNativeViewManager} from 'expo-modules-core'
import {BottomSheetState, BottomSheetViewProps} from './BottomSheet.types'
import {isIOS} from '#/platform/detection'
import {
type BottomSheetState,
type BottomSheetViewProps,
} from './BottomSheet.types'
import {BottomSheetPortalProvider} from './BottomSheetPortal'
import {Context as PortalContext} from './BottomSheetPortal'
@@ -24,7 +30,10 @@ const NativeView: React.ComponentType<
const NativeModule = requireNativeModule('BottomSheet')
const isIOS15 = Platform.OS === 'ios' && Number(Platform.Version) < 16
const isIOS15 =
Platform.OS === 'ios' &&
// semvar - can be 3 segments, so can't use Number(Platform.Version)
Number(Platform.Version.split('.').at(0)) < 16
export class BottomSheetNativeComponent extends React.Component<
BottomSheetViewProps,
@@ -81,12 +90,10 @@ export class BottomSheetNativeComponent extends React.Component<
return null
}
const {children, backgroundColor, ...rest} = this.props
const cornerRadius = rest.cornerRadius ?? 0
let extraStyles
if (isIOS15 && this.state.viewHeight) {
const {viewHeight} = this.state
const cornerRadius = this.props.cornerRadius ?? 0
if (viewHeight < screenHeight / 2) {
extraStyles = {
height: viewHeight,
@@ -99,39 +106,70 @@ export class BottomSheetNativeComponent extends React.Component<
return (
<Portal>
<NativeView
{...rest}
<BottomSheetNativeComponentInner
{...this.props}
nativeViewRef={this.ref}
onStateChange={this.onStateChange}
ref={this.ref}
style={{
position: 'absolute',
height: screenHeight,
width: '100%',
extraStyles={extraStyles}
onLayout={e => {
const {height} = e.nativeEvent.layout
this.setState({viewHeight: height})
this.updateLayout()
}}
containerBackgroundColor={backgroundColor}>
<View
style={[
{
flex: 1,
backgroundColor,
},
Platform.OS === 'android' && {
borderTopLeftRadius: cornerRadius,
borderTopRightRadius: cornerRadius,
},
extraStyles,
]}>
<View
onLayout={e => {
const {height} = e.nativeEvent.layout
this.setState({viewHeight: height})
this.updateLayout()
}}>
<BottomSheetPortalProvider>{children}</BottomSheetPortalProvider>
</View>
</View>
</NativeView>
/>
</Portal>
)
}
}
function BottomSheetNativeComponentInner({
children,
backgroundColor,
onLayout,
onStateChange,
nativeViewRef,
extraStyles,
...rest
}: BottomSheetViewProps & {
extraStyles?: StyleProp<ViewStyle>
onStateChange: (
event: NativeSyntheticEvent<{state: BottomSheetState}>,
) => void
nativeViewRef: React.RefObject<View>
onLayout: (event: LayoutChangeEvent) => void
}) {
const insets = useSafeAreaInsets()
const cornerRadius = rest.cornerRadius ?? 0
const sheetHeight = isIOS ? screenHeight - insets.top : screenHeight
return (
<NativeView
{...rest}
onStateChange={onStateChange}
ref={nativeViewRef}
style={{
position: 'absolute',
height: sheetHeight,
width: '100%',
}}
containerBackgroundColor={backgroundColor}>
<View
style={[
{
flex: 1,
backgroundColor,
},
Platform.OS === 'android' && {
borderTopLeftRadius: cornerRadius,
borderTopRightRadius: cornerRadius,
},
extraStyles,
]}>
<View onLayout={onLayout}>
<BottomSheetPortalProvider>{children}</BottomSheetPortalProvider>
</View>
</View>
</NativeView>
)
}
@@ -1,4 +1,4 @@
import {BottomSheetViewProps} from './BottomSheet.types'
import {type BottomSheetViewProps} from './BottomSheet.types'
export function BottomSheetNativeComponent(_: BottomSheetViewProps) {
throw new Error('BottomSheetNativeComponent is not available on web')
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
s.static_framework = true
s.dependency 'ExpoModulesCore'
s.dependency 'SDWebImage', '~> 5.19.1'
s.dependency 'SDWebImage', '~> 5.21.0'
s.dependency 'SDWebImageWebPCoder', '~> 0.14.6'
# Swift/Objective-C compatibility
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) 2025 Alan Hughes
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+3
View File
@@ -0,0 +1,3 @@
# expo-emoji-picker
Based on [react-native-emoji-popup](https://github.com/okwasniewski/react-native-emoji-popup) and [expo-emoji-picker](https://github.com/alanjhughes/expo-emoji-picker)
@@ -0,0 +1,46 @@
apply plugin: 'com.android.library'
group = 'expo.community.modules.emojipicker'
version = '0.1.0'
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
apply from: expoModulesCorePlugin
applyKotlinExpoModulesCorePlugin()
useCoreDependencies()
useExpoPublishing()
// If you want to use the managed Android SDK versions from expo-modules-core, set this to true.
// The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code.
// Most of the time, you may like to manage the Android SDK versions yourself.
def useManagedAndroidSdkVersions = false
if (useManagedAndroidSdkVersions) {
useDefaultAndroidSdkVersions()
} else {
buildscript {
// Simple helper that allows the root project to override versions declared by this library.
ext.safeExtGet = { prop, fallback ->
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
}
project.android {
compileSdkVersion safeExtGet("compileSdkVersion", 34)
defaultConfig {
minSdkVersion safeExtGet("minSdkVersion", 21)
targetSdkVersion safeExtGet("targetSdkVersion", 34)
}
}
}
android {
namespace "expo.community.modules.emojipicker"
defaultConfig {
versionCode 1
versionName "0.1.0"
}
lintOptions {
abortOnError false
}
dependencies {
implementation "androidx.emoji2:emoji2-emojipicker:1.5.0"
}
}
@@ -0,0 +1,2 @@
<manifest>
</manifest>
@@ -0,0 +1,15 @@
package expo.community.modules.emojipicker
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
import java.net.URL
class EmojiPickerModule : Module() {
override fun definition() = ModuleDefinition {
Name("EmojiPicker")
View(EmojiPickerModuleView::class) {
Events("onEmojiSelected")
}
}
}
@@ -0,0 +1,40 @@
package expo.community.modules.emojipicker
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Configuration
import androidx.emoji2.emojipicker.EmojiPickerView
import expo.modules.kotlin.AppContext
import expo.modules.kotlin.viewevent.EventDispatcher
import expo.modules.kotlin.views.ExpoView
@SuppressLint("ViewConstructor")
class EmojiPickerModuleView(context: Context, appContext: AppContext) :
ExpoView(context, appContext) {
private var emojiView: EmojiPickerView = EmojiPickerView(context)
private val onEmojiSelected by EventDispatcher()
init {
setupView()
}
private fun setupView() {
addView(
emojiView, LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT
)
)
emojiView.setOnEmojiPickedListener { emoji ->
onEmojiSelected(mapOf("emoji" to emoji.emoji))
}
}
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
removeView(emojiView)
setupView()
}
}
@@ -0,0 +1,9 @@
{
"platforms": ["apple", "android"],
"apple": {
"modules": ["EmojiPickerModule"]
},
"android": {
"modules": ["expo.community.modules.emojipicker.EmojiPickerModule"]
}
}
+3
View File
@@ -0,0 +1,3 @@
export {default as EmojiPicker} from './src/EmojiPicker'
export {default} from './src/EmojiPickerModule'
export * from './src/EmojiPickerModule.types'
@@ -0,0 +1,25 @@
Pod::Spec.new do |s|
s.name = 'EmojiPickerModule'
s.version = '1.0.0'
s.summary = 'An emoji picker for use in Bluesky'
s.description = 'An emoji picker for use in Bluesky'
s.author = 'alanjhughes'
s.homepage = 'https://github.com/bluesky-social/social-app'
s.platforms = {
:ios => '15.1',
:tvos => '15.1'
}
s.source = { git: '' }
s.swift_version = '5.4'
s.static_framework = true
s.dependency 'ExpoModulesCore'
s.dependency 'MCEmojiPicker'
# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
}
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
end
@@ -0,0 +1,11 @@
import ExpoModulesCore
public class EmojiPickerModule: Module {
public func definition() -> ModuleDefinition {
Name("EmojiPicker")
View(EmojiPickerView.self) {
Events("onEmojiSelected")
}
}
}
@@ -0,0 +1,30 @@
import ExpoModulesCore
import WebKit
import MCEmojiPicker
class EmojiPickerView: ExpoView, MCEmojiPickerDelegate {
let onEmojiSelected = EventDispatcher()
override func layoutSubviews() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
self.addGestureRecognizer(tapGesture)
}
@objc func handleTap(_ gesture: UITapGestureRecognizer) {
presentEmojiPicker()
}
func presentEmojiPicker() {
let emojiPicker = MCEmojiPickerViewController()
let reactRootVC = reactViewController()
emojiPicker.sourceView = self
emojiPicker.delegate = self
reactRootVC?.present(emojiPicker, animated: true)
}
func didGetEmoji(emoji: String) {
onEmojiSelected([
"emoji": emoji
])
}
}
@@ -0,0 +1,28 @@
import {useMemo} from 'react'
import {useColorScheme} from 'react-native'
import {type EmojiPickerViewProps} from './EmojiPickerModule.types'
import EmojiPickerNativeView from './EmojiPickerView'
const EmojiPicker = ({onEmojiSelected}: EmojiPickerViewProps) => {
const scheme = useColorScheme()
const styles = useMemo(
() =>
({
flex: 1,
width: '100%',
backgroundColor: scheme === 'dark' ? '#000' : '#fff',
} as const),
[scheme],
)
return (
<EmojiPickerNativeView
onEmojiSelected={emoji => {
onEmojiSelected(emoji)
}}
style={styles}
/>
)
}
export default EmojiPicker
@@ -0,0 +1,15 @@
import {type EmojiPickerViewProps} from './EmojiPickerModule.types'
import EmojiPickerNativeView from './EmojiPickerView'
const EmojiPicker = ({children, onEmojiSelected}: EmojiPickerViewProps) => {
return (
<EmojiPickerNativeView
onEmojiSelected={emoji => {
onEmojiSelected(emoji)
}}>
{children}
</EmojiPickerNativeView>
)
}
export default EmojiPicker
@@ -0,0 +1,5 @@
import {NativeModule, requireNativeModule} from 'expo'
declare class EmojiPickerModule extends NativeModule {}
export default requireNativeModule<EmojiPickerModule>('EmojiPicker')
@@ -0,0 +1,20 @@
import {type ViewProps} from 'react-native'
export type EmojiSelectionListener = (event: {
nativeEvent: SelectionEvent
}) => void
export type SelectionEvent = {
emoji: string
}
export type EmojiPickerViewProps = ViewProps & {
/*
* Callback that will be called when an emoji is selected.
*/
onEmojiSelected: (emoji: string) => void
}
export type EmojiPickerNativeViewProps = ViewProps & {
onEmojiSelected: EmojiSelectionListener
}
@@ -0,0 +1,21 @@
import {requireNativeView} from 'expo'
import type * as React from 'react'
import {
type EmojiPickerNativeViewProps,
type EmojiPickerViewProps,
} from './EmojiPickerModule.types'
const NativeView: React.ComponentType<EmojiPickerNativeViewProps> =
requireNativeView('EmojiPicker')
export default function EmojiPicker(props: EmojiPickerViewProps) {
return (
<NativeView
{...props}
onEmojiSelected={({nativeEvent}) => {
props.onEmojiSelected(nativeEvent.emoji)
}}
/>
)
}
@@ -1,5 +1,3 @@
import React from 'react'
export interface ExpoScrollForwarderViewProps {
scrollViewTag: number | null
children: React.ReactNode
@@ -1,7 +1,6 @@
import * as React from 'react'
import {requireNativeViewManager} from 'expo-modules-core'
import {ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types'
import {type ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types'
const NativeView: React.ComponentType<ExpoScrollForwarderViewProps> =
requireNativeViewManager('ExpoScrollForwarder')

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