Compare commits

...

350 Commits

Author SHA1 Message Date
Dan Abramov b10d204e0a Fix forwarded ref 2024-06-04 16:43:58 +01:00
Ryan Skinner e7968bc8d7 add profiles to search history (#4169)
* add profiles to search history

* increasing horizontal padding slightly

* tightening up styling

* fixing navigation issue

* making corrections

* Make the search history profiles a little smaller

* bug stomping

* Fix issues

* Persist taps

* Rm unnecessary

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-06-04 16:31:24 +01:00
dan 6f1589971c Fix missing top borders (#4346) 2024-06-04 11:07:11 +01:00
Samuel Newman 2ffb98e22a allow nested quotes in DMs (#4345) 2024-06-04 11:03:43 +01:00
Samuel Newman d918f8dc2a Composer - unbork web (#4344)
* reduce side gap + add overflow hidden

also remove the animations since they don't appear in prod, and are kinda broken

* removed fixed height to fix alt text
2024-06-04 10:58:09 +01:00
Samuel Newman d032734278 Composer - make bottom border more consistent when typing (#4343)
* floor values

* fix last line being obscured

* Rm unnecessary runOnUI

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-06-04 10:55:35 +01:00
Eric Bailey 3e1f076891 [🙅] Disambiguation of the deactivation (#4267)
* Disambiguation of the deactivation

* Snapshot crackle pop

* Change log context

* [🙅] Add status to session state (#4269)

* Add status to session state

* [🙅] Add new deactivated screen (#4270)

* Add new deactivated screen

* Update copy, handle logout

* Remove icons, adjust padding

* [🙅] Add deactivate account dialog (#4290)

* Deactivate dialog

(cherry picked from commit 33940e2dfe0d710c0665a7f68b198b46f54db4a2)

* Factor out dialog, add to delete modal too

(cherry picked from commit 47d70f6b74e7d2ea7330fd172499fe91ba41062d)

* Update copy, icon

(cherry picked from commit e6efabbe78c3f3d9f0f8fb0a06a6a1c4fbfb70a9)

* Update copy

(cherry picked from commit abb0ce26f6747ab0548f6f12df0dee3c64464852)

* Sizing tweaks

(cherry picked from commit fc716d5716873f0fddef56496fc48af0614b2e55)

* Add a11y label
2024-06-04 02:10:43 +01:00
Eric Bailey de93e8de74 [🐴] Post embeds polish (#4339)
* Handle message cleanup

* Handle last message in chat list

* Memoize lastMessage
2024-06-04 02:07:01 +01:00
Samuel Newman da96fb1ef5 Native formSheet for GIF select on iOS (#4328)
* native formsheet for gif select

* trigger confirm discard if have gif

* give modal a background color

* fix web top bar - unrelated but I cba to make a separate PR
2024-06-04 02:05:46 +01:00
Hailey b02445883a add an apk to production build outputs for Obtanium release support (#4317)
* add an apk to production build outputs

* test a build

* Revert "test a build"

This reverts commit f89bfeefb7.
2024-06-03 17:32:58 -07:00
Thomas Dickerson bd4703ca1e Support for Flickr album and group pool embeds (#3936)
* Support for Flickr album and group pool embeds

* Oops, forgot to add flickr to the persisted externalEmbeds schema

* Need a bigint since our id can have more than 52 bits...

* Remove unexpected trailing / from test data to match the expected behavior

* nits

---------

Co-authored-by: Hailey <me@haileyok.com>
2024-06-03 17:29:45 -07:00
Samuel Newman 891b432ead Composer - add animated bottom border (#4325)
* start adding bottom border (wip)

* add content change listener

* add layout listener and move to hook

* remove logs

* use square-er image icon

* visually align bottom bar icons

* reduce keyboard vertical offset slightly

* only add border to top/bottom

* run worklet function on UI thread
2024-06-04 00:49:50 +01:00
dan 3b55f61d5f Avi follow experiment tweaks (#4341)
* Move avi button to visually align content

* Fix wrong prop warning

* Remove avi follow from post thread
2024-06-04 00:38:12 +01:00
Hailey 8c596b61c0 fix top border width for user list updates (#4340)
* fix nits in add/remove users from list screen

invert check

use `ViewHeader`

simplify

replace with hairline width

fix top border width for user list updates

* dont use `ViewHeader`

* update one more hairline
2024-06-03 16:34:37 -07:00
Bartosz Kaszubowski 44670c7ee2 Unify profile tabs and lists screens placeholders (#4315) 2024-06-03 16:05:26 -07:00
Hailey 8d8323421c remove resolution from post thread (#4297)
* remove resolution from post thread

nit

completely remove did cache lookup

move cache check for did to `usePostThreadQuery`

remove resolution from post thread

* helper function

* simplify

* simplify search too

* fix missing check for root or parent quoted post 🤯

* fix thread traversal
2024-06-03 23:58:16 +01:00
Yoshihiro Sugi 21d4d5f600 Fix filtering uris of fetchSubjects (#4324) 2024-06-03 23:41:03 +01:00
Hailey bda10510a4 use the new icon in reposted by (#4307)
* use the new icon in reposted by

* tweak
2024-06-03 23:35:57 +01:00
Hailey 16f295ca85 truncate if extending one line acct switcher (#4310) 2024-06-03 23:33:35 +01:00
Hailey f05aebf78e don't use flexBasis on web for message post embeds (#4303)
* don't use flexBasis on web

* rm unnecessary style
2024-06-03 17:05:37 -05:00
Eric Bailey de257a1186 Revert "[🐴] Embed backwards compat (#4302)" (#4338)
This reverts commit f868821cfc.
2024-06-03 17:05:14 -05:00
Hailey d93acb25f4 hide top border for mentions and replies (#4330) 2024-06-03 17:21:02 +01:00
Hailey 708a80e7a7 fix accessibility label in notifications (#4305)
* fix accessibility label in notifications

* add accessibility options to expand post

* inherit from outside, but always include `activate`

* include option to disable label/hint on previewable avatar

* fix hidden elements still being read on voiceover

* make it work for followers too

* extract variable

* fix hint

* update wording elsewhere
2024-05-31 21:02:18 +01:00
Samuel Newman b51640fbc0 [🐴] add emoji multiplier prop to RichText and bump it up for DMs (#4229)
* add emoji multiplier prop to RichText and bump it up for DMs

* remove background if only emoji

* Handle more emoji

* Adjust emoji regex and length

* Fix bad merge conflict res

* Fix logic

* Revert to emoji specific regex

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-31 20:57:42 +01:00
Eric Bailey 5cda807d9d Tweak avi follow button styles (#4304)
* Tighten up

* Tweak colors

* Tweak for night mode

* Add missing file

* Contrast plus
2024-05-31 20:45:41 +01:00
Eric Bailey f868821cfc [🐴] Embed backwards compat (#4302) 2024-05-31 12:56:06 -05:00
Eric Bailey 2bb3694819 [🐴] Add labels to chats (#4293)
* Add labels to chat list

* Add to convo header

* Prevent click through on PostAlert buttons

* Fix space

* Fix alignment
2024-05-31 12:14:11 -05:00
Samuel Newman cd3b502b34 [🐴] Option to share via chat in post dropdown (#4231)
* add send via chat button to post dropdown

(cherry picked from commit d8458c0bc344f993266f7bc7e325d47e40619648)

* let usePostQuery take uris with DIDs

(cherry picked from commit 16b577ce749fd07e1d5f8461e8ca71c5b874a936)

* add embed preview in composer

(cherry picked from commit 795ceb98d55b6a3ab5b83187a582f9656d71db69)

* rm log

(cherry picked from commit 374d6b8869459f08d8442a3a47d67149e8d9ddd4)

* remove params properly, or at least as close to

(cherry picked from commit c20e0062c2ca4d9c2b28324eee5e713a1a3ab251)

* show images in preview

(cherry picked from commit 5bb617a3ce00f67bfc79784b2f81ef8dcb5bfc25)

* Register embed immediately

(cherry picked from commit ee120d5438a2c91c8980288665576d6a29b4c7e7)

* Add hover to match embeds

(cherry picked from commit 5297a5b06e499f46a9f6da510124610005db2448)

* Update post dropdown copy

(cherry picked from commit bc7e9f6a4303926a53c5c889f1f1b136faf20491)

* Embed preview style tweaks

(cherry picked from commit 9e3ccb0f25ac2f3ce6af538bb29112a3e96e01b1)

* use hydrated posts from API and just use postembed component

(cherry picked from commit cc0b84db87ca812d76cc69f46170ae84cfdde4ef)

* fix type error

(cherry picked from commit 9c49b940e1248e8a7c3b64190c5cb20750043619)

* undo needless export

(cherry picked from commit 1186701c997c50c0b29a809637cb9bc061b8c0a0)

* fix overflow

(cherry picked from commit 8868d5075062d0199c8ef6946fabde27e46ea378)

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-31 11:10:00 -05:00
Samuel Newman 22e1eb18c8 [🐴] Record message (#4230)
* send record via link in text

* re-trim text after removing link

* record message

* only show copy text if message + add translate

* reduce padding

* adjust padding

* Tweak spacing

* Stop clickthrough for hidden content

* Update bg to show labels

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-31 10:43:04 -05:00
Samuel Newman 8eb3cebb36 [🐴] send record via link in text (Record DMs - base PR) (#4227)
* send record via link in text

* re-trim text after removing link
2024-05-31 10:41:06 -05:00
Samuel Newman 455937dd0f Use new icons on notifications screen (#4299)
* use new icons on notif screen

* replace placeholder icon too

* cull unused legacy icons
2024-05-31 13:13:01 +01:00
Samuel Newman 05b55c1966 Composer - fix modals, and other tweaks (#4298)
* fix depreciated import

* add animations to old dropdown

* wrap modals in fullwindowoverlay

* move errors inside header

* add background to bottom bar and stop overlap

* nest dialogs on android

* fix android (wrap in gesturehandlerrootview)

* make borders all the same color

* revert threadgate button back to solid
2024-05-31 12:55:51 +01:00
Eric Bailey d614f6cb71 Shadows (#4265) 2024-05-31 05:56:09 +01:00
Hailey 89c9fd3be1 Change many border widths from 1 to hairlineWidth (#4294)
* feed items

* update some more

* moar

* profile card

* composer and notifications

* settings screen

* remove border from first item in feeds

* remove border from first item in feeds

* more removal of top border

* fix flatlist rendering

* oops

* scroll to top fab

* a.border

* centeredview/list

* placeholder

* web sidebar

* search posts

* feeds list

* user lists

* list header

* account list width 1

* hide top border feedgens

* same for lists

* fix tab bar web desktop

* wait...

* show the border on desktop web

* fix lists

* fix lists

* round
2024-05-31 05:32:54 +01:00
Samuel Newman 8569e2e389 Add follow button to feed item avatar (#3560)
* add follow button to feed item avatar

* remove confirmation

* add confirmation (just system alert)

* Shrink the avi follow indicator a smidge

* gate the follow button

* remove from your own posts

* add to post thread item

* hide the follow button locally to component

* Use native dropdown

* Add follow btn to notifications and search

* UI tweaks

* Hide on PWI

* Add toast for confirmation

* Check gate last

* compiler

* Rm unused

* Use names

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-31 05:05:52 +01:00
dan 9879159438 Disable non-deterministic flaky test (#4295) 2024-05-31 04:09:23 +01:00
Hailey 8e2c21a882 Don't log downsample warning when unnecessary (#4291)
* fix log

use process.env

ensure the log happens regardless of `isDownsampledSession`

fix log

* oops, revert test
2024-05-31 01:52:56 +01:00
dan d6275e98c2 [Statsig] Sample noisy events (#4288)
* Sample state:background and state:foreground

* Sample feed events

* Add DEV protection against forgetting to add events to the list
2024-05-30 16:32:59 +01:00
dan 9431201026 Bump FontAwesome (#4285) 2024-05-30 15:57:56 +01:00
dan 9d4622e713 Fix scrolling for labeler profiles (#4286) 2024-05-30 15:57:45 +01:00
dan 8de028387c Reduce Threadgate button size (#4287) 2024-05-30 15:57:03 +01:00
Samuel Newman 8feb2ab449 put dropdown in fullscreenoverlay on iOS (#4284) 2024-05-30 14:06:59 +01:00
Samuel Newman 16925baf8d play haptics before closing modal (#4283) 2024-05-30 13:46:26 +01:00
Samuel Newman b077cbe399 match loadmore position to fab (#4280) 2024-05-30 12:40:22 +01:00
Samuel Newman 3bdceac2fb Composer - Use sheet presentation on iOS (#4278)
* use sheet presentation + tweak spacing

* line up elements + add hitslop to cancel

* fixing spacing on replies
2024-05-30 12:39:36 +01:00
Hailey 76f860dad2 don't maintain position whenever there are no parents (#4277) 2024-05-30 12:36:40 +01:00
Samuel Newman 13c08f56ba Fix native translations on iOS 17.5.1 (#4282)
* enable translations on iOS 17.5.1

* add comment
2024-05-30 12:35:38 +01:00
Samuel Newman a72f55a11f Composer - fix divider when replying to someone (#4279)
* move replyto border to beneath

* use hairline width for consistency

* fix border colors
2024-05-30 12:34:30 +01:00
Samuel Newman cd497a3974 only show divider when scrolled (#4275) 2024-05-30 10:45:35 +03:00
Samuel Newman d92036f2c5 Post controls update followup (#4276)
* rm legacy repost modal

* make repost button transparent

* reduce gap between post and ctrls

* remove old repost modal on web
2024-05-30 09:44:49 +03:00
Samuel Newman c4abaa1abc Use <Modal> for Composer (#3588)
* use <Modal> to display composer

* trigger `onPressCancel` on modal cancel

* remove android top padding

* use light statusbar on ios

* use KeyboardStickyView from r-n-keyboard-controller

* make extra bottom padding ios-only

* make cancelRef optional

* scope legacy modals

* don't change bg color on ios

* use fullScreen instead of formSheet

* adjust padding on keyboardaccessory to account for new buttons

* Revert "use KeyboardStickyView from r-n-keyboard-controller"

This reverts commit 426c812904.

* fix insets

* tweaks and merge

* revert 89f51c72

* nit

* import keyboard provider

---------

Co-authored-by: Hailey <me@haileyok.com>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-30 05:44:20 +01:00
Samuel Newman fba4a9ca02 scale down FAB on press (#4259) 2024-05-30 05:36:07 +01:00
Paul Frazee e48f8e15eb Interpret 'hide' setting as ALWAYS hiding from thread replies (#4263) 2024-05-30 05:34:47 +01:00
Paul Frazee 5fe1e171f0 Improve the visual clarity of labels on profiles and posts (#4262)
* Update PostAlerts rendering to show the avi of the labeler rather than the display name; also add size variations

* Update ProfileHeaderAlerts to match PostAlerts behavior
2024-05-30 05:33:18 +01:00
Hailey 4cc55f05c2 Use a margin of -6 instead of -5 for PostCtrls 😵‍💫 (#4272)
* -6 instead of -5 😵‍💫

* same here
2024-05-30 04:37:45 +01:00
Hailey 9edb487949 Always show the header on post threads on native (#4254)
* always show header on native

* ALF ALF ALF

* rm offset for top border

* wrap in a `CenteredView`

* use `CenteredView`'s side borders

* account for loading state on web

* move `isTabletOrMobile`

* hide top border on first post in list

* show border if parents are loading

* don't show top border for deleted or blocked posts

* hide top border for hidden replies

* Rm root post top border

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-30 04:28:32 +01:00
Hailey 9628070e52 add prop to ListImpl for disabling content-visibility style (#4236)
* add prop to `ListImpl` for `content-visibility` style

* change to `disableContentVisibility`

* lint

* tweaks

* Keep the fix more general

* Clarify ambiguity

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-30 04:09:24 +01:00
Hailey eb6f44853d adjust notifications experiment by removing canAskAgain (#4271)
* adjust notifications experiment by removing `canAskAgain`

* move to `StepFinished` for after onboarding
2024-05-30 02:42:12 +01:00
Samuel Newman 165feedb86 Use ALF for post controls (#3400)
* alf the repost dropdown on web + import icons

* alf like icon

* convert other post controls

* add missing padding to share button

* refine buttons and use better icons

* revert buttonicon changes

* remove ButtonIcon and ButtonText from repost dialog

* use 15px font size when not big

* reduce size and use contrast_25

* add hover state to logged out view

* add `userSelect: 'none'` to buttons

* use width rather than height

* fix quote close behaviour

* prettier

* Fix Esc on repost

* Use new icons for placeholder

* Fix placeholder

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-30 01:25:11 +01:00
Mary 4d39ef2e19 fix: don't round up count, truncate (#4261) 2024-05-29 19:50:13 +01:00
Nick Manos 65ad16e394 Change Android's MainActivity launchMode to singleTop (#4255)
* Add build config plugin to set .MainActivity launchMode

* Change android:launchMode to standard

* Revert "Change android:launchMode to standard"

This reverts commit fddbc4e1b5.

* adjust

---------

Co-authored-by: Hailey <me@haileyok.com>
2024-05-29 02:56:36 -07:00
Samuel Newman 33de856c32 match web version exports (#4257) 2024-05-29 12:00:15 +03:00
Hailey 613884a3d3 use xcode 15.3 (#4253)
* use xcode 15.3

* tweak cache update
2024-05-29 01:50:06 -07:00
Eiichi Yoshikawa 211eff3d32 Add statusBarTranslucent prop (= true) to KeyboardProvider in App.native.tsx (#4208) 2024-05-29 05:13:36 +01:00
Samuel Newman b59c8e22af Native translation expo module (#4098)
* translation expo module

* add `onClose` and `onReplacementAction`

* rm onReplacementAction

* make all props published

* make translation api available globally w/o wrapper (#4110)

* conditionally import the translation module

* only use native translation if language is probably supported

* open native translation via dropdown menu

---------

Co-authored-by: Hailey <me@haileyok.com>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-28 21:08:46 -07:00
Hailey a60f9933d8 Enable navigation animations on Android, decrease animation speed (#4207)
* bump and rm patch

* use the better settings

* fix types

* remove animation duration

* try it with full screen

* thanks mozz - use `ios` only on android

* maybe a little duration

* slightly faster duration

* Revert "fix types"

This reverts commit d15d4b7a9b.

* Revert "bump and rm patch"

This reverts commit 571f85f9e5.

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-29 05:04:56 +01:00
dan ff6a044f66 Bump more Expo libs (#4251)
* Bump more Expo libs

* Use legacy camera API

* fix `expo-notifications` patch

* bump `menu`

* change patch name

* patch reanimated

* Revert "patch reanimated"

This reverts commit dad822d8ea.

* Use nightly reanimated

* Revert "Use nightly reanimated"

This reverts commit 6687c71828.

* Revert "Revert "patch reanimated""

This reverts commit c30abd6732.

---------

Co-authored-by: Hailey <me@haileyok.com>
2024-05-29 05:02:49 +01:00
Paul Frazee efdfb7f57a Alt text followups -- SLIGHTLY larger, and update gifs (#4252)
* Bump up the alt text indicator's text size just a smidge

* Update the GIF alt indicator to match images (right side, visually smaller on mobile)
2024-05-29 04:58:40 +01:00
Hailey 19ee89caf3 upgrade react-native-svg to 15.3.0 (#4249) 2024-05-29 03:55:10 +01:00
Hailey eb0859bffb Fix hitSlop type (#4248) 2024-05-28 19:12:56 -07:00
Hailey 8f8af476cc Bump react-navigation (#4216)
* bump and rm patch

* fix types

* use `Home` default

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-29 02:38:52 +01:00
Hailey 888bec7b4f Upgrade to Expo 51 and React Native 0.74 (#3980)
* upgrade packages

* remove `expo-image-picker` patch

* remove old expo-updates patch

* rename rn patch

* downgrade crop picker

* bump `ExpoGifView` `SDWebImage` version

* apply config changes

* update build docs for apple silicon

* update build docs for apple silicon

* update expo-updates patch

* add back patch readme

* bump `expo-dev-client`

* bump `babel-preset`

* update `babel.config.js`

* update `react-native-paste-input` patch

* remove old ota updates hook

* update types

* update types

* downgrade pager-view

* update animated ref type

* fix web-only type

* update `react-native-bottom-sheet` `BottomSheetTextInput`

* add `expo-application` to jest mocks

* remove reanimated patch

* update notifications patch

* update reanimated path

* fix import

* update yarn.lock

* use `ItemT` instead of `any`

* expo bump

* Revert logic change, fix types

* Fix JSON file

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-29 02:15:35 +01:00
Hailey 5ceb440d4e use custom github action for fingerprinting (#4226)
* use custom github action for fingerprinting

* update pr workflow

* update names of workflows

* make a native change (testing)

* adjust the action

* Revert "make a native change (testing)"

This reverts commit 8db9835733.

* update bundle-deploy script

* test a prod build

* crazy depth

* manually set

* use prod default

* force prod

* revert test changes

* save cache after deploy

* revert testing
2024-05-28 16:38:24 -07:00
dan adbbded003 Remove old onboarding (#4224)
* Hardcode onboarding_v2 to true, rm dead code

* Rm initialState, use initialStateReduced

* Rm dead code

* Drop *reduced prefix in code

* Prettier
2024-05-28 16:56:06 +01:00
dan 9bd411c151 Replace getAgent() with reading agent (#4243)
* Replace getAgent() with agent

* Replace {agent} with agent
2024-05-28 16:37:51 +01:00
Hailey 8a2f43c218 Bump 1.85.0 (#4237) 2024-05-28 15:35:50 +01:00
Hailey 75e2c5487c bump iOS target to 14.0 (#4238) 2024-05-27 22:21:25 -07:00
Hailey af10d3acbb set onEndReachedThreshold to 2 for notifications (#4235) 2024-05-28 00:43:07 +01:00
Paul Frazee e6d26186a9 Run intl extract (#4217) 2024-05-24 13:48:16 -07:00
Takayuki KUSANO 642941f41d Updated Japanese translation (#4144)
* Updated Japanese translation

* Updated Japanese translation to resolve conflicts and updated msg

* Updated Japanese translation

ref. #4145

* changed the "Clip clop" translation

* Updated Japanese translation

* Updated Japanese translation

* Updated Japanese translation
2024-05-24 13:47:17 -07:00
Frudrax Cheng 96b5fecdb9 Updated Chinese translation (#4147)
* Update zh-TW to latest commit

* fixe p.p.  for "blocked"

* Update zh-TW to latest commit

* Update messages.po

* Remove superseded strings

* Clean zh-TW

* TW: Update messages.po

* TW: improve translation

Co-Authored-By: cirx <133132480+cirx1e@users.noreply.github.com>

* CN: extract

* Update zh-CN to latest commit

* TW: Update

* improve zh-CN translate

* BOTH: fix "Following {0}"

* CN: Update

* TW: Update

* BOTH: fix

msgid "You can continue ongoing conversations regardless of which setting you choose."

---------

Co-authored-by: Kuwa Lee <kuwalee1069@gmail.com>
Co-authored-by: cirx <133132480+cirx1e@users.noreply.github.com>
2024-05-24 13:46:47 -07:00
Minseo Lee 350e936b8c Update Korean localization (#4148)
* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po
2024-05-24 13:45:56 -07:00
Ivan Beà 55b50e694d Update catalan messages.po (#4149)
* Update messages.po

New lines added, new lines localized.

Check it please @jordimas @darccio @surfdude29

* Update catalan messages.po

Corrections by @surfdude29

* Update messages.po

apply @jordimas corrections
2024-05-24 13:45:08 -07:00
kodebanget 735fead673 Update Indonesian translation (#4165)
* Update Indonesian translation

* Update messages.po

---------

Co-authored-by: Indonesian <github-actions@github.com>
2024-05-24 13:44:44 -07:00
Samuel Newman dc9d80d2a8 [🐴] update convo list from message bus (#4189)
* update convo list from message bus

* don't increase unread count if you're the sender

* add refetch interval back

* Fix deleted message state copy

* only enable if `hasSession`

* Fix logged out handling

* increase refetch interval to 60s

* request 10s interval when message screen active

* use useAppState hook for convo resume/background

* Combine forces

* fix useFocusEffect logic

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-24 13:59:28 -05:00
Eric Bailey c0175af76a Recover from initial failed firehose state (#4211) 2024-05-24 13:50:50 -05:00
Paul Frazee afab4d5129 Move ALT indicator right and shrink it a bit (#4213) 2024-05-24 11:24:20 -07:00
Eric Bailey 2897b79bef Make sure failed messages enter error state (#4210) 2024-05-24 10:01:30 -05:00
Hailey 85782aeb93 [🐴] Don't submit the message on return press when on a phone (web input) (#4203)
move this to the `onKeyDown` prop

Revert "do the same for tablets"

This reverts commit 47c709e2734f2acf34f89dd5aca42a75a2b56270.

do the same for tablets

don't submit message if the device is a phone on web

move `onTouchStart` to `browser.ts` globals
2024-05-23 19:45:50 -07:00
dan fa039e542d Include feedContext in DOM as data- (#4206) 2024-05-24 01:25:11 +01:00
Paul Frazee f7ee532a85 Improve moderation behaviors: show alert/inform sources and improve UX around threads (#3677)
* Dont show account or profile alerts and informs on posts

* Sort threads to put blurred items at bottom

* Group blurred replies under a single 'show hidden replies' control

* Distinguish between muted and hidden replies in the thread view

* Fix types

* Modify the label alerts with some minor aesthetic updates and to show the source of a label

* Tune when an account-level alert is shown on a post

* Revert: show account-level alerts on posts again

* Rm unused import

* Fix to showing hidden replies when viewing a blurred item

* Go ahead and uncover replies when 'show hidden posts' is clicked

---------

Co-authored-by: dan <dan.abramov@gmail.com>
2024-05-24 00:39:39 +01:00
Samuel Newman d2c42cf169 Privileged app passwords (#4200)
* add checkbox to create privileged app password

* add indicator to privileged app pwds to list

* bump api

* oops missed the yarnlock

* adjust modal padding

* lowercase

* one more lowercase

---------

Co-authored-by: Hailey <me@haileyok.com>
2024-05-23 16:10:13 -07:00
Eric Bailey 406993cf0e [🐴] Overfetch follow for default new dialog state (#4205) 2024-05-23 16:06:50 -07:00
Eric Bailey 9096655955 Reduce polling (#4204)
* Reduce polling a bit

* Bump to 60

* Increase all

* ok 3
2024-05-23 17:21:47 -05:00
Hailey 5c2e99e3e6 [🐴] Fix Firefox send button positioning (#4201)
* use `align_center`

* revert

* account for firefox textarea size differences

set to `38`

remove some extra stuff

equal height on all platforms

* use atom
2024-05-23 13:08:12 -07:00
Hailey af20229b41 Add bundleDate, bundleIdentifier to StatsigUser (#4199)
* record event for fetched ota update

* Revert "record event for fetched ota update"

This reverts commit 4b49efe036.

* add `bundleDate` to `StatsigUser`

* include `bundleIdentifier` too

* move to `custom`
2024-05-23 19:52:36 +01:00
Hailey 70f190d44f Remove getProfile calls when loading feed (#3881)
* remove unnecessary `getProfile()` calls from feed load

add comments

ensure only if first

simplify

nit

handle cases where the parent is removed

add a comment

remove unnecessary `getProfile()` calls from feed load

limit only to the first post in the returned items

move the logic out of the render and into the query

add the grandparent properly

update `FeedItem`

bump package

update `FeedItem`

update `post-feed` query

update `FeedSlice`

* nit

* simplify logic

* always pass `parentAuthor`

* oops!

* update `DebugMod`
2024-05-23 19:35:49 +01:00
Eric Bailey 6d647551cd Log error statuses from failed resume session calls (#4174)
* Add log to track how resume fails

* Use safe field name

* Better log

* Properly catch
2024-05-23 19:27:53 +01:00
Hailey e5fc0baa6a disable alt text auto focus on Android (#4198)
* disable alt text auto focus on Android

* revert timeout change
2024-05-23 11:04:20 -07:00
Samuel Newman 0e77280310 [🐴] add link to chat settings from main settings (#4197)
* add link to chat settings from main settings

* move to beneath saved feeds

weird ass diff on this commit lol
2024-05-23 18:57:23 +01:00
Hailey f924465899 ✍️ Add OTA Docs (#4187)
* add OTA documentation

* maybe will look better

* nits

* one more nit

* use the right image
2024-05-23 10:34:01 -07:00
Hailey 9900d32904 Decrease thickness of border on message input (#4196) 2024-05-23 10:17:50 -07:00
Samuel Newman b093e0b673 [🐴] better error message for "Bad token scope" error (#4194)
* better error message for "Bad token scope" error

* log -> sign
2024-05-23 18:05:30 +01:00
Hailey 5217876f24 Add padding to dialogs when keyboard is open on Android (#4182)
* add keyboard padding to android dialogs

* missing `keyboardDismissMode` for `ScrollableInner`

* add to `MutedWords`

* add to `LabelsOnMe`
2024-05-23 10:01:31 -07:00
Eric Bailey 3d1ed04a70 [🐴] Do not init event bus if no session (#4193)
* Do not init event bus if no session

* Be explicit

* Simplify, fix log
2024-05-23 12:00:56 -05:00
Samuel Newman 17e0cb62a8 stop line breaks for timeelapsed (#4191) 2024-05-23 17:55:27 +01:00
Eric Bailey 9011c11eaf Reduce polling when app is backgrounded (#4192) 2024-05-23 11:54:22 -05:00
Hailey d051614342 implement a safari hack for ime (#4186)
remove debug logs

use a better hack

implement a safari hack

extract `isSafari` and `isFirefox` to a global variable
2024-05-23 16:45:24 +01:00
Eric Bailey 2c6c906934 [🐴] Suspend event bus when switching accounts (#4190)
* Suspend event bus when switching accounts

* Make effect symmetrical
2024-05-23 10:08:37 -05:00
Hailey efdcfd09e6 Bump 1.84.0 (#4185) 2024-05-23 04:15:38 +01:00
Samuel Newman 334483ad9a [Embeds] stop adding tracking params to non-bsky.app links (#4167)
* don't add tracking params on non-bsky.app links

* validate facets
2024-05-23 03:52:46 +01:00
Hailey 69f4684859 Handle zero bottom inset on iOS (#4184)
* set message padding to a minimum of 60 and max of 70

* adjust range
2024-05-22 19:44:37 -07:00
Dan Abramov 8938fc87a0 [Session] Dispose of stale agents immediately 2024-05-23 03:35:25 +01:00
Dan Abramov acf1def6c1 [Session] Persist updates from inactive agent 2024-05-23 03:35:25 +01:00
Hailey 03655abb7c wrap web in disabled keyboard provider (#4176) 2024-05-22 14:19:47 -07:00
dan 0c2fb13516 [Temporary] Disable React Compiler lint rules (#4172) 2024-05-22 19:04:28 +01:00
lauren bf8db6172f Add React Compiler (#4161)
* Install babel-plugin-react-compiler

* Install eslint-plugin-react-compiler

* Add and configure react-compiler-runtime

React Compiler uses a small cache function from React 19 at runtime.
Until it's possible to use R19 on RN, this adds a userspace
implementation to polyfill the cache function

* Add eslint-plugin-react-compiler to config

* @lingui/macro should run as the first plugin

@lingui recommends running their `macro` plugin [first in the
pipeline](https://lingui.dev/ref/macro). Normally with the React
Compiler, the compiler plugin should run first as we want to see the
original code as it was written. However, this sometimes causes
conflicts with other babel plugins.

In this case, it looks like the @lingui/macro plugin does some very
light transformation that the compiler can still understand and compile
correctly, so let's run it first.

Before this commit, the compiler would cause the @lingui/macro plugin to
crash because it seems like it would strip off the `extra.raw` property
off of StringLiterals which was being used
[here](https://github.com/lingui/js-lingui/blob/1293412c5dcc565636403443788a5b5d4ca206c1/packages/macro/src/macroJsx.ts#L395).
I need to figure out why the compiler is doing that but for now this
works and should be a safe change unless there were specific reasons
the macro plugin was placed 2nd to last.
2024-05-22 18:46:45 +01:00
dan e6e7027d01 Cleanup gates (#4170)
* Unlaunch disable_poll_on_discover_v2

* Rm unused gates

* Unlaunch autoexpand_suggestions_on_profile_follow_v2

* Launch disable_min_shell_on_foregrounding_v3
2024-05-22 18:19:07 +01:00
Samuel Newman 3ca41e4efb [🐴] Invalidate list convos query on block (#4171)
* more memoization

* invalidate listconvos query on block
2024-05-22 18:14:15 +01:00
Eric Bailey b937372325 More retries when resuming non-stale account (#4156) 2024-05-22 11:34:21 -05:00
Samuel Newman 690926dd90 Add note to clarify "allow new messages from" setting (#4166) 2024-05-22 15:52:04 +01:00
Hailey 6522ee9bbf don't use contentVisibility on Firefox (#4164) 2024-05-22 14:07:07 +01:00
Eric Bailey 4b0e118844 Remove added radius, add to specific location (#4160) 2024-05-21 17:14:30 -05:00
Hailey cbfb69dd15 [🐴] Support Japanese (et al.) IME in message input on web (#4159)
* support japanese et al. IME

* update comment

* nit
2024-05-21 13:37:16 -07:00
Samuel Newman 866b0b9121 [🐴] Fix convo menu overlap (web) (#4153)
* add right padding to chatlistitem to avoid overlap

* reduce padding amount
2024-05-21 15:33:00 -05:00
Hailey 630b9b7786 check maxTouchPoints is greater than 1, not zero (#4158) 2024-05-21 20:18:56 +01:00
Samuel Newman 7334e9fd81 close loggedout view when logging in (#4154) 2024-05-21 12:49:46 -05:00
Samuel Newman e5a1472974 flip order (#4152) 2024-05-21 16:16:36 +01:00
Samuel Newman f06a6024e6 fix to negative top of component so it moves with container growth (#4151) 2024-05-21 16:16:27 +01:00
Hailey 1ec4e0a867 Make list end text customizable (#4145)
* only try to initialize once

* nit

* change to `You have reached the end`

* make the text at end of list customizable

* make the text at end of list customizable

* update intl
2024-05-20 21:04:19 -07:00
dan b89e4ded2f Only fallback to Discover if Following is first pinned (#4146) 2024-05-20 21:03:17 -07:00
dan d6625c29d1 [Statsig] Sample router events (#4143) 2024-05-20 20:28:12 -07:00
Hailey 8cec1679a7 [🐴] only try to initialize once in the NUX (#4142)
* only try to initialize once

* nit
2024-05-20 20:13:06 -07:00
Paul Frazee 184c65836b Run intl extract 2024-05-20 20:09:03 -07:00
Hailey 5bbb5f5806 use same visuals for notification sounds setting as the allow messages from (#4141) 2024-05-20 20:08:29 -07:00
Eric Bailey 8be65a8790 Add convoId as key to Convo wrapper (#4140) 2024-05-20 21:59:55 -05:00
Paul Frazee 6b6a002b0a Run intl extract 2024-05-20 19:52:04 -07:00
Paul Frazee cb4045d2be Switch to a more visually obvious button for the threadgate (#4139)
* Switch to a more visually obvious button for the threadgate

* Move threadgate button into the keyboard-sticky area

* Fix keyboard offset
2024-05-20 19:51:34 -07:00
Eric Bailey 6cc040a94e [🐴] Add end of list text, fix threshold (#4138)
* Add end of list text

* onEndReachedThreshold
2024-05-20 21:42:49 -05:00
Eric Bailey ad2d84fb05 Fix button size on labeler (#4137)
* Fix button size

* Fix mobile
2024-05-20 21:04:27 -05:00
Pokai Chang 87fa501433 expand the background color to cover the overscroll area on settings screen (#4101) 2024-05-21 02:28:18 +01:00
Paul Frazee aa34d6b4d2 Release 1.83 (#4136)
* Test fixes

* Run intl:extract
2024-05-20 18:23:41 -07:00
Hailey a7c2370680 [🐴] set layout height in onLayout (#4135)
* set layout height in `onLayout`

* keep setting it in `onScroll` too
2024-05-20 18:03:53 -07:00
Pokai Chang cadc33c625 Fix laggy scrolling on mobile app's home screen, etc. (#4108)
* Improve scrolling performance for List

* Update List.tsx

* Apply same fix to profile labels

---------

Co-authored-by: dan <dan.abramov@gmail.com>
2024-05-21 01:41:12 +01:00
Samuel Newman 4a7436886d remove DMs gate (#4112) 2024-05-20 19:29:22 -05:00
Eric Bailey a7b0242cc8 [🐴] Empty chat prompt (#4132)
* Add empty chat pill

* Tweak padding

* move to `components`, place inside `KeyboardStickyView`

* cleanup unused vars

* add a new animation type

* (unrelated) add haptic to long press

* adjust shrink and pop

---------

Co-authored-by: Hailey <me@haileyok.com>
2024-05-20 16:56:44 -07:00
Eric Bailey 6dde487563 [🐴] Prevent flash upon first message (#4133)
* Prevent flash upon first message

* set `hasScrolled` to true when sending a message if it isn't already true

* revert other change

* lint

---------

Co-authored-by: Hailey <me@haileyok.com>
2024-05-20 16:29:16 -07:00
dan 4fa92d7a49 [Statsig] Fix exposure logging for reduced onboarding (#4131)
* Add dangerouslyDisableExposureLogging option

* Rename onboarding gate to v2

* Disable exposure logging for onboarding in PostFeed query
2024-05-21 00:17:57 +01:00
Hailey 516eb69637 [🐴] Add new chat metrics (#4130)
* remove a comment

* add types for event, add log to profile button

* add `chat:open`

* add to chat list items

* fix types

* oops

* oops 2.0
2024-05-20 15:26:05 -07:00
Eric Bailey 22522090c2 Ensure deleted chats don't count towards unread (#4129) 2024-05-20 17:19:01 -05:00
Eric Bailey e98bf6521b [🐴 Tweak appeal button styles (#4128)
* Tweak styles

* Tweak copy
2024-05-20 16:41:03 -05:00
Samuel Newman d3d2dc8ad4 [🐴] Appeal form for disabled DMs (#4126)
* add appeal dialog

* use useMutation for the labels on me dialog

* replace text button with small button
2024-05-20 22:23:36 +01:00
Samuel Newman e5aa8c081a in-convo muted chat indicator (#4127) 2024-05-20 22:16:53 +01:00
Eric Bailey 70019e73ef Some styling of empty list chats states (#4124) 2024-05-20 16:16:46 -05:00
Eric Bailey 31a716d256 [🐴] Handle deleted accounts, restructure ChatListItem (#4114)
* Handle deleted accounts, restructure ChatListItem

* Remove triggerOpacity option

* account for handle change in screen reader

* simplify the check

---------

Co-authored-by: Hailey <me@haileyok.com>
2024-05-20 16:16:29 -05:00
Eric Bailey becf373edb Maybe? (#4125) 2024-05-20 14:06:29 -07:00
Stanislas Signoud aa7c3130db Update French localization (#4113)
* Extract new strings to translate in French

* Translate new strings into French
2024-05-20 13:22:11 -07:00
Takayuki KUSANO 8194e07092 Update Japanese translations (#3886)
* Update Japanese translations

* Updated as PR on Plural is merged (#3882)
* Feedback API (#3498)

etc.

* Improve localization marks (#3285)

* Update Lightbox.tsx

* Change strings for easier localization

* Update DeleteAccount.tsx

* Update LabelsOnMeDialog.tsx

* Update FeedCard.tsx

* Update index.tsx

* Update LabelsOnMeDialog.tsx

* Update index.tsx

* Update FeedCard.tsx

* Update SelfLabel.tsx

* Update Hashtag.tsx

* Update index.tsx

* Update Hashtag.tsx

* Update ChangeHandle.tsx

* Update index.web.tsx

* Update index.web.tsx

* Update index.tsx

* Remove unnecessary `<Trans>` tags

* Update Drawer.tsx

* Finnish translation update (#3755)

* Update messages.po

Translated new strings (GIF's etc) and cleaned up deprecated ones.

* Update messages.po

resolve conflict

* Update messages.po

removed double quotes. Thanks @lapanti

* fix bad bool check in action (#3885)

* fix bad bool check in action

* add `fetch-depth` so we can get the commit hash

* `.env` should be in `.easignore` 🙃

* Updated to follow #3285 etc.

* The translation of 'place' and 'apply' of labels has been unified into '適用する'.

* Fix translation of "repost"

* Updated

* Updated Japanese translation

* Updated Japanese translation

- #3816

* Fixed translations

* Updated translation : #3995

* Updated Japanese translation

* Updated Japanese translation (ref. #3962 #4028)

* Updated Japanese translation

* Updated Japanese translation

* Updated Japanese translation

---------

Co-authored-by: Minseo Lee <itoupluk427@gmail.com>
Co-authored-by: Jan-Olof Eriksson <jan-olof.eriksson@iki.fi>
Co-authored-by: Hailey <me@haileyok.com>
2024-05-20 13:21:21 -07:00
Gildásio Filho 37739e817b Update pt-BR localization to latest version (#4009)
* Update messages.po

* Update src/locale/locales/pt-BR/messages.po

Co-authored-by: Gleydson Rodrigues <gleydsonsr@gmail.com>

---------

Co-authored-by: Gleydson Rodrigues <gleydsonsr@gmail.com>
2024-05-20 13:20:29 -07:00
Frudrax Cheng 6fba4143b4 Update zh-CN translations (#3932)
* remove superseded strings

* update messages.po

* fix typo

* remove messages.mo

* Simplify plural strings

* Correct some translations

* Correct some translations#2

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* fixed typo

* normalize string

* re-translated camera roll

* re-translated library

* remove .mo

* run intl:extract & update messages.po

* remove superseded strings

* update messages.po

* update messages.po

* adjust following feed translations

* adjusted feed translations

* adjusted following feed settings translations

* adjusted following feed settings translations#2

* Update messages.po

Co-authored-by: Kuwa Lee <kuwalee1069@gmail.com>

* Update messages.po

Co-authored-by: Kuwa Lee <kuwalee1069@gmail.com>

* Update messages.po

Co-authored-by: Kuwa Lee <kuwalee1069@gmail.com>

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* Update src/locale/locales/zh-CN/messages.po

* update messages.po

* update header information

* reverse some translations

* update messages.po

* fix removed translation

* run intl:extract

* update messages.po

* remove superseded strings

* translate 'People I Follow'

* make more localizable

* Fix special case "WhoCanReply"

* Update messages.po

* remove extraneous blank line

* remove duplicate 'click'

* update messages.po

* update messages.po

* update messages.po

* update messages.po

* update messages.po

---------

Co-authored-by: Kuwa Lee <kuwalee1069@gmail.com>
2024-05-20 13:19:59 -07:00
Kuwa Lee 2df0919e2d Update zh-TW translations (#4025)
* Update new strings to 1.82

* finalize 1.82 zh-TW

* Clean unused string

* zh-TW daily update

* zh-TW daily update

* unify "unblock" for "解除封鎖"

* Update messages.po

* Update zh-TW new strings

* Update messages.po

* fix typo

* Fix special case "WhoCanReply"

* Update src/locale/locales/zh-TW/messages.po

Co-authored-by: cirx <133132480+cirx1e@users.noreply.github.com>

* Update src/locale/locales/zh-TW/messages.po

Co-authored-by: cirx <133132480+cirx1e@users.noreply.github.com>

* Update src/locale/locales/zh-TW/messages.po

Co-authored-by: cirx <133132480+cirx1e@users.noreply.github.com>

* Update "Adjust the number of likes a reply must have to be shown in your feed."

* Update messages.po

* Update src/locale/locales/zh-TW/messages.po

Co-authored-by: cirx <133132480+cirx1e@users.noreply.github.com>

* Update latest commit sttrings

+ 3 new strings

* Update latest commit strings

* Update strings to latest commit

* Fix special case "WhoCanReply" again

* Explicitly description for "Graphic Media"

* small improve

* Update strings to latest commit

+21

* Small improve

* Update messages.po

Co-authored-by: cirx <133132480+cirx1e@users.noreply.github.com>

* fix "WhoCanReply" , and update

---------

Co-authored-by: cirx <133132480+cirx1e@users.noreply.github.com>
2024-05-20 13:19:14 -07:00
Minseo Lee b524d5409b Update Korean localization (#4030)
* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po
2024-05-20 13:18:32 -07:00
Ivan Beà 7cc3e958c8 Update catalan messages.po (#4079)
* Update catalan messages.po

New lines added, new lines localized.

Check it please @jordimas @darccio @surfdude29

* Update messages.po

apply @surfdude29 correction

* Update messages.po

Apply @jordimas corrections
2024-05-20 13:18:02 -07:00
Brodie 76be48b1a1 Update Spanish Localization (#4105) 2024-05-20 13:15:01 -07:00
Eric Bailey fe15e9df26 Allow removal of feeds that fail to load (#4121) 2024-05-20 13:04:33 -07:00
Hailey 52a885ad19 [🐴] Make message input layout resizing synchronous (#4123)
* make input resizing synchronous

* remove a log

* make scroll enable/disable sync

* lint

* start as undefined
2024-05-20 13:01:21 -07:00
Hailey 994af1454f [🐴] Adjust content height whenever the emoji picker keyboard is opened or closed (#4120)
* properly resize whenever the emoji keyboard is opened

* properly resize whenever the emoji keyboard is opened
2024-05-20 12:53:15 -07:00
Eric Bailey 5771ff4b56 Conditionally set chat declaration (#4122) 2024-05-20 14:41:24 -05:00
Eric Bailey f52db843ad [🐴] Fix load state for disabled chats (#4119) 2024-05-20 12:17:26 -07:00
Eric Bailey 3356bcfba6 Bump api sdk (#4118) 2024-05-20 14:00:37 -05:00
Eric Bailey d0bfe703d9 [🐴] Switch back to encouraging users to report messages (#4117)
* Swap prompt back in

* Remove unused convoAccount affordances
2024-05-20 13:49:20 -05:00
Samuel Newman cc7a0da1a2 convo button skeleton (#4115) 2024-05-20 19:44:50 +01:00
Hailey 492216a584 [🐴] Screenreader accessibility actions for individual chat items (#4116)
* add accessibility tap to messages

* add a label for the accessibility action

* improve accessibility actions on chat list items

* adjust types

* more consistent wording

* make the strings localizable
2024-05-20 11:36:08 -07:00
Samuel Newman 24f8794d4d [🐴] DM button on profile (#4097)
* add profile button

* separate out button to component

* normalise subscribe to labeller button size

* infinite staletime

* use Link rather than Button and change icon

* adjust icon position
2024-05-20 17:18:56 +01:00
Eric Bailey 2414559b80 [🐴] Don't retry sends (#4111)
* Don't retry sends

* Don't retry batch sends
2024-05-20 09:56:57 -05:00
Hailey 52beb29a0d [🐴] Fully implement keyboard controller (#4106)
* Revert "[🐴] Ensure keyboard gets dismissed when leaving screen (#4104)"

This reverts commit 3ca671d9aa.

* getting somewhere

* remove some now nuneeded code

* fully implement keyboard controller

* onStartReached check

* fix new messages pill alignment

* scroll to end on press

* simplify pill scroll logic

* update comment

* adjust logic on when to hide the pill

* fix backgrounding jank

* improve look of deleting messages

* add double tap on messages

* better onStartReached logic

* nit

* add hit slop to the gesture

* better gestures for press and hold

* nits
2024-05-19 19:25:49 -07:00
Eric Bailey 7de0b0a58c [🐴] Convo agent cleanup (#4109)
* Move comment, remove unused code

* Clean up sending

* Remove temp hack

* Remove debug
2024-05-19 18:52:51 -05:00
Hailey 3ca671d9aa [🐴] Ensure keyboard gets dismissed when leaving screen (#4104) 2024-05-18 18:25:42 -07:00
Samuel Newman cb7ce1d22e disable min shell on convo screen (#4103) 2024-05-19 02:14:04 +01:00
Hailey 1ac13abf4d [🐴] Minor nits (#4102)
* set a better size for `initialNumToRender`

* memo list items

* scroll to end on both platforms

* rev
2024-05-18 16:45:46 -07:00
Hailey 5343910570 [🐴] 🤞 This should be the final message list change - Use dispatchCommand so we don't need to know the content height (#4090)
* handle keyboard scroll more elegantly

simplify

missing `runOnUI`

better naming to avoid confusion

nit

remove unused function

use `dispatchCommand` in `onContentSizeChanged` as well

use `dispatchCommand` so we don't need to know the content height

remove `isMomentumScrolling`

* better timing

* nit

* another nit

* handle message input resizes better too

* account for other size changes like emoji keyboard opening

* one last nit

* just adding comments

* account for dragging

* make it easier to read

* add a comment

* 🤦‍♀️

* remove a little bit of that padding at the top
2024-05-18 12:29:23 -07:00
Hailey 2eaecfcaa4 [🐴] Reset screen when pressing a DM notification while already in the conversation screen (#4091)
* add a small comment

* reset if current screen
2024-05-18 12:23:24 -07:00
Hailey d2c81c9d3d Disable badge incrementing for DMs (#4088)
* disable badge increments for dms

* revert decrementing in js for dms

* reset badge on read notifications

* remove some other code

* prevent duplicate notification events
2024-05-17 16:05:32 -07:00
Eric Bailey 49314e2d1f [🐴] Mod disabled (#4089)
* Handle send failures

* Add chat disabled state
2024-05-17 16:05:21 -07:00
Eric Bailey 8b3bfb3cf7 Make generic convo report dialog (#4085) 2024-05-17 17:56:58 -05:00
Eric Bailey 1cdcb3e6c3 [🐴] New chat dialog refresh (#4071)
* Checkpoint, header styled, empty

* Checkpoint, styles

* Show recent follows in initial state, finesse some styles

* Add skeleton

* Add some limits

* Fix autofocus on web, use bottom sheet input on native

* Ignore type

* Clean up edits

* Format

* Tweak icon placement

* Fix type

* use prop for dismissing keyboard

---------

Co-authored-by: Hailey <me@haileyok.com>
2024-05-17 15:03:50 -07:00
Hailey d02e0884c4 [🐴] Block Info (#4068)
* get the damn thing in there 😮‍💨

* more cleanup and little fixes

another nit

nit

small annoyance

add a comment

only use `scrollTo` when necessary

remove now unnecessary styles

* move padding out

* add unblock function

* rm need for moderationpts

* ?

* ??

* extract leaveconvoprompt

* move `setHasScrolled` to `onContentSizeChanged`

* account for block footer

* wrap up

nit

make sure recipient is loaded before showing

refactor to hide chat input

typo squigglie

add report dialog

finalize delete

implement custom animation

add configurable replace animation

add leave convo to block options

* correct functionality for report

* moev component to another file

* maybe...

* fix chat item

* improve

* remove unused gtmobile

* nit

* more cleanup

* more cleanup

* fix merge

* fix header

* few more changes

* nit

* remove old
2024-05-17 16:21:15 -05:00
Eric Bailey 1b47ea7367 Set chat declaration upon signup (#4084) 2024-05-17 15:38:47 -05:00
Samuel Newman cef243bcf4 [🐴] delete chat service account on account delete (#4056)
* delete chat service account on account delete

* Add proxy header

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-17 14:53:51 -05:00
Samuel Newman f42f7fa035 [🐴] don't include blocked convos in unread count (#4082)
* don't include blocked convos in unread count

* Use moderateProfile

* Handle blocked state in chat list

* Fix logic formatting, add todo

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-17 14:46:01 -05:00
Samuel Newman dd0f57e3e3 [🐴] NUX (#4062)
* remove type assertion

* DMs NUX

* delete button for testing

* tweak styles and copy

* rm log

* style tweaks

* reduce amount of words

* Fix not showing on first load

* Spacing tweaks

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-17 14:24:06 -05:00
Samuel Newman 115041f4bf [🐴] Reduce header size (#4078)
* make text input container smaller

* make header much smaller

* improve web styling
2024-05-17 14:17:59 -05:00
Hailey 5e312d5f3a [🐴] Don't always show notification for everything (#4083)
* don't always show a notification

* nit
2024-05-17 09:23:46 -07:00
Hailey dd4c8d8e4f [🐴] Additional tweaks to the message list (#4075)
* more cleanup and little fixes

another nit

nit

small annoyance

add a comment

only use `scrollTo` when necessary

remove now unnecessary styles

* move `setHasScrolled` to `onContentSizeChanged`

* account for block footer
2024-05-17 08:21:35 -07:00
Eric Bailey 829f6a9e64 Conditionally load unreads (#4072) 2024-05-16 20:13:55 -05:00
Eric Bailey 0444e69c35 Revert "Aggregate quickly-sent messages into batches (#4061)" (#4069)
This reverts commit d424945eed.
2024-05-16 19:51:26 -05:00
Eric Bailey 1ff15b47f4 100% Real Deal™ (#4070) 2024-05-16 19:51:20 -05:00
Hailey 808511617d [🐴] 60 FPS Keyboard (#4066)
* use `scrollTo`

* let the animated reaction handle keyboard scroll

* no need for `requestAnimationFrame` now

* 'worklet'

* nit

* fixes

* more nits

* bool check
2024-05-16 17:12:41 -07:00
Eric Bailey eb1428b1d8 Fix delete message error (#4065) 2024-05-16 19:08:04 -05:00
Eric Bailey d424945eed Aggregate quickly-sent messages into batches (#4061) 2024-05-16 16:39:05 -05:00
Hailey a84a14d084 [🐴] Input hover and focus styles (#4064)
* styles for native input

* web focus/hover

* nit
2024-05-16 14:23:02 -07:00
Hailey ba068c8934 fix typo (#4060) 2024-05-16 16:16:51 -05:00
Eric Bailey 0c6af4fc6e Fix error styles (#4063) 2024-05-16 16:16:28 -05:00
Eric Bailey 449f16b7c5 Reset leave chat optimistic update if fails (#4058) 2024-05-16 15:52:53 -05:00
Hailey 5e5716c0a8 don't show individual labels on own profile, only "have been placed..." (#4057) 2024-05-16 13:22:04 -07:00
Eric Bailey 3a8baba129 [🐴] Tweak header styles (#4053)
* Tweak desktop header styles

* Tweak mobile

* Bump icon size

* Remove unused else
2024-05-16 15:19:35 -05:00
Hailey 72550df0e2 Properly update badge for other unread notifications (#4052)
* decrement badge count for chats

* handle decrement in `useMarkAsRead`

* remove async

* remove setting badge count

* oops

* update the number correctly

* nit
2024-05-16 12:21:29 -07:00
Hailey 5e8650a204 [🐴] Decrement app badge when opening unread chat (#4040)
* decrement badge count for chats

* handle decrement in `useMarkAsRead`

* remove async

* oops
2024-05-16 12:15:35 -07:00
Eric Bailey 4bceabc21c [🐴] Error recovery (#4036)
* Handle block state when sending messages

* Handle different pending failures

* Use existing profile data to handle blocks

* Better cleanup, leave room for more

* Attempt recover upon next send

* Reset pending failure

* Capture unexpected error

* Gracefully handle network errors and recovery

* Re-align error components and types

* Include history fetching in recoverable states
2024-05-16 14:01:39 -05:00
Hailey dff6bd7c65 [🐴] infinite stale time (#4051) 2024-05-16 11:58:45 -07:00
Hailey ef0ce951e7 [🐴] Only scroll down one "screen" in height when foregrounding (#4027)
* maintain position after foreground

* one possibility

* don't overscroll when content size changes.

* ignore the rule on 1 item

* fix

* [🐴] Pill for additional unreads when coming from background (#4043)

* create a pill with some animatons

* add some basic styles to the pill

* make the animations reusable

* bit better styling

* rm logs

---------

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

* import

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
2024-05-16 10:40:12 -07:00
Hailey b15b49a48f [🐴] Remove keyboard controller lib (#4038)
* remove library

* implement using just reanimated

* always return false for `keyboardIsOpening` on web

* undo comment

* handle input focus scroll more elegantly

* add back minimal shell toggle on mobile web

* adjust initialnumtorender

* oops

* nit
2024-05-16 09:32:10 -07:00
Samuel Newman da2bdf5d6f [🐴] use Toggle component in settings screen (#4048)
* use Toggle component

* nits + notifs sounds native only
2024-05-16 16:57:07 +01:00
Hailey d639c40e17 [🐴] Tweak padding of web input (#4033)
* tweak more

* nit
2024-05-16 08:52:53 -07:00
Eric Bailey 98af0e8678 Handle failed resumeSession case when switching accounts (#4047) 2024-05-16 10:46:20 -05:00
Hailey 400c269330 [🐴] Copy tweaks (#4042)
* `notifications` -> `conversation`

* `users` -> `people`

* `other participants` -> `the other participant`

* rename
2024-05-16 08:37:04 -07:00
Hailey b635d000b5 [🐴] Disable hover card when blocked or blocking (#4041) 2024-05-16 08:17:34 -07:00
Hailey 9499d4343d [🐴] A few tweaks to message input on native (#4035)
* tweaks

* only apply the padding on ios

* use a hitslop of 10 instead

* version bump
2024-05-16 08:09:14 -07:00
Samuel Newman aded49f65b Implement prefersReducedMotion on native (#4039)
* implement prefersReducedMotion on native

* just take the function from the reanimated source

* use patch-package to export internal function
2024-05-16 12:01:26 +01:00
Eric Bailey 3674c8abce Remove error for refresh, not necessary (#4034) 2024-05-15 15:32:40 -05:00
Hailey bf7b66d5c1 Add push notification extensions (#4005)
* add wav

* add sound to config

* add extension to `updateExtensions.sh`

* add ios source files

* add a build extension

* add a new module

* use correct type on ios

* update the build plugin

* add android handler

* create a patch for expo-notifications

* basic android implementation

* add entitlements for notifications extension

* add some generic logic for ios

* add age check logic

* add extension to app config

* remove dash

* move directory

* rename again

* update privacy manifest

* add prefs storage ios

* better types

* create interface for setting and getting prefs

* add notifications prefs for android

* add functions to module

* add types to js

* add prefs context

* add web stub

* wrap the app

* fix types

* more preferences for ios

* add a test toggle

* swap vars

* update patch

* fix patch error

* fix typo

* sigh

* sigh

* get stored prefs on launch

* anotehr type

* simplify

* about finished

* comment

* adjust plugin

* use supported file types

* update NSE

* futureproof ios

* futureproof android

* update sound file name

* handle initialization

* more cleanup

* update js types

* strict js types

* set the notification channel

* rm

* add silent channel

* add mute logic

* update patch

* podfile

* adjust channels

* fix android channel

* update readme

* oreo or higher

* nit

* don't use getValue

* nit
2024-05-15 11:49:07 -07:00
Hailey 31868b255f [🐴] Tweak list on mobile web (#3958)
* mobile web tweaks chat screen

* revert a change

* remove unnecessary prop

* Spacing tweaks

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-15 09:50:16 -07:00
Eric Bailey 04aea93192 [🐴] Better retry styling (#4032)
* Pass whole object to MessageItem for clarity

* Add retry to pending-message

* Style send failure, retry

* Group pending messages

* Remove todos

* Fix types with fake message
2024-05-15 11:45:18 -05:00
Samuel Newman ed8922281a [🐴] Show if user can be messaged in new chat search (#4021)
* show if user can be messaged

* allow 2 lines in handle field due to new text

* cannot -> can't

* rework canBeMessaged logic and move to new file

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-15 16:05:17 +01:00
Minseo Lee 2121b5f86f Make more localizable (#3962)
* Update ProfileList.tsx

* Update NoFollowingFeed.tsx

* Update LabelsOnMeDialog.tsx

* Update LabelsOnMeDialog.tsx

* Update NoFollowingFeed.tsx

* Update SavedFeeds.tsx

* Revert "Update SavedFeeds.tsx"

This reverts commit db128eb27d.
2024-05-14 22:44:59 -07:00
Hailey a90cc1c030 [🐴] change Follows Only to People I Follow (#4028) 2024-05-14 19:58:56 -07:00
Eric Bailey 6382fec732 Reset after 5 min (#4026) 2024-05-14 21:21:09 -05:00
Eric Bailey 6efe90a5f5 [🐴] Block states, read only (#4022)
* Refactor ChatListItem for mod state

* Refactor Conversation Header for mod state

* Invalidate query for list when blocking/unblocking

* Remove unused prop, restore border

* Add mutations, hook up profile shadow to list query, use shadow-aware query for convo (#4024)
2024-05-14 20:07:53 -05:00
Hailey d390db0fa2 [🐴]Add DM push notification sound (#4000)
* add wav

* add sound to config
2024-05-14 18:02:57 -07:00
Samuel Newman 0e04b19627 remove serviceurl gate (#4019) 2024-05-14 21:19:22 +01:00
Samuel Newman ebc7571368 reword subtitle (#4017) 2024-05-14 21:18:54 +01:00
Hailey e1ed4a4429 [🐴] show deleted account for missing.invalid (#4014)
* show deleted account for `missing.invalid`

* sigh
2024-05-14 11:42:54 -07:00
Samuel Newman 08836ecbec [🐴] use "Chats" instead of "Messages" (#4013)
* use "Chats" instead of "Messages"

* chats to chat

* use messages in the header
2024-05-14 19:18:08 +01:00
Samuel Newman 6b2635c870 100vh settings screen (#4015) 2024-05-14 19:17:53 +01:00
Paul Frazee 03da056513 Run intl extract (#4016) 2024-05-14 11:15:27 -07:00
Samuel Newman 5af61ca4e4 [🐴] Settings screen (#3830)
* create settings screen + api

* update api package

* use putrecord API with validate false

* create new RadioGroup component
2024-05-14 18:57:16 +01:00
Samuel Newman 9861494e34 [🐴] Message drafts (#3993)
* drafts

* don't throw if no convo ID

* Remove labs package

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-14 18:55:43 +01:00
Minseo Lee f147256fdc Update Korean localization (#3887)
* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

* Update messages.po

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

Co-authored-by: Frudrax Cheng <i@cynosura.one>

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

Co-authored-by: Frudrax Cheng <i@cynosura.one>

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

Co-authored-by: Frudrax Cheng <i@cynosura.one>

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

Co-authored-by: Frudrax Cheng <i@cynosura.one>

* Update messages.po

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

Co-authored-by: Frudrax Cheng <i@cynosura.one>

* Update messages.po

* Update messages.po

---------

Co-authored-by: Frudrax Cheng <i@cynosura.one>
2024-05-14 10:51:13 -07:00
Ivan Beà d515985fdd Update catalan messages.po (#3984)
* Update catalan messages.po

New lines update
You can check it @jordimas @darccio @ferranrego @MiquelAdell @johnnydement @surfdude29

* Update messages.po

apply @surfdude29 corrections
2024-05-14 10:48:47 -07:00
Eric Bailey d7f1b2a5df Fix dep (#4011) 2024-05-14 12:20:12 -05:00
Eric Bailey 1c51a48764 [🐴] Make status checks easier, fix load state (#4010)
* Make status checks easier, fix load state

* Make naming more clear

* Split up types for easier re-use

* Replace hacky usage
2024-05-14 11:59:53 -05:00
Samuel Newman bffb9b5906 [🐴] Chat muted state (#3988)
* separate out chatlistitem and add muted icon

* move bell icon to the right of the timeelapsed
2024-05-14 17:41:20 +01:00
Eric Bailey 9173be686c [🐴] Swap in new package, update usages (#3992)
* Swap in new package, update usages

* Remove uneccessary patch

* Override type in safe place
2024-05-14 09:22:09 -05:00
Paul Frazee 107760d551 Add better onboard testing (#4007) 2024-05-13 20:23:31 -07:00
Hailey fd704bfd44 add a Login notifications request (#4006) 2024-05-13 19:51:12 -07:00
Hailey fce65b74ff align the trash icon in the center in feed edit list (#4004)
* align the trash icon in the center

* align_center instead of align_start
2024-05-13 18:26:58 -07:00
Paul Frazee 0776cd99e5 Make feeds easier to reorder (#3998)
* Make feeds easier to reorder

* Add reorder e2e test

* Tweak feed card to only allow one line (#4002)

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-13 15:56:48 -07:00
Eric Bailey 95514e3af7 [Reduced Onboarding] Fix forward/backward nav with profile step (#3997)
* WIP

* Fix forward-backward to profile step

* [Reduced Onboarding] Add avatar metric (#3999)

* Add prop to finished event

* Fix type

* Use separate event
2024-05-13 16:54:12 -05:00
Eric Bailey 9980012021 Gate base following feed usage (#3994) 2024-05-13 16:54:03 -05:00
Samuel Newman 5d92ac2ce3 dont send message if >1000 graphemes (#3995) 2024-05-13 22:36:56 +01:00
Paul Frazee 27bb73c701 New onboarding tests (#3996)
* Add onboarding test

* Add onboarding avatar-creator test

* Update profile screen edit test
2024-05-13 14:20:27 -07:00
Eric Bailey f0cd8ab6f4 Swap in base following (#3991) 2024-05-13 12:44:21 -07:00
Eric Bailey 10919319bf Remove profile step from old onboarding (#3989) 2024-05-13 13:15:38 -05:00
Hailey 8e1541e0a5 actually register token on permissions change (#3990)
* actually register token on permissions change

* actually register token on permissions change

* get updated permissions every time

* remove all usages of `usePermissions`

* skip perms check on granted result from request
2024-05-13 11:11:35 -07:00
Hailey d3406c89cf Move request for notifications permissions to HomeReadyScreen (#3977)
* cleanup the current logic

* add statsig logs

* implement requests for permissions where needed

* oops

* let `addPushTokenListener` handle the token registration

* place new log event type with the other `notifications` type

* place registration next to handler

* more organization

* only call `gate()` if permission is not yet granted

* be more specific to prevent gate pollution

* nit

* make `token` non-optional in `registerToken`

* remove `prevDid`, move `registerPushToken` into `useEffect`

* keep it outside actually

* nit
2024-05-13 09:19:35 -07:00
Matthieu Sieben 63b38b413d fix wording in french onboarding (#3987) 2024-05-13 09:19:21 -07:00
Hailey e02cae2acd Fix overflowing text on web and iOS in PostMeta (#3982)
* `flexShrink` on iOS and web

`flexShrink` on iOS and web

`flexShrink` on iOS and web

actually, `flexShrink`

use `flex`

* adjust web

* `expect-error` `onMouseUp`

* ignore ref type check
2024-05-13 08:49:54 -07:00
Paul Frazee d49b93dc7e Replace e2e tests with Maestro (#3983)
* Setup maestro tests and convert some initial tests

* Remove detox

* Replace all tests with maestro
2024-05-13 08:43:13 -07:00
Hailey 5cd4ac3a34 get a little more accurate with month length (#3981)
* get a little more accurate with month length

* create some wiggle room, create some specific tests

* update more tests
2024-05-13 08:39:34 -07:00
Hailey 73d094c67e Delete the entire temporary directory instead of just the temp file, also use cacheDirectory over documentDirectory (#3985)
* lint

* remove extra arg
2024-05-13 02:10:29 -07:00
Matthieu Sieben 00a57df5b1 Fix "Download CAR file" on mobile (#3816)
* download CAR file using AtpAgent instead of building URL

* add loader icon on download car button

* actually save to disk on android

* style nits

* bottom margin nit

* localize toast

* remove fallback so back button works correctly

* keep throwing an error if mime type isn't used

* be more explicit with toasts

* send errors to sentry when encountered

---------

Co-authored-by: Hailey <me@haileyok.com>
2024-05-12 14:18:42 -07:00
dan 4458b03173 FeedFeedback fixes (#3968)
* Lower seen threshold to 1.5s

* Send feedContext for replies

* Use a simpler and more reliable feedContext fallback

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2024-05-12 10:30:00 -07:00
Hailey 97750c4aab Show "label has been placed..." even for self-labels (#3874)
* show labels placed on your content even if it's a self-label

even friendlier wording

friendlier wording

remove unnecessary `export`

temp revert reordering

show labels placed on your content even if it's a self-label

* Bump api 0.12.9

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2024-05-11 15:07:50 -07:00
dan 08462375ca Fix flashes when replacing For You (#3967)
* Fix flashes when replacing For You

* Switch to Discover if pinned after removing
2024-05-11 20:35:08 +01:00
dan 51b4b22dec Onboarding fixes (#3966)
* Ensure prefs are up-to-date before leaving onboarding

* Parallelize upsertProfile call

* Don't upsertProfile if no image

* Don't waterfall blob upload

* Fix useProfileUpdateMutation to parallelize uploads

* Invalidate user profile before leaving onboarding

* Ungate setting the pic
2024-05-11 19:54:58 +01:00
Paul Frazee 6f5b551bda Add shutdown message to for you feed (#3776) 2024-05-11 05:57:21 +01:00
Hailey d0440d087e bump (#3961) 2024-05-11 05:44:17 +01:00
Eric Bailey 4e37e2f59b [Reduced Onboarding] Add profile step (#3933)
* Onboarding avatar creator or upload (#2860)

* add screen to onboarding flow

* update base

* add icon

* fix icon

* fix after merge

* create flatlist

* add emoji list

* add state context, pressables

* select/update

* add camera icon

* add photo selection button

* image selection

* cleanup

* add most needed icons

* fix icon naming

* add icons

* export path strings for emoji

* canvas drawing for web

* types

* move breakpoints to individual steps

* create canvas

* canvas working 🎉

* update state

* it works!

* working on both platforms

* remove comments

* remove log

* remove unused web canvas

* animate picture selection/removal

* compress images on web correctly

* add times icon

* scrollable horizontal flatlist on web

* prefetch

* adjustments

* add more assets

* remove unused smiles

* add all the icons

* adjust color options

* animate grow/shrink selections

* change layout on tablet/desktop

* better web layout

* fix path

* adjust web layout

* organize

* organize imports and cleanup styles

* make generated images smaller

* implement design changes

use row for buttons on web

use RNGH FlatList

random color at start

improve logic

update dialog for web

update dialog style on mobile

some more progress

create dialog

simplify context

start implementing design

* rm change

* cleanup imports

* trigger a pr label

* Formatting

---------

Co-authored-by: Eric Bailey <git@esb.lol>
(cherry picked from commit 087186e386)

* UI tweaks

* Revert layout change

* Gate avi upload

* Support returning to profile step

* Add Statsig

---------

Co-authored-by: Hailey <me@haileyok.com>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-11 05:37:23 +01:00
Eric Bailey 80ce6f980e [Reduced Onboarding] Add new step, new state to reducer (#3931)
* Add new step, new state to reducer

* Don't set default feeds
2024-05-11 05:19:16 +01:00
Eric Bailey 08979f37e7 Movable following feed (#3593)
* Handle home algo with backwards compat

* Remove todo, fix pwi view

* Simplify filter logic

* Handle edge case

* Handle home algo in FeedSourceCard

* Fix handling of pinned feed if home algo is disabled

* Handle home algo on ProfileFeed screen

* Rename

* Fix pinned feeds key

* Improve perf of pinned feeds with primary algo

* Update statsig API

* Revert unneeded changes

* Support following feed as well

* Better formatting

* Clarify primary algo usage

* Better comment

* Handle saved feed screen edge case

* Restore Feeds sparkle, fix line height

* Move gate call down

* Filter out primary algo from feeds page

* Filter dupe from Feeds screen

* Simplify logic

* Missing following handling

* Hide primary feed setting outside exp

* Revert testing change

* Migrate usePinnedFeedInfos

* Migrate FeedSourceCard

* Migrate Feeds screen

* Migrate SavedFeeds screen

* Handle timeline in feed infos

* Finish migrating ProfileFeed, FeedSourceCard

* Migrate ProfileList

* Finalize mutation hooks

* Allow unsaving lists

* Handle following feed on Feeds screen

* Handle following on SavedFeeds

* Get rid of deprecated interface usages

* Handle no pinned feeds

* Handle no feeds on Feeds screen

* Reuse component on SavedFeeds screen

* Handle no following feed

* Remove primary algo references

* Migrate to new plural APIs

* Remove unused event

* Prevent duplicate keys

* Make handling much more clear

* Dedupe useHeaderOffset

* Filter unknown feed types at source

* Use just following

* Immprove key handling

* Resume from last tab

* Bump sdk

* Revert Gemfile

* Additional protection in FeedSourceCard

* Fix ProfileList save/unsave handling

* Translate

* Translate

* Match existing handling post-signup

* Ensure onboarding results in correct selected feeds

* Some testing tweaks on create/onboarding

* Revert primary algo consderations

* Remove comment

* Handle default feed setting

* Rm unnecessary type cast

* Remove premature gate check

* Remove nullable check in onPageSelecting, assume the pager checks bounds

* Use null for default selected feed

* Rm unrelated change

* Remove the concept of __key__

I don't think this concept is consistent.

It's introduced on FeedSourceInfo which is used both by pinned feeds and by useFeedSourceInfoQuery. Pinned feeds use the pinning ID there. But there is no pinning ID for useFeedSourceInfoQuery. So this means this field is sometimes one thing and sometimes some other thing. That is a decent sign that it shouldn't be on that type at all.

It's not used anywhere except the desktop feed enumeration. It seems reasonable to assume there that we wouldn't want to show the same feed URL twice. (And if it does occur in the array twice, IMO we should solve that at the API level and dedupe it on read or next write.) So I think we should just use the URL in that place. (I used the descriptor, which is equivalent.)

* Dedupe pinned feeds by URL on read

* Filter timeline out of mergefeed sources

* Put FeedDescriptor into FeedSourceInfo

* Group saved info with feed for pins

This removes a loop within a loop within a loop.

* Fix Feeds link on native

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-11 04:39:21 +01:00
Eric Bailey 2974ce1b20 Gate chat icon in bottom bars (#3959) 2024-05-10 18:02:33 -05:00
Eric Bailey f84a2def29 [🐴] Simplify message passing, cleanup (#3952)
* Simplify message passing

* Setup/teardown events
2024-05-10 12:44:55 -05:00
Samuel Newman ab21aafc28 [🐴] Report message dialog (#3941)
* message report dialog

* report chat prompt

* typo

* 100% height sheet on android

* messages-specific report options

* restore unwanted sexual content

* chat -> conversation
2024-05-10 17:52:21 +01:00
Samuel Newman 7370bebf07 remove 12hr time (#3954) 2024-05-10 17:36:06 +01:00
Eric Bailey cf981124e4 Add icons to drawer (#3956) 2024-05-10 11:08:53 -05:00
Hailey 9f6552241f bump max width of message (#3955) 2024-05-10 09:04:03 -07:00
Hailey f928e0a547 [🐴] Mutate data instead of invalidating queries when muting or unmuting (#3946)
* mutate for mutes

* mutate data for mutes

* add initial data, `useConvoQuery` in `ConvoMenu`

* `useInitialData`

* don't use `identifier` for notifications, use `dates` instead

* better implementation

* simplify

* simplify

* fix types
2024-05-10 08:46:51 -07:00
Eric Bailey 8f56f79c6c [🐴] Change up icons (#3938)
* Swap for chat icon

* Replace icons in left nav

* Replace icons in bottom bars

* Ditch feeds, drop size

* Fine tune

* Swap bell icon, improve alignment and size
2024-05-10 10:42:45 -05:00
Eric Bailey d7f3a8d01f [🐴] Clean up after deleting message (#3950)
* Clean up after removal

* Remove console
2024-05-10 10:40:52 -05:00
Hailey 54c4baacb6 [🐴] Move KeyboardAvoidingView up to the main screen (#3953) 2024-05-10 08:24:29 -07:00
Hailey e729647c02 [🐴] Adjust messages list styles (#3945)
* some initial tweaks

* tweaks

* more tweaks

* tweak chat header

* properly align placeholders

* tweak web header

* one more...

* remove extra loading states from chat

* limit line count for display name

* Tweaks styles (#3949)

* Adjust sizing

* Consistent font size

* Adjust header

* oops

* fix accessibility in list

* don't use `identifier` for notifications, use `dates` instead

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-10 08:09:00 -07:00
Hailey 1a90426026 [🐴] Remove extra spinner states from chat screen (#3947)
* remove extra loading states from chat

* nits

* fix scrolling animation to bottom

* nit

* move spinner to top
2024-05-10 07:49:08 -07:00
Eric Bailey 195c9f1045 [🐴] Handle errors, improve styling (#3937)
* Handle errors, improve styling

* Remove old UI
2024-05-10 08:23:37 -05:00
Hailey 1821a992ab Use build arg in docker action to correctly pass git commit SHA (#3940)
* use env variables through docker args

* remove quotes

* use an output instead

* try that again

* write the variables to .env

* rm unused

* use short sha

* remove test branch
2024-05-09 17:29:25 -07:00
dan 6e172b6ce3 [Session] Restore emailAuthFactor and emailConfirmed from last session (#3939) 2024-05-09 16:05:44 -07:00
Eric Bailey 55fdbc7399 Add retries to all handlers (#3935) 2024-05-09 16:31:36 -05:00
Samuel Newman becc708c61 [🐴] Rich text in messages (#3926)
* add facets to message

* richtext messages

* undo richtexttag changes

* whoops, don't redetect facets

* dont set color directly

* shorten links and filter invalid facets

* fix link shortening

* pass in underline style
2024-05-09 21:08:56 +01:00
Samuel Newman 03b2796976 lowcase ALT text (#3934) 2024-05-09 20:58:22 +01:00
Hailey 17e3b946cb Handle push notifications for DMs (#3895)
* add some better handling for notifications

prep merge

move `useNotificationsListener` into shell

progress

better structure

only show messages notifications while using app if it is the current account

progress

only emit on native

current chat emitter

only show alerts for the current chat

type

add logs

setup handlers

* remove event emitter

* just needs cleanup

* oops

* remove unnecessary `queryClient` param

* few fixes

* cleanup

* nit

* remove folds

* remove comment

* simplify if

* add back invalidate

* comment out other navigations for now

* rename type

* handle various navigation cases

* push to conversation from notification

* update badge in all cases except `chat-message`

* ensure no duplicate notifications

* rm unused `animationOnReplace`

* revert to using `goBack` in the conversation header

* add todo comment
2024-05-09 10:04:05 -07:00
Eric Bailey 1341845537 Add gate, a:a swap onboarding state (#3930) 2024-05-09 11:34:36 -05:00
Hailey 2fe76333bc [🐴] Add hover context menu for convo list on web (#3923)
* remove some unnecessary props

* add hover trigger on web for convo list

* lint

* use `UserAvatar` to not affect accessibility

* remove extra wrapper

* add `label`

* always show on mobile

* adjust size of dots

* make the message trigger dots the same size

* 
2024-05-09 09:07:57 -07:00
Samuel Newman 55ac287d5e [🐴] Skeleton header (#3921) 2024-05-08 17:08:24 -07:00
Eric Bailey 3bac0182b5 [🐴] Integrate event bus (#3915)
* Integrate event bus

* Fixes

* Move events mgmt into Convo class

* Clean up poll interval updates

* Remove unused

* Remove annoying log
2024-05-08 18:01:07 -05:00
Eric Bailey ce2eddca8e [🐴] Refactor event bus (#3919)
* Refactor to singleton class outside react

* Fix retry, remove debug logs
2024-05-08 17:41:10 -05:00
dan 0c6bf276dd Replace updateCurrentAccount() with refreshSession() (#3910)
Replace updateCurrentAccount() with resumeSession()
2024-05-08 23:11:39 +01:00
Hailey f62b0458a7 [🐴] Adjust press and hold delay on messages (#3918)
* adjust press and hold delay on messages

* adjust hit slop
2024-05-08 13:56:36 -07:00
Samuel Newman 701e508a1a add sideborders prop (#3920) 2024-05-08 21:44:49 +01:00
Samuel Newman 750a5c899b actually optimistic mark as read (#3917) 2024-05-08 21:19:45 +01:00
Eric Bailey 7d06fb9432 Move to requestPollInterval handling (#3914) 2024-05-08 11:34:04 -05:00
bnewbold f3515e2673 use four-digit years for RSS pubDate (#3907) 2024-05-08 09:33:38 -07:00
Samuel Newman 38198fdf7f [🐴] Mark as read in convo menu (#3913)
* add mark as read option

* optimistic update + link up menu

* rm messageid
2024-05-08 15:48:05 +01:00
Eric Bailey 56f713077f [🐴] Reorg convo files (#3909)
* Remove unused prop

* Reorganize
2024-05-07 19:46:59 -07:00
dan 814ec2bd7f Add session reducer tests (#3860) 2024-05-08 03:34:35 +01:00
dan 0910525e2e [Session] Code cleanup (#3854)
* Split utils into files

* Move reducer to another file

* Write types explicitly

* Remove unnnecessary check

* Move things around a bit

* Move more stuff into agent factories

* Move more stuff into agent

* Fix gates await

* Clarify comments

* Enforce more via types

* Nit

* initSession -> resumeSession

* Protect against races

* Make agent opaque to reducer

* Check using plain condition
2024-05-08 03:30:55 +01:00
Samuel Newman 4fe5a869c3 [🐴] Unread messages badge (#3901)
* add badge

* move stringify logic to hook

* add mutation hooks

* optimistic mark convo as read

* don't count muted chats

* Integrate new context

* Integrate mark unread mutation

* Remove unused edit

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-07 21:23:09 -05:00
dan 0c41b3188a [Session] Remove global agent (#3852)
* Remove logs and outdated comments

* Move side effect upwards

* Pull refreshedAccount next to usage

* Simplify account refresh logic

* Extract setupPublicAgentState()

* Collapse setStates into one

* Ignore events from stale agents

* Use agent from state

* Remove clearCurrentAccount

* Move state to a reducer

* Remove global agent

* Fix stale agent reference in create flow

* Proceed to onboarding even if setting date fails

---------

Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-08 03:10:03 +01:00
Eric Bailey 31a8356aef Handle invalid service URLs (#3908) 2024-05-07 21:09:02 -05:00
Eric Bailey 165fdb7049 [🐴] Integrate global event bus (#3904)
* Conditionally run global event bus

* Add current convo id context, bundle providers
2024-05-07 20:25:58 -05:00
Hailey 37f22ca224 fix privacy api type (#3903) 2024-05-07 16:35:04 -07:00
Eric Bailey b2b1c6c040 Let React app replace preload (#3900)
* Let React app replace preload

* Fix html structure

* Fix indent
2024-05-07 18:29:21 -05:00
Eric Bailey 53d844495b Remove messages provider (#3902) 2024-05-07 18:29:06 -05:00
Eric Bailey f78126e01a [🐴] State transitions (#3880)
* Handle init/resume/suspend/background and polling

* Add debug and temp guard

* Make state transitions sync

* Make init sync also

* Checkpoint: confusing but working state machine

* Reducer-esque

* Remove poll events

* Guard fetchConvo

(cherry picked from commit 8385579d31500bb4bfb60afeecdc1eb3ddd7e747)

* Clean up polling, make sync

(cherry picked from commit 7f75cd04c3bf81c94662785748698640a84bef51)

* Update history handling

(cherry picked from commit b82b552ba4040adf7ead2377541132a386964ff8)

* Check for screen focus in app state listener

* Get rid of ad-hoc status checks
2024-05-07 17:54:52 -05:00
Eric Bailey 87cb4c105e [🐴] Global event mgmt (#3897)
* Add global event bus for messages logs

* Add rev to state

* Better handle error

* Clean up polling, add backgrounding

* Add trailConvo method

* Extend polling until we're ready for this
2024-05-07 17:54:34 -05:00
Paul Frazee 0625a914bd Run intl:extract 2024-05-07 14:15:34 -07:00
Hailey 4678c4353b typo in if/else (#3899) 2024-05-07 13:17:40 -07:00
Hailey 0658dd053d create new cache key on each run when saving previous commit hash (#3898)
* create new cache key on each run

* dynamic restore-key
2024-05-07 13:08:44 -07:00
Minseo Lee c6d30f671a Remove unnecessary Trans tags (#3888) 2024-05-07 20:06:39 +01:00
Samuel Newman 7d72dfb1cb [GIFs] Restore default alt text (#3893)
* restore default alt text

* factor out gif alt logic + enable require alt text setting

* rm console.log

* don't prefill input + esc handling

* typo

* Nits

* shorten user alt prefix

* Remove unnecessary condition, rename for clarity

* Add comment

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-07 20:05:40 +01:00
Samuel Newman 77e6c75a2c Fix color of new web splash logo (#3896) 2024-05-07 19:28:51 +01:00
Minseo Lee af77574b3c Update Feed.tsx (#3715) 2024-05-07 11:09:22 -07:00
Minseo Lee b1a1ca98e8 Update Feeds.tsx (#3719) 2024-05-07 11:07:57 -07:00
kodebanget 3cca5f04d6 Update Indonesian translation (#3891)
* Update Indonesian translation

* Update id/messages.po

---------

Co-authored-by: Indonesian <github-actions@github.com>
2024-05-07 10:33:59 -07:00
Minseo Lee 7f88ec7ca5 Update WhoCanReply.tsx (#3720) 2024-05-07 10:20:05 -07:00
Hailey 790a9c4fad fix bad bool check in action (#3885)
* fix bad bool check in action

* add `fetch-depth` so we can get the commit hash

* `.env` should be in `.easignore` 🙃
2024-05-06 20:13:12 -07:00
Jan-Olof Eriksson 92f6665f93 Finnish translation update (#3755)
* Update messages.po

Translated new strings (GIF's etc) and cleaned up deprecated ones.

* Update messages.po

resolve conflict

* Update messages.po

removed double quotes. Thanks @lapanti
2024-05-06 20:08:36 -07:00
Minseo Lee 2ea9e2c929 Improve localization marks (#3285)
* Update Lightbox.tsx

* Change strings for easier localization

* Update DeleteAccount.tsx

* Update LabelsOnMeDialog.tsx

* Update FeedCard.tsx

* Update index.tsx

* Update LabelsOnMeDialog.tsx

* Update index.tsx

* Update FeedCard.tsx

* Update SelfLabel.tsx

* Update Hashtag.tsx

* Update index.tsx

* Update Hashtag.tsx

* Update ChangeHandle.tsx

* Update index.web.tsx

* Update index.web.tsx

* Update index.tsx

* Remove unnecessary `<Trans>` tags

* Update Drawer.tsx
2024-05-06 19:58:04 -07:00
Paul Frazee 4fad18b2fa Implement FeedFeedback API (#3498)
* Implement onViewableItemsChanged on List.web.tsx

* Introduce onItemSeen to List API

* Add FeedFeedback tracker

* Add clickthrough interaction tracking

* Add engagement interaction tracking

* Reduce duplicate sends, introduce a flushAndReset to be triggered on refreshes, and modify the api design a bit

* Wire up SDK types and feedContext

* Avoid needless function allocations

* Fix schema usage

* Add show more / show less buttons

* Fix minor rendering issue on mobile menu

* Wire up sendInteractions()

* Fix logic error

* Fix: it's item not uri

* Update 'seen' to mean 3 seconds on-screen with some significant portion visible

* Fix non-reactive debounce

* Move methods out

* Use a WeakSet for deduping

* Reset timeout

* 3 -> 2 seconds

* Oopsie

* Throttle instead

* Fix divider

* Remove explicit flush calls

* Rm unused

---------

Co-authored-by: dan <dan.abramov@gmail.com>
2024-05-07 03:08:33 +01:00
Paul Frazee e264dfbb87 Merge branch 'TuxPenguin09-web-loading' into main 2024-05-06 18:06:44 -07:00
Paul Frazee 032f849092 Protect against missing element 2024-05-06 18:06:31 -07:00
Paul Frazee 0a8dc289ff Merge branch 'web-loading' of https://github.com/TuxPenguin09/bsky-social-app into TuxPenguin09-web-loading 2024-05-06 17:51:51 -07:00
Paul Frazee 901feba6db Replace pluralize by plural by @tkusano (#3882)
* Replace pluralize with plural or Plural
* Replace all pluralize (defined by src/lib/strings/helpers.ts) with plural or Plural (defined by @lingui/macro) to make some UI elements translatable.
* Delete pluralize() and related test.

* Import @formatjs polyfill libraries for plural on ios and android

- ios and andorid: import `@formtjs/intl-locale` and `@formatjs/intl-pluralrules` to polyfill `Intl.Locale` and `Intl.PluralRules` which are used in `plural()` and '<Plural />'.
- update `plural` use in notification messages for better translation.

* Rewrite to pass lint

* Add Catalan plural polyfill

* more replacement

* import zh plural data for zh-CN

* Refactor feed header components (#2964)

* Move home-related files to view/com/home

* Add HomeHeader in front of FeedTabBar

* Move isDekstop check outside FeedsTabBar

* Remove PWI logic from tabbar

* Separate platform-specific layout from shared logic

* Rename Home Feed Prefs to Following Feed Prefs (#2965)

* use `useOpenLink` hook for links in ALF (#2975)

* use `useOpenLink` hook for links in ALF

* web only for `outline`

* increase timeout to 15s (#2958)

* Normalize relative day (#2874)

* fix: normalize relative date

* chore: add comments

* refactor: skip flooring normalized diff

* refactor: let -> const

* fix: get own copy of date to prevent mutating

* refactor: rounding does the same trick

* Add handle validation to create account UI (#2959)

* show uiState errors in the box as well

simplify copy

update ui for only letters and numbers

add ui validation to handle selection

* simplify names

* Fix accidental text-node render

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>

* Make dim theme dim (#2966)

* Make dim color scheme dim

* Tweaks

* Overall tweaks

* We have to go darker

* Tweak saturation of blues in dim

* Increase contrast on dark-dark mode

* adjust dim

---------

Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: Hailey <me@haileyok.com>

* Fix dim mode unread notif color

* use `showControls` to show/hide live text icon on ios (#2982)

* Update .po files

* fix reversed icons in validator 🤦 (#2991)

* Adjust `windowSize` on `PostThread` `FlatList` (#2989)

* adjust window size, cells batching period

* rm batching period change

* Pluralize 'follow(s)'

* Include a space between the msgid count and "follower(s)/following(s)" so the translator can adjust the translated count line to fit within the Drawer.

* pluralie '# following'

* Fix & Update

* Rewrite to use Plural

* rmeove unused import

* When commiting changes, disable 'simple-import-sort' plugin in .eslintrc.js to sync with bluesky-social:main

* Revert simple-import-sort/imports related changes

* Move ProfileHoverCard web to plural util

* Followings -> following

* Add plural following to hovercard

* Followings -> Following

---------

Co-authored-by: Takayuki KUSANO <kusano@tkusano.jp>
Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com>
Co-authored-by: dan <dan.abramov@gmail.com>
Co-authored-by: Hailey <me@haileyok.com>
Co-authored-by: Mary <148872143+mary-ext@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
2024-05-06 16:55:57 -07:00
Paul Frazee 2ca4b74955 Merge branch 'piotrpalek-fix-banner-cropper' into main 2024-05-06 15:49:52 -07:00
Paul Frazee fe82257801 Dont leave promise unresolved 2024-05-06 15:44:19 -07:00
Paul Frazee e1940983a3 Merge branch 'fix-banner-cropper' of https://github.com/piotrpalek/social-app into piotrpalek-fix-banner-cropper 2024-05-06 15:30:54 -07:00
Samuel Newman 136b0e12ab make gif alt text prompt selectable (#3879) 2024-05-06 22:14:00 +01:00
Hailey fdb5ffff53 remove trailing period from query term in useActorAutocompleteQuery (#3765)
* remove trailing period from query term

* Rm useMemo

---------

Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
2024-05-06 22:04:47 +01:00
Hailey b4015d10d1 Add PrivacyManifest info to comply with new App Store guidelines (#3784)
* add necessary privacy reasons

* bump expo to support creation of the manifest
2024-05-06 21:47:55 +01:00
Hailey 99f3f10fe7 A few containWeb List nits (#3877)
* use getters for returned values

* pass ref

* add log to `onScroll` in tester

* improve expect error
2024-05-06 21:45:14 +01:00
Eric Bailey 0b6ace990e [Clipclops] All my clops gone (#3850)
* Handle two common errors, provide more clarity around error states

* Handle failed polling

* Remove unused error type

* format
2024-05-06 15:35:05 -05:00
Ivan Beà 2a1dbd2756 Update catalan messages.po (#3764)
Translate new lines, messages are coming! 
You can check it @jordimas @darccio @ferranrego @MiquelAdell @mvdan @johnnydement @Mejans @surfdude29
2024-05-06 13:27:08 -07:00
Minseo Lee a9feba4efd Update Korean localization (#3809)
* Update messages.po

* Update messages.po

* Update messages.po
2024-05-06 13:26:32 -07:00
Takayuki KUSANO 5cfe5d4f58 Update Japanese translations (#3810)
* Update Japanese translations

* Updated Japanese translation

* Updated Japanese translation

* Update Japanese translations

* Updated based on @Hima-Zinn's suggestion
2024-05-06 13:25:59 -07:00
Frudrax Cheng c90443b37a Update zh-TW translations (#3873)
* 修正及改進翻譯

* Epic zh-TW rebrand

* small fix

* remove reundant "設定" for "偏好"

* legacy for "殘存"

* Update Translator

---------

Co-authored-by: Kuwa Lee <kuwalee1069@gmail.com>
2024-05-06 13:25:07 -07:00
aliamanuba 1d8fdbcc34 Add Preload for Web - Update base.html 2024-05-02 19:38:33 +08:00
aliamanuba c303df5bd6 Added Preload for Web
- Bluesky logo in the center when a new visitor or shift+refresh by browser client
2024-05-02 19:24:35 +08:00
Piotr P bf7aee19b8 add missing cropImageUtil file 2024-04-27 14:59:00 +02:00
Piotr P beddddcb57 hide alternative ratio buttons when using custom ratio 2024-04-27 14:31:51 +02:00
Piotr P bc956803b8 allow for custom cropper aspect ration based on image 2024-04-27 14:31:45 +02:00
Piotr P ebd333b331 Fix cropper crashing after clicking cancel 2024-04-27 14:31:39 +02:00
Piotr P ae26963b45 eslint autofixes 2024-04-27 14:31:33 +02:00
549 changed files with 57360 additions and 37729 deletions
-86
View File
@@ -1,86 +0,0 @@
/** @type {Detox.DetoxConfig} */
module.exports = {
testRunner: {
args: {
$0: 'jest',
config: '__e2e__/jest.config.js',
},
jest: {
setupTimeout: 120000,
},
},
apps: {
'ios.debug': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/bluesky.app',
build:
'xcodebuild -workspace ios/Bluesky.xcworkspace -scheme Bluesky -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',
},
'ios.release': {
type: 'ios.app',
binaryPath:
'ios/build/Build/Products/Release-iphonesimulator/bluesky.app',
build:
'xcodebuild -workspace ios/Bluesky.xcworkspace -scheme Bluesky -configuration Release -sdk iphonesimulator -derivedDataPath ios/build',
},
'android.debug': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
build:
'cd android ; ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug ; cd -',
reversePorts: [8081],
},
'android.release': {
type: 'android.apk',
binaryPath: 'android/app/build/outputs/apk/release/app-release.apk',
build:
'cd android ; ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release ; cd -',
},
},
devices: {
simulator: {
type: 'ios.simulator',
device: {
type: 'iPhone 15 Pro',
},
},
attached: {
type: 'android.attached',
device: {
adbName: '.*',
},
},
emulator: {
type: 'android.emulator',
device: {
avdName: 'Pixel_3a_API_30_x86',
},
},
},
configurations: {
'ios.sim.debug': {
device: 'simulator',
app: 'ios.debug',
},
'ios.sim.release': {
device: 'simulator',
app: 'ios.release',
},
'android.att.debug': {
device: 'attached',
app: 'android.debug',
},
'android.att.release': {
device: 'attached',
app: 'android.release',
},
'android.emu.debug': {
device: 'emulator',
app: 'android.debug',
},
'android.emu.release': {
device: 'emulator',
app: 'android.release',
},
},
}
+1 -2
View File
@@ -95,8 +95,7 @@ web-build/
/ios/
# environment variables
.env
.env.*
# Firebase (Android) Google services
# INCLUDED: google-services.json
# INCLUDED: google-services.json
+3 -1
View File
@@ -9,11 +9,11 @@ module.exports = {
parser: '@typescript-eslint/parser',
plugins: [
'@typescript-eslint',
'detox',
'react',
'lingui',
'simple-import-sort',
'bsky-internal',
'eslint-plugin-react-compiler',
],
rules: {
// Temporary until https://github.com/facebook/react-native/pull/43756 gets into a release.
@@ -68,6 +68,8 @@ module.exports = {
},
],
'simple-import-sort/exports': 'warn',
// TODO: Reenable when we figure out why it gets stuck on CI.
// 'react-compiler/react-compiler': 'error',
},
ignorePatterns: [
'**/__mocks__/*.ts',
@@ -43,6 +43,10 @@ jobs:
tags: |
type=sha,enable=true,priority=100,prefix=,suffix=,format=long
- name: Set outputs
id: vars
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v4
@@ -54,6 +58,5 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
env:
EXPO_PUBLIC_BUNDLE_IDENTIFIER: $(git rev-parse --short HEAD)
EXPO_PUBLIC_BUNDLE_DATE: $(date -u +"%y%m%d%H")
build-args: |
EXPO_PUBLIC_BUNDLE_IDENTIFIER=${{ steps.vars.outputs.sha_short }}
@@ -25,6 +25,8 @@ jobs:
- name: ⬇️ Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
- name: 🔧 Setup Node
uses: actions/setup-node@v4
@@ -117,3 +119,41 @@ jobs:
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CLIENT_ALERT_WEBHOOK }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
- 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
- name: 🚀 Upload Production APK Artifact
id: upload-artifact-production-apk
if: ${{ inputs.profile == 'production' }}
uses: actions/upload-artifact@v4
with:
retention-days: 30
compression-level: 6
name: build-${{ steps.timestamp.outputs.time }}.apk
path: build.apk
- name: 🔔 Notify Slack of Production APK Build
if: ${{ inputs.profile == 'production' }}
uses: slackapi/slack-github-action@v1.25.0
with:
payload: |
{
"text": "Android production APK build is ready for download. This is a production build, and you should add it to the GitHub release! Download the artifact here: ${{ steps.upload-artifact-production-apk.outputs.artifact-url }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CLIENT_ALERT_WEBHOOK }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
- name: ⬇️ Restore Cache
id: get-base-commit
uses: actions/cache@v4
if: ${{ inputs.profile == 'testflight' }}
with:
path: most-recent-testflight-commit.txt
key: most-recent-testflight-commit
- name: ✏️ Write commit hash to cache
if: ${{ inputs.profile == 'testflight' }}
run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
+18
View File
@@ -25,6 +25,8 @@ jobs:
- name: ⬇️ Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
- name: 🔧 Setup Node
uses: actions/setup-node@v4
@@ -45,6 +47,10 @@ jobs:
- name: ⚙️ Install dependencies
run: yarn install
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '15.3'
- name: ☕️ Setup Cocoapods
uses: maxim-lobanov/setup-cocoapods@v1
with:
@@ -74,3 +80,15 @@ jobs:
- name: 🚀 Deploy
run: eas submit -p ios --non-interactive --path build.ipa
- name: ⬇️ Restore Cache
id: get-base-commit
uses: actions/cache@v4
if: ${{ inputs.profile == 'testflight' }}
with:
path: most-recent-testflight-commit.txt
key: most-recent-testflight-commit
- name: ✏️ Write commit hash to cache
if: ${{ inputs.profile == 'testflight' }}
run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
+57 -61
View File
@@ -26,7 +26,7 @@ jobs:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}-deploy
cancel-in-progress: true
outputs:
fingerprint-is-different: ${{ steps.fingerprint-debug.outputs.fingerprint-is-different }}
changes-detected: ${{ steps.fingerprint.outputs.includes-changes }}
steps:
- name: Check for EXPO_TOKEN
@@ -49,67 +49,22 @@ jobs:
with:
fetch-depth: 0
- name: ⬇️ Get last successful deployment commit from the cache
id: get-base-commit
uses: actions/cache@v4
with:
path: last-successful-commit-hash.txt
key: last-successful-deployment-commit-${{ github.ref_name }}
- name: Add the last successful deployment commit to the output
id: last-successful-commit
run: echo base-commit=$(cat last-successful-commit-hash.txt) >> "$GITHUB_OUTPUT"
- name: ⬇️ Fetch commits from base branch
if: ${{ github.ref != 'refs/heads/main' }}
run: git fetch origin main:main --depth 100
# This should get the current production release's commit's hash to see if the update is compatible
- name: 🕵️ Get the base commit
id: base-commit
run: |
if [ -z "${{ inputs.channel == 'production' }}" ]; then
echo base-commit=$(git show-ref -s ${{ inputs.runtimeVersion }}) >> "$GITHUB_OUTPUT"
else
echo base-commit=${{ steps.last-successful-commit.base-commit }} >> "$GITHUB_OUTPUT"
fi
- name: ✓ Make sure we found a base commit
run: |
if [ -z "${{ steps.base-commit.outputs.base-commit }}" && ${{ inputs.channel == 'production' }} ]; then
echo "Could not find a base commit for this release. Exiting."
exit 1
fi
- name: 🔧 Setup Node
uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: yarn
- name: ⚙️ Install Dependencies
run: yarn install
# Run the fingerprint
- name: 📷 Check fingerprint
- name: 📷 Check fingerprint and install dependencies
id: fingerprint
uses: expo/expo-github-action/fingerprint@main
uses: bluesky-social/github-actions/fingerprint-native@main
with:
previous-git-commit: ${{ steps.base-commit.outputs.base-commit }}
- name: 👀 Debug fingerprint
id: fingerprint-debug
run: |
echo "previousGitCommit=${{ steps.fingerprint.outputs.previous-git-commit }} currentGitCommit=${{ steps.fingerprint.outputs.current-git-commit }}"
echo "isPreviousFingerprintEmpty=${{ steps.fingerprint.outputs.previous-fingerprint == '' }}"
fingerprintDiff='$(echo "${{ steps.fingerprint.outputs.fingerprint-diff }}")'
if [[ $fingerprintDiff =~ "bareRncliAutolinking" || $fingerprintDiff =~ "expoAutolinkingAndroid" || $fingerprintDiff =~ "expoAutolinkingIos" ]]; then
echo fingerprint-is-different="true" >> "$GITHUB_OUTPUT"
else
echo fingerprint-is-different="false" >> "$GITHUB_OUTPUT"
fi
profile: ${{ inputs.channel || 'testflight' }}
previous-commit-tag: ${{ inputs.runtimeVersion }}
- name: Lint check
run: yarn lint
@@ -125,22 +80,22 @@ jobs:
- name: 🔨 Setup EAS
uses: expo/expo-github-action@v8
if: ${{ steps.fingerprint-debug.outputs.fingerprint-is-different == 'false'}}
if: ${{ !steps.fingerprint.outputs.includes-changes }}
with:
expo-version: latest
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: ⛏️ Setup Expo
if: ${{ steps.fingerprint-debug.outputs.fingerprint-is-different == 'false'}}
if: ${{ !steps.fingerprint.outputs.includes-changes }}
run: yarn global add eas-cli-local-build-plugin
- name: 🪛 Setup jq
if: ${{ steps.fingerprint-debug.outputs.fingerprint-is-different == 'false'}}
if: ${{ !steps.fingerprint.outputs.includes-changes }}
uses: dcarbone/install-jq-action@v2
- name: ✏️ Write environment variables
if: ${{ steps.fingerprint-debug.outputs.fingerprint-is-different == 'false'}}
if: ${{ !steps.fingerprint.outputs.includes-changes }}
run: |
export json='${{ secrets.GOOGLE_SERVICES_TOKEN }}'
echo "${{ secrets.ENV_TOKEN }}" > .env
@@ -149,19 +104,28 @@ jobs:
echo "$json" > google-services.json
- name: 🏗️ Create Bundle
if: ${{ steps.fingerprint-debug.outputs.fingerprint-is-different == 'false'}}
if: ${{ !steps.fingerprint.outputs.includes-changes }}
run: EXPO_PUBLIC_ENV="${{ inputs.channel || 'testflight' }}" yarn export
- name: 📦 Package Bundle and 🚀 Deploy
if: ${{ steps.fingerprint-debug.outputs.fingerprint-is-different == 'false'}}
if: ${{ !steps.fingerprint.outputs.includes-changes }}
run: yarn use-build-number bash scripts/bundleUpdate.sh
env:
DENIS_API_KEY: ${{ secrets.DENIS_API_KEY }}
RUNTIME_VERSION: ${{ inputs.runtimeVersion }}
CHANNEL_NAME: ${{ inputs.channel || 'testflight' }}
- name: Save successful deployment commit hash
run: echo ${{ steps.fingerprint.outputs.current-git-commit }} > last-successful-commit-hash.txt
- name: ⬇️ Restore Cache
id: get-base-commit
uses: actions/cache@v4
if: ${{ !steps.fingerprint.outputs.includes-changes }}
with:
path: most-recent-testflight-commit.txt
key: most-recent-testflight-commit
- name: ✏️ Write commit hash to cache
if: ${{ !steps.fingerprint.outputs.includes-changes }}
run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
# GitHub actions are horrible so let's just copy paste this in
buildIfNecessaryIOS:
@@ -169,11 +133,11 @@ jobs:
runs-on: macos-14
concurrency:
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}-build-ios
cancel-in-progress: false
cancel-in-progress: true
needs: [bundleDeploy]
# Gotta check if its NOT '[]' because any md5 hash in the outputs is detected as a possible secret and won't be
# available here
if: ${{ inputs.channel != 'production' && needs.bundleDeploy.outputs.fingerprint-is-different == 'true' }}
if: ${{ inputs.channel != 'production' && needs.bundleDeploy.outputs.changes-detected }}
steps:
- name: Check for EXPO_TOKEN
run: >
@@ -184,6 +148,8 @@ jobs:
- name: ⬇️ Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
- name: 🔧 Setup Node
uses: actions/setup-node@v4
@@ -204,6 +170,10 @@ jobs:
- name: ⚙️ Install dependencies
run: yarn install
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '15.3'
- name: ☕️ Setup Cocoapods
uses: maxim-lobanov/setup-cocoapods@v1
with:
@@ -234,6 +204,18 @@ jobs:
- name: 🚀 Deploy
run: eas submit -p ios --non-interactive --path build.ipa
- name: ⬇️ Restore Cache
id: get-base-commit
uses: actions/cache@v4
if: ${{ inputs.channel == 'testflight' }}
with:
path: most-recent-testflight-commit.txt
key: most-recent-testflight-commit
- name: ✏️ Write commit hash to cache
if: ${{ inputs.channel == 'testflight' }}
run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
buildIfNecessaryAndroid:
name: Build and Submit Android
runs-on: ubuntu-latest
@@ -243,7 +225,7 @@ jobs:
needs: [ bundleDeploy ]
# Gotta check if its NOT '[]' because any md5 hash in the outputs is detected as a possible secret and won't be
# available here
if: ${{ inputs.channel != 'production' && needs.bundleDeploy.outputs.fingerprint-is-different == 'true' }}
if: ${{ inputs.channel != 'production' && needs.bundleDeploy.outputs.changes-detected }}
steps:
- name: Check for EXPO_TOKEN
@@ -255,6 +237,8 @@ jobs:
- name: ⬇️ Checkout
uses: actions/checkout@v4
with:
fetch-depth: 5
- name: 🔧 Setup Node
uses: actions/setup-node@v4
@@ -319,3 +303,15 @@ jobs:
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CLIENT_ALERT_WEBHOOK }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
- name: ⬇️ Restore Cache
id: get-base-commit
uses: actions/cache@v4
if: ${{ inputs.channel != 'testflight' && inputs.channel != 'production' }}
with:
path: most-recent-testflight-commit.txt
key: most-recent-testflight-commit
- name: ✏️ Write commit hash to cache
if: ${{ inputs.channel != 'testflight' && inputs.channel != 'production' }}
run: echo ${{ github.sha }} > most-recent-testflight-commit.txt
+11 -24
View File
@@ -1,7 +1,7 @@
# Credit for fingerprint action https://github.com/expo/expo
# https://github.com/expo/expo/blob/main/.github/workflows/pr-labeler.yml
---
name: PR labeler
name: PR Tests
on:
push:
@@ -21,7 +21,7 @@ permissions:
jobs:
webpack-analyzer:
runs-on: ubuntu-22.04
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.event_name == 'pull_request'}}
steps:
- name: ⬇️ Checkout
uses: actions/checkout@v4
@@ -94,10 +94,9 @@ jobs:
| ${{ steps.get-diff.outputs.base_file_string }} | ${{ steps.get-diff.outputs.pr_file_string }} | ${{ steps.get-diff.outputs.diff_file_string }} (${{ steps.get-diff.outputs.percent }}%) |
---
test-suite-fingerprint:
fingerprint-native:
runs-on: ubuntu-22.04
if: ${{ github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'push' }}
concurrency: fingerprint-${{ github.event_name != 'pull_request' && 'main' || github.run_id }}
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.event_name == 'pull_request'}}
steps:
- name: ⬇️ Checkout
uses: actions/checkout@v4
@@ -114,35 +113,23 @@ jobs:
node-version-file: .nvmrc
cache: yarn
- name: ⚙️ Install Dependencies
run: yarn install
- name: Get the base commit
id: base-commit
run: echo base-commit=$(git log -n 1 main --pretty=format:'%H') >> "$GITHUB_OUTPUT"
- name: 📷 Check fingerprint
- name: 📷 Check fingerprint and install dependencies
id: fingerprint
uses: expo/expo-github-action/fingerprint@main
uses: bluesky-social/github-actions/fingerprint-native@main
with:
previous-git-commit: ${{ steps.base-commit.outputs.base-commit }}
- name: 👀 Debug fingerprint
run: |
echo "previousGitCommit=${{ steps.fingerprint.outputs.previous-git-commit }} currentGitCommit=${{ steps.fingerprint.outputs.current-git-commit }}"
echo "isPreviousFingerprintEmpty=${{ steps.fingerprint.outputs.previous-fingerprint == '' }}"
profile: pull-request
- name: 💬 Drop a comment
uses: marocchino/sticky-pull-request-comment@v2
if: ${{ github.event_name == 'pull_request' && steps.fingerprint.outputs.fingerprint-diff != '[]' }}
if: ${{ steps.fingerprint.outputs.includes-changes }}
with:
header: fingerprint-diff
message: |
The Pull Request introduced fingerprint changes against the base commit: ${{ steps.fingerprint.outputs.previous-git-commit }}
The Pull Request introduced fingerprint changes against the base commit:
<details><summary>Fingerprint diff</summary>
```json
${{ steps.fingerprint.outputs.fingerprint-diff }}
${{ steps.fingerprint.outputs.diff }}
```
</details>
@@ -152,7 +139,7 @@ jobs:
- name: 💬 Delete comment
uses: marocchino/sticky-pull-request-comment@v2
if: ${{ github.event_name == 'pull_request' && steps.fingerprint.outputs.fingerprint-diff == '[]' }}
if: ${{ !steps.fingerprint.outputs.includes-changes }}
with:
header: fingerprint-diff
delete: true
+1
View File
@@ -12,3 +12,4 @@
android
ios
src/locale/locales
lib/react-compiler-runtime
+8 -1
View File
@@ -15,6 +15,10 @@ 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}
COPY . .
#
@@ -29,10 +33,13 @@ RUN mkdir --parents $NVM_DIR && \
RUN \. "$NVM_DIR/nvm.sh" && \
nvm install $NODE_VERSION && \
nvm use $NODE_VERSION && \
echo "Using bundle identifier: $EXPO_PUBLIC_BUNDLE_IDENTIFIER" && \
echo "EXPO_PUBLIC_BUNDLE_IDENTIFIER=$EXPO_PUBLIC_BUNDLE_IDENTIFIER" >> .env && \
echo "EXPO_PUBLIC_BUNDLE_DATE=$(date -u +"%y%m%d%H")" >> .env && \
npm install --global yarn && \
yarn && \
yarn intl:build && \
yarn build-web
EXPO_PUBLIC_BUNDLE_IDENTIFIER=$EXPO_PUBLIC_BUNDLE_IDENTIFIER EXPO_PUBLIC_BUNDLE_DATE=$() yarn build-web
# DEBUG
RUN find ./bskyweb/static && find ./web-build/static
+2
View File
@@ -0,0 +1,2 @@
flows:
- "flows/*"
+30
View File
@@ -0,0 +1,30 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: ?users
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
# Post an image with the porn label
- tapOn:
id: "composeFAB"
- inputText: "Post with an image"
- tapOn:
id: "openGalleryBtn"
- tapOn:
id: "labelsBtn"
- tapOn:
label: "Tap on porn"
point: 78%,67%
- tapOn:
label: "Tap on confirm"
point: 51%,92%
- tapOn:
id: "composerPublishBtn"
- tapOn:
id: "e2eRefreshHome"
- assertVisible: "Adult Content"
+87
View File
@@ -0,0 +1,87 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: ?users
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "composeFAB"
- inputText: "Post text only"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
id: "composeFAB"
- tapOn:
id: "composeFAB"
- inputText: "Post with an image"
- tapOn:
id: "openGalleryBtn"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
id: "composeFAB"
- tapOn:
id: "composeFAB"
- inputText: "Post with a https://example.com link card"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
id: "composeFAB"
- tapOn:
id: "e2eRefreshHome"
- tapOn:
id: "replyBtn"
- inputText: "Reply text only"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
id: "composeFAB"
- tapOn:
id: "replyBtn"
- inputText: "Reply with an image"
- tapOn:
id: "openGalleryBtn"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
id: "composeFAB"
- tapOn:
id: "replyBtn"
- inputText: "Reply with a https://example.com link card"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
id: "composeFAB"
- tapOn:
id: "repostBtn"
- tapOn:
id: "quoteBtn"
- inputText: "QP text only"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
id: "composeFAB"
- tapOn:
id: "repostBtn"
- tapOn:
id: "quoteBtn"
- inputText: "QP with an image"
- tapOn:
id: "openGalleryBtn"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
id: "composeFAB"
- tapOn:
id: "repostBtn"
- tapOn:
id: "quoteBtn"
- inputText: "QP with a https://example.com link card"
- tapOn:
id: "composerPublishBtn"
- assertVisible:
id: "composeFAB"
+37
View File
@@ -0,0 +1,37 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: ""
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eOpenLoggedOutView"
- tapOn:
id: "createAccountButton"
- tapOn:
id: "selectServiceButton"
- tapOn:
id: "customSelectBtn"
- tapOn:
id: "customServerTextInput"
- inputText: "http://localhost:3000"
- pressKey: Enter
- tapOn:
id: "doneBtn"
- tapOn:
id: "emailInput"
- inputText: "example@test.com"
- tapOn:
id: "passwordInput"
- inputText: "hunter2"
- pressKey: Enter
- tapOn:
id: "nextBtn"
- tapOn:
id: "handleInput"
- inputText: "e2e-test"
- tapOn:
id: "nextBtn"
+208
View File
@@ -0,0 +1,208 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&follows&posts"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
label: "Create a curate list"
id: "e2eGotoLists"
- tapOn:
id: "newUserListBtn"
- assertVisible:
id: "createOrEditListModal"
- tapOn:
id: "editNameInput"
- inputText: "Good Ppl"
- tapOn:
id: "editDescriptionInput"
- inputText: "They good"
- tapOn: "Save"
- tapOn: "Save"
- assertNotVisible:
id: "createOrEditListModal"
- tapOn: "About"
- assertVisible: "Good Ppl"
- assertVisible: "They good"
- tapOn:
label: "Edit display name and description via the edit curatelist modal"
point: "90%,9%"
- tapOn: "Edit list details"
- assertVisible:
id: "createOrEditListModal"
- tapOn:
id: "editNameInput"
- eraseText
- inputText: "Bad Ppl"
- hideKeyboard
- tapOn:
id: "editDescriptionInput"
- eraseText
- inputText: "They bad"
- tapOn: "Save"
- tapOn: "Save"
- assertNotVisible:
id: "createOrEditListModal"
- assertVisible: Bad Ppl
- assertVisible: They bad
- tapOn:
label: "Remove description via the edit curatelist modal"
point: "90%,9%"
- tapOn: "Edit list details"
- assertVisible:
id: "createOrEditListModal"
- tapOn:
id: "editDescriptionInput"
- eraseText
- tapOn: "Save"
- tapOn: "Save"
- assertNotVisible:
id: "createOrEditListModal"
- assertNotVisible:
id: "listDescription"
- tapOn:
label: "Delete the curatelist"
point: "90%,9%"
- tapOn: "Delete List"
- tapOn:
id: "confirmBtn"
- assertVisible:
id: "listsEmpty"
- tapOn:
label: "Create a new curatelist"
id: "e2eGotoLists"
- tapOn:
id: "newUserListBtn"
- assertVisible:
id: "createOrEditListModal"
- tapOn:
id: "editNameInput"
- inputText: "Good Ppl"
- tapOn:
id: "editDescriptionInput"
- inputText: "They good"
- tapOn: "Save"
- tapOn: "Save"
- assertNotVisible:
id: "createOrEditListModal"
- tapOn: "About"
- assertVisible: "Good Ppl"
- assertVisible: "They good"
- tapOn: "About"
- tapOn:
label: "Adds users on curatelists from the list"
id: "addUserBtn"
- assertVisible:
id: "listAddUserModal"
- tapOn:
id: "searchInput"
- inputText: "b"
- pressKey: Enter
- tapOn:
id: "user-bob.test-addBtn"
- tapOn:
id: "doneBtn"
- assertNotVisible:
id: "listAddUserModal"
- assertVisible:
id: "user-bob.test"
- tapOn: "Posts"
- assertVisible:
label: "Shows posts by the users in the list"
id: "feedItem-by-bob.test"
- tapOn:
label: "Pins the list"
id: "pinBtn"
- tapOn:
id: "e2eGotoHome"
- tapOn: "Good Ppl"
- assertVisible:
id: "feedItem-by-bob.test"
- tapOn:
id: "e2eGotoFeeds"
- tapOn:
id: "saved-feed-Good Ppl"
- assertVisible:
id: "feedItem-by-bob.test"
- tapOn:
id: "unpinBtn"
- tapOn:
id: "bottomBarHomeBtn"
- assertNotVisible:
id: "homeScreenFeedTabs-Good Ppl"
- tapOn:
id: "e2eGotoLists"
- tapOn:
id: "list-Good Ppl"
- tapOn: "About"
- assertVisible:
label: "Removes users on curatelists from the list"
id: "user-bob.test"
- tapOn:
point: "90%,43%"
- assertVisible:
id: "userAddRemoveListsModal"
- tapOn:
id: "user-bob.test-addBtn"
- tapOn:
id: "doneBtn"
- assertNotVisible:
id: "userAddRemoveListsModal"
- tapOn:
label: "Shows the curatelist on my profile"
id: "bottomBarProfileBtn"
- swipe:
from:
id: "profilePager-selector"
direction: LEFT
- tapOn:
id: "profilePager-selector-5"
- tapOn:
id: "list-Good Ppl"
- tapOn:
label: "Adds and removes users on curatelists from the profile"
id: "bottomBarSearchBtn"
- tapOn:
id: "searchTextInput"
- inputText: "bob"
- tapOn:
id: "searchAutoCompleteResult-bob.test"
- assertVisible:
id: "profileView"
- tapOn:
id: "profileHeaderDropdownBtn"
- tapOn: "Add to Lists"
- assertVisible:
id: "userAddRemoveListsModal"
- tapOn:
id: "user-bob.test-addBtn"
- tapOn:
id: "doneBtn"
- assertNotVisible:
id: "userAddRemoveListsModal"
- tapOn:
id: "profileHeaderDropdownBtn"
- tapOn: "Add to Lists"
- assertVisible:
id: "userAddRemoveListsModal"
- tapOn:
id: "user-bob.test-addBtn"
- tapOn:
id: "doneBtn"
- assertNotVisible:
id: "userAddRemoveListsModal"
+82
View File
@@ -0,0 +1,82 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: ?users&follows&posts&feeds
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
# Pin alice's feed
- tapOn:
id: "bottomBarProfileBtn"
- swipe:
from:
id: "profilePager-selector"
direction: LEFT
- tapOn:
id: "profilePager-selector-4"
- tapOn:
id: "feed-alice-favs"
- tapOn: "Pin to Home"
- tapOn:
id: "bottomBarHomeBtn"
- assertNotVisible: "Feeds ✨"
- assertVisible:
id: "homeScreenFeedTabs-selector-0"
text: "Following"
- assertVisible:
id: "homeScreenFeedTabs-selector-1"
text: "alice-favs"
# Set alice-favs first
- tapOn:
id: "viewHeaderDrawerBtn"
- tapOn:
id: "menuItemButton-Feeds"
- tapOn: "Edit Saved Feeds"
- tapOn:
label: "Tap on down arrow"
point: "79%,23%"
- tapOn:
id: "bottomBarHomeBtn"
- assertVisible:
id: "homeScreenFeedTabs-selector-0"
text: "alice-favs"
- assertVisible:
id: "homeScreenFeedTabs-selector-1"
text: "Following"
# Set following first
- tapOn:
id: "viewHeaderDrawerBtn"
- tapOn:
id: "menuItemButton-Feeds"
- tapOn:
label: "Tap on down arrow"
point: "79%,23%"
- tapOn:
id: "bottomBarHomeBtn"
- assertVisible:
id: "homeScreenFeedTabs-selector-0"
text: "Following"
- assertVisible:
id: "homeScreenFeedTabs-selector-1"
text: "alice-favs"
# Remove following
- tapOn:
id: "viewHeaderDrawerBtn"
- tapOn:
id: "menuItemButton-Feeds"
- tapOn:
label: "Tap on unpin"
point: "91%,23%"
- tapOn:
id: "bottomBarHomeBtn"
- assertVisible:
id: "homeScreenFeedTabs-selector-0"
text: "alice-favs"
- assertNotVisible: "Following"
+63
View File
@@ -0,0 +1,63 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: ?users&follows&posts&feeds
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
label: "Can go to feeds page using feeds button in tab bar"
text: "Feeds ✨"
- assertVisible: "Discover New Feeds"
- tapOn:
label: "Feeds button disappears after pinning a feed"
id: "bottomBarProfileBtn"
- swipe:
from:
id: "profilePager-selector"
direction: LEFT
- tapOn:
id: "profilePager-selector-4"
- tapOn:
id: "feed-alice-favs"
- tapOn: "Pin to Home"
- tapOn:
id: "bottomBarHomeBtn"
- assertNotVisible: "Feeds ✨"
- tapOn:
label: "Can like posts"
id: "likeBtn"
- assertVisible:
id: "likeCount"
text: "1"
- tapOn:
id: "likeBtn"
- assertNotVisible:
id: "likeCount"
- tapOn:
label: "Can repost posts"
id: "repostBtn"
- tapOn: "Repost"
- assertVisible:
id: "repostCount"
text: "1"
- tapOn:
id: "repostBtn"
- tapOn: "Undo repost"
- assertNotVisible:
id: "repostCount"
- tapOn:
label: "Can delete posts"
id: "postDropdownBtn"
childOf:
id: "feedItem-by-alice.test"
- tapOn: "Delete post"
- tapOn: "Delete"
+26
View File
@@ -0,0 +1,26 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eOpenLoggedOutView"
- tapOn: "Sign in"
- tapOn:
id: "selectServiceButton"
- tapOn: "Custom"
- tapOn:
id: "customServerTextInput"
- inputText: "http://localhost:3000"
- tapOn: "Done"
- tapOn:
id: "loginUsernameInput"
- inputText: "Alice"
- tapOn:
id: "loginPasswordInput"
- inputText: "hunter2"
- pressKey: Enter
- assertVisible: "Following"
+45
View File
@@ -0,0 +1,45 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&follows&labels"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
# create a modlist
- tapOn:
id: "e2eGotoModeration"
- tapOn:
id: "moderationlistsBtn"
- tapOn: "New"
- tapOn:
id: "editNameInput"
- inputText: "Muted Users"
- tapOn:
id: "editDescriptionInput"
- inputText: "Shhh"
- tapOn: "Save"
- tapOn: "Save"
# view modlist
- assertVisible: "Muted Users"
- assertVisible: "Shhh"
# toggle mute subscription
- tapOn:
point: "70%,9%"
- tapOn: "Mute accounts"
- tapOn: "Mute list"
- tapOn: "Unmute"
# toggle block subscription
- tapOn:
point: "70%,9%"
- tapOn: "Block accounts"
- tapOn: "Block list"
- tapOn: "Unblock"
# the rest of the behaviors are tested in curate-lists.yml
@@ -0,0 +1,32 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "e2eStartOnboarding"
- tapOn: "Open avatar creator"
- tapOn: "Select the zap emoji as your avatar"
- tapOn:
label: "Tap on yellow"
point: "23%,79%"
- tapOn: "Done"
- waitForAnimationToEnd
- tapOn: "Select an avatar"
- tapOn: "Select the atom emoji as your avatar"
- tapOn: "Done"
- waitForAnimationToEnd
- tapOn: "Continue to next step"
- assertVisible: "What are your interests?"
- tapOn:
label: "Tap on continue"
point: "50%,92%"
- assertVisible: "You're ready to go!"
- tapOn:
label: "Tap on Lets go"
point: "50%,92%"
+31
View File
@@ -0,0 +1,31 @@
# Remove this test when the old onboarding is deprecated
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "e2eStartLongboarding"
- tapOn: "Continue to next step"
- tapOn: "Continue to the next step without following any accounts"
- tapOn: Show replies in Following feed
- tapOn: Show quote-posts in Following feed
- tapOn: Show re-posts in Following feed
- tapOn: Show replies in Following feed
- waitForAnimationToEnd
- tapOn: Continue to next step
- waitForAnimationToEnd
- tapOn: "Continue to the next step"
- waitForAnimationToEnd
- tapOn: Continue to next step
- waitForAnimationToEnd
- tapOn: Continue to next step
- waitForAnimationToEnd
- tapOn: "Complete onboarding and start using your account"
- waitForAnimationToEnd
- assertVisible: Following
+28
View File
@@ -0,0 +1,28 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "e2eStartOnboarding"
- tapOn: "Select an avatar"
- waitForAnimationToEnd
- tapOn:
point: "16%,22%"
- waitForAnimationToEnd
- tapOn: "Choose"
- waitForAnimationToEnd
- tapOn: "Continue to next step"
- assertVisible: "What are your interests?"
- tapOn:
label: "Tap on continue"
point: "50%,92%"
- assertVisible: "You're ready to go!"
- tapOn:
label: "Tap on Lets go"
point: "50%,92%"
+125
View File
@@ -0,0 +1,125 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&posts&feeds"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
# Navigate to my profile
- tapOn:
id: "bottomBarProfileBtn"
# Can see feeds
- swipe:
from:
id: "profilePager-selector"
direction: LEFT
- tapOn:
id: "profilePager-selector-4"
- assertVisible:
id: "feed-alice-favs"
- swipe:
from:
id: "profilePager-selector"
direction: RIGHT
- tapOn:
id: "profilePager-selector-0"
# Open and close edit profile modal
- tapOn:
id: "profileHeaderEditProfileButton"
- assertVisible:
id: "editProfileModal"
- tapOn:
id: "editProfileCancelBtn"
- assertNotVisible:
id: "editProfileModal"
# Edit display name and description via the edit profile modal
- tapOn:
id: "profileHeaderEditProfileButton"
- assertVisible:
id: "editProfileModal"
- tapOn:
id: "editProfileDisplayNameInput"
- eraseText
- inputText: "Alicia"
- tapOn:
id: "editProfileDescriptionInput"
- eraseText
- inputText: "One cool hacker"
- tapOn: "Description"
- tapOn:
id: "editProfileSaveBtn"
- assertNotVisible:
id: "editProfileModal"
- assertVisible: "Alicia"
- assertVisible: "One cool hacker"
# Remove display name and description via the edit profile modal
- tapOn:
id: "profileHeaderEditProfileButton"
- assertVisible:
id: "editProfileModal"
- tapOn:
id: "editProfileDisplayNameInput"
- eraseText
- tapOn:
id: "editProfileDescriptionInput"
- eraseText
- tapOn: "Description"
- tapOn:
id: "editProfileSaveBtn"
- assertNotVisible:
id: "editProfileModal"
- assertVisible: "alice.test"
- assertNotVisible: "One cool hacker"
# Set avi and banner via the edit profile modal
- assertVisible:
id: "userBannerFallback"
- tapOn:
id: "profileHeaderEditProfileButton"
- assertVisible:
id: "editProfileModal"
- tapOn:
id: "changeBannerBtn"
- tapOn: "Upload from Library"
- waitForAnimationToEnd
- tapOn: "Choose"
- waitForAnimationToEnd
- tapOn:
id: "changeAvatarBtn"
- tapOn: "Upload from Library"
- waitForAnimationToEnd
- tapOn: "Choose"
- waitForAnimationToEnd
- tapOn:
id: "editProfileSaveBtn"
- assertNotVisible:
id: "editProfileModal"
- assertVisible:
id: "userBannerImage"
# # Remove avi and banner via the edit profile modal
- tapOn:
id: "profileHeaderEditProfileButton"
- assertVisible:
id: "editProfileModal"
- tapOn:
id: "changeBannerBtn"
- tapOn: "Remove Banner"
- tapOn:
id: "changeAvatarBtn"
- tapOn: "Remove Avatar"
- tapOn:
id: "editProfileSaveBtn"
- assertNotVisible:
id: "editProfileModal"
- assertVisible:
id: "userBannerFallback"
+37
View File
@@ -0,0 +1,37 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&posts&feeds"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
# Navigate to another user profile
- tapOn:
id: "bottomBarSearchBtn"
- tapOn:
id: "searchTextInput"
- inputText: "b"
- tapOn:
id: "searchAutoCompleteResult-bob.test"
- assertVisible:
id: "profileView"
# Can follow/unfollow another user
- tapOn:
id: "followBtn"
- tapOn:
id: "unfollowBtn"
# Can mute/unmute another user
- tapOn:
id: "profileHeaderDropdownBtn"
- tapOn: "Mute Account"
- assertVisible: "Account Muted"
- tapOn:
id: "profileHeaderDropdownBtn"
- tapOn: "Unmute Account"
- assertNotVisible: "Account Muted"
+22
View File
@@ -0,0 +1,22 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
# Navigate to another user profile via autocomplete
- tapOn:
id: "bottomBarSearchBtn"
- tapOn:
id: "searchTextInput"
- inputText: "b"
- tapOn:
id: "searchAutoCompleteResult-bob.test"
- assertVisible:
id: "profileView"
+82
View File
@@ -0,0 +1,82 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&follows"
- runFlow:
file: ../setupApp.yml
# Login, create a thread, and log out
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "composeFAB"
- inputText: "Test thread"
- tapOn:
id: "composerPublishBtn"
# Login, reply to the thread, and log out
- tapOn:
id: "e2eSignInBob"
- tapOn:
id: "replyBtn"
- inputText: "Reply 1"
- tapOn:
id: "composerPublishBtn"
# Login, confirm notification exists, mute thread, and log out
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "bottomBarNotificationsBtn"
- assertVisible:
id: "feedItem-by-bob.test"
- tapOn:
id: "feedItem-by-bob.test"
- tapOn:
id: "postDropdownBtn"
childOf:
id: "postThreadItem-by-bob.test"
- tapOn: "Mute thread"
# Login, reply to the thread twice, and log out
- tapOn:
id: "e2eSignInBob"
- tapOn:
id: "bottomBarProfileBtn"
- tapOn:
id: "profilePager-selector-1"
- tapOn:
id: "replyBtn"
- inputText: "Reply 2"
- tapOn:
id: "composerPublishBtn"
- tapOn:
id: "replyBtn"
- inputText: "Reply 3"
- tapOn:
id: "composerPublishBtn"
# Login, confirm notifications dont exist, unmute the thread, confirm notifications exist
- tapOn:
id: "e2eSignInAlice"
- tapOn:
id: "bottomBarNotificationsBtn"
- assertNotVisible:
id: "feedItem-by-bob.test"
- tapOn:
id: "bottomBarHomeBtn"
- tapOn:
id: "postDropdownBtn"
- tapOn: "Unmute thread"
- tapOn:
id: "bottomBarNotificationsBtn"
- swipe:
from:
id: "notifsFeed"
direction: DOWN
- assertVisible:
id: "feedItem-by-bob.test"
+84
View File
@@ -0,0 +1,84 @@
appId: xyz.blueskyweb.app
---
- runScript:
file: ../setupServer.js
env:
SERVER_PATH: "?users&follows&thread"
- runFlow:
file: ../setupApp.yml
- tapOn:
id: "e2eSignInAlice"
# Navigate to thread
- tapOn: "Thread root"
- assertVisible: "Thread reply"
# Can like the root post
- tapOn:
id: "likeBtn"
childOf:
id: "postThreadItem-by-bob.test"
- assertVisible:
id: "likeCount-expanded"
- tapOn:
id: "likeBtn"
childOf:
id: "postThreadItem-by-bob.test"
- assertNotVisible:
id: "likeCount-expanded"
# Can like a reply post
- tapOn:
id: "likeBtn"
childOf:
id: "postThreadItem-by-carla.test"
- assertVisible:
id: "likeCount"
childOf:
id: "postThreadItem-by-carla.test"
- tapOn:
id: "likeBtn"
childOf:
id: "postThreadItem-by-carla.test"
- assertNotVisible:
id: "likeCount"
childOf:
id: "postThreadItem-by-carla.test"
# Can repost the root post
- tapOn:
id: "repostBtn"
childOf:
id: "postThreadItem-by-bob.test"
- tapOn: "Repost"
- assertVisible:
id: "repostCount-expanded"
- tapOn:
id: "repostBtn"
childOf:
id: "postThreadItem-by-bob.test"
- tapOn: "Undo repost"
- assertNotVisible:
id: "repostCount-expanded"
# Can repost a reply post
- tapOn:
id: "repostBtn"
childOf:
id: "postThreadItem-by-carla.test"
- tapOn: "Repost"
- assertVisible:
id: "repostCount"
childOf:
id: "postThreadItem-by-carla.test"
- tapOn:
id: "repostBtn"
childOf:
id: "postThreadItem-by-carla.test"
- tapOn: "Undo repost"
- assertNotVisible:
id: "repostCount"
childOf:
id: "postThreadItem-by-carla.test"
-12
View File
@@ -1,12 +0,0 @@
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
rootDir: '..',
testMatch: ['<rootDir>/__e2e__/**/*.test.ts'],
testTimeout: 120000,
maxWorkers: 1,
globalSetup: 'detox/runners/jest/globalSetup',
globalTeardown: 'detox/runners/jest/globalTeardown',
reporters: ['detox/runners/jest/reporter'],
testEnvironment: 'detox/runners/jest/testEnvironment',
verbose: true,
}
@@ -1,3 +1,4 @@
# flow.yaml
appId: xyz.blueskyweb.app
@@ -74,4 +75,3 @@ appId: xyz.blueskyweb.app
- "scroll"
- "scroll"
- "scroll"
+11
View File
@@ -0,0 +1,11 @@
appId: xyz.blueskyweb.app
---
- launchApp:
appId: "xyz.blueskyweb.app"
clearState: true
- waitForAnimationToEnd
- tapOn: "http://localhost:8081"
- waitForAnimationToEnd
- swipe:
from: "Bluesky"
direction: DOWN
+5
View File
@@ -0,0 +1,5 @@
// eslint-disable-next-line
http.post('http://localhost:1986/' + SERVER_PATH, {
headers: {'Content-Type': 'text/plain'},
body: '',
})
-109
View File
@@ -1,109 +0,0 @@
/* eslint-env detox/detox */
import {beforeAll, describe, it} from '@jest/globals'
import {expect} from 'detox'
import {createServer, loginAsAlice, openApp, sleep} from '../util'
describe('Composer', () => {
beforeAll(async () => {
await createServer('?users')
await openApp({
permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'},
})
})
it('Login', async () => {
await loginAsAlice()
await element(by.id('homeScreenFeedTabs-Following')).tap()
})
it('Post text only', async () => {
await element(by.id('composeFAB')).tap()
await device.takeScreenshot('1- opened composer')
await element(by.id('composerTextInput')).typeText('Post text only')
await device.takeScreenshot('2- entered text')
await element(by.id('composerPublishBtn')).tap()
await device.takeScreenshot('3- opened general section')
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('Post with an image', async () => {
await element(by.id('composeFAB')).tap()
await element(by.id('composerTextInput')).typeText('Post with an image')
await element(by.id('openGalleryBtn')).tap()
await sleep(1e3)
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('Post with a link card', async () => {
await element(by.id('composeFAB')).tap()
await element(by.id('composerTextInput')).typeText(
'Post with a https://example.com link card',
)
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('Reply text only', async () => {
await element(by.id('e2eRefreshHome')).tap()
const post = by.id('feedItem-by-alice.test')
await element(by.id('replyBtn').withAncestor(post)).atIndex(0).tap()
await element(by.id('composerTextInput')).typeText('Reply text only')
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('Reply with an image', async () => {
const post = by.id('feedItem-by-alice.test')
await element(by.id('replyBtn').withAncestor(post)).atIndex(0).tap()
await element(by.id('composerTextInput')).typeText('Reply with an image')
await element(by.id('openGalleryBtn')).tap()
await sleep(1e3)
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('Reply with a link card', async () => {
const post = by.id('feedItem-by-alice.test')
await element(by.id('replyBtn').withAncestor(post)).atIndex(0).tap()
await element(by.id('composerTextInput')).typeText(
'Reply with a https://example.com link card',
)
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('QP text only', async () => {
const post = by.id('feedItem-by-alice.test')
await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap()
await element(by.id('quoteBtn').withAncestor(by.id('repostModal'))).tap()
await element(by.id('composerTextInput')).typeText('QP text only')
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('QP with an image', async () => {
const post = by.id('feedItem-by-alice.test')
await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap()
await element(by.id('quoteBtn').withAncestor(by.id('repostModal'))).tap()
await element(by.id('composerTextInput')).typeText('QP with an image')
await element(by.id('openGalleryBtn')).tap()
await sleep(1e3)
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('QP with a link card', async () => {
const post = by.id('feedItem-by-alice.test')
await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap()
await element(by.id('quoteBtn').withAncestor(by.id('repostModal'))).tap()
await element(by.id('composerTextInput')).typeText(
'QP with a https://example.com link card',
)
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
})
-39
View File
@@ -1,39 +0,0 @@
/* eslint-env detox/detox */
import {describe, beforeAll, it} from '@jest/globals'
import {expect} from 'detox'
import {openApp, createServer} from '../util'
describe('Create account', () => {
let service: string
beforeAll(async () => {
service = await createServer('')
await openApp({permissions: {notifications: 'YES'}})
})
it('I can create a new account', async () => {
await element(by.id('e2eOpenLoggedOutView')).tap()
await element(by.id('createAccountButton')).tap()
await device.takeScreenshot('1- opened create account screen')
await element(by.id('selectServiceButton')).tap()
await device.takeScreenshot('2- selected other server')
await element(by.id('customSelectBtn')).tap()
await element(by.id('customServerTextInput')).typeText(service)
await element(by.id('customServerTextInput')).tapReturnKey()
await element(by.id('doneBtn')).tap()
await device.takeScreenshot('3- input test server URL')
await element(by.id('emailInput')).typeText('example@test.com')
await element(by.id('passwordInput')).typeText('hunter2')
await device.takeScreenshot('4- entered account details')
await element(by.id('nextBtn')).tap()
await element(by.id('handleInput')).typeText('e2e-test')
await device.takeScreenshot('5- entered handle')
await element(by.id('nextBtn')).tap()
await expect(element(by.id('onboardingInterests'))).toBeVisible()
})
})
-213
View File
@@ -1,213 +0,0 @@
/* eslint-env detox/detox */
import {beforeAll, describe, it} from '@jest/globals'
import {expect} from 'detox'
import {createServer, loginAsAlice, loginAsBob, openApp, sleep} from '../util'
describe('Curate lists', () => {
beforeAll(async () => {
await createServer('?users&follows&posts')
await openApp({
permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'},
})
})
it('Login and create a curatelists', async () => {
await loginAsAlice()
await element(by.id('e2eGotoLists')).tap()
await element(by.id('newUserListBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).toBeVisible()
await element(by.id('editNameInput')).typeText('Good Ppl')
await element(by.id('editDescriptionInput')).typeText('They good')
await element(by.id('saveBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
await element(by.text('About')).tap()
await expect(element(by.id('headerTitle'))).toHaveText('Good Ppl')
await expect(element(by.id('listDescription'))).toHaveText('They good')
})
it('Edit display name and description via the edit curatelist modal', async () => {
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Edit list details')).tap()
await expect(element(by.id('createOrEditListModal'))).toBeVisible()
await element(by.id('editNameInput')).clearText()
await element(by.id('editNameInput')).typeText('Bad Ppl')
await element(by.id('editDescriptionInput')).clearText()
await element(by.id('editDescriptionInput')).typeText('They bad')
await element(by.id('saveBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
await expect(element(by.id('headerTitle'))).toHaveText('Bad Ppl')
await expect(element(by.id('listDescription'))).toHaveText('They bad')
// have to wait for the toast to clear
await waitFor(element(by.id('headerDropdownBtn')))
.toBeVisible()
.withTimeout(5000)
})
it('Remove description via the edit curatelist modal', async () => {
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Edit list details')).tap()
await expect(element(by.id('createOrEditListModal'))).toBeVisible()
await element(by.id('editDescriptionInput')).clearText()
await element(by.id('saveBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
await expect(element(by.id('listDescription'))).not.toBeVisible()
// have to wait for the toast to clear
await waitFor(element(by.id('headerDropdownBtn')))
.toBeVisible()
.withTimeout(5000)
})
it('Set avi via the edit curatelist modal', async () => {
await expect(element(by.id('userAvatarFallback'))).toExist()
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Edit list details')).tap()
await expect(element(by.id('createOrEditListModal'))).toBeVisible()
await element(by.id('changeAvatarBtn')).tap()
await element(by.text('Upload from Library')).tap()
await sleep(3e3)
await element(by.id('saveBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
await expect(element(by.id('userAvatarImage'))).toExist()
// have to wait for the toast to clear
await waitFor(element(by.id('headerDropdownBtn')))
.toBeVisible()
.withTimeout(5000)
})
it('Remove avi via the edit curatelist modal', async () => {
await expect(element(by.id('userAvatarImage'))).toExist()
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Edit list details')).tap()
await expect(element(by.id('createOrEditListModal'))).toBeVisible()
await element(by.id('changeAvatarBtn')).tap()
await element(by.text('Remove Avatar')).tap()
await element(by.id('saveBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
await expect(element(by.id('userAvatarFallback'))).toExist()
// have to wait for the toast to clear
await waitFor(element(by.id('headerDropdownBtn')))
.toBeVisible()
.withTimeout(5000)
})
it('Delete the curatelist', async () => {
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Delete List')).tap()
await element(by.id('confirmBtn')).tap()
await expect(element(by.id('listsEmpty'))).toBeVisible()
})
it('Create a new curatelist', async () => {
await element(by.id('e2eGotoLists')).tap()
await element(by.id('newUserListBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).toBeVisible()
await element(by.id('editNameInput')).typeText('Good Ppl')
await element(by.id('editDescriptionInput')).typeText('They good')
await element(by.id('saveBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
await element(by.text('About')).tap()
await expect(element(by.id('headerTitle'))).toHaveText('Good Ppl')
await expect(element(by.id('listDescription'))).toHaveText('They good')
})
it('Adds users on curatelists from the list', async () => {
await element(by.text('About')).tap()
await element(by.id('addUserBtn')).tap()
await expect(element(by.id('listAddUserModal'))).toBeVisible()
await element(by.id('searchInput')).typeText('b')
await waitFor(element(by.id('user-bob.test-addBtn')))
.toBeVisible()
.withTimeout(5000)
await element(by.id('user-bob.test-addBtn')).tap()
await element(by.id('doneBtn')).tap()
await expect(element(by.id('listAddUserModal'))).not.toBeVisible()
await expect(element(by.id('user-bob.test'))).toBeVisible()
})
it('Shows posts by the users in the list', async () => {
await element(by.text('Posts')).tap()
await expect(element(by.id('feedItem-by-bob.test'))).toBeVisible()
})
it('Pins the list', async () => {
await expect(element(by.id('pinBtn'))).toBeVisible()
await element(by.id('pinBtn')).tap()
await element(by.id('e2eGotoHome')).tap()
await element(by.id('homeScreenFeedTabs-Good Ppl')).tap()
await expect(element(by.id('feedItem-by-bob.test'))).toBeVisible()
await element(by.id('bottomBarFeedsBtn')).tap()
await element(by.id('saved-feed-Good Ppl')).tap()
await expect(element(by.id('feedItem-by-bob.test'))).toBeVisible()
await element(by.id('unpinBtn')).tap()
await element(by.id('bottomBarHomeBtn')).tap()
await expect(
element(by.id('homeScreenFeedTabs-Good Ppl')),
).not.toBeVisible()
await element(by.id('e2eGotoLists')).tap()
await element(by.id('list-Good Ppl')).tap()
})
it('Removes users on curatelists from the list', async () => {
await element(by.text('About')).tap()
await expect(element(by.id('user-bob.test'))).toBeVisible()
await element(by.id('user-bob.test-editBtn')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
await element(by.id('user-bob.test-addBtn')).tap()
await element(by.id('doneBtn')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
})
it('Shows the curatelist on my profile', async () => {
await element(by.id('bottomBarProfileBtn')).tap()
await element(by.id('profilePager-selector')).swipe('left')
await element(by.id('profilePager-selector-5')).tap()
await element(by.id('list-Good Ppl')).tap()
})
it('Adds and removes users on curatelists from the profile', async () => {
await element(by.id('bottomBarSearchBtn')).tap()
await element(by.id('searchTextInput')).typeText('bob')
await element(by.id('searchAutoCompleteResult-bob.test')).tap()
await expect(element(by.id('profileView'))).toBeVisible()
await element(by.id('profileHeaderDropdownBtn')).tap()
await element(by.text('Add to Lists')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
await element(by.id('user-bob.test-addBtn')).tap()
await element(by.id('doneBtn')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
await element(by.id('profileHeaderDropdownBtn')).tap()
await element(by.text('Add to Lists')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
await element(by.id('user-bob.test-addBtn')).tap()
await element(by.id('doneBtn')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
})
it('Can report a user list', async () => {
await element(by.id('e2eGotoSettings')).tap()
await element(by.id('signOutBtn')).tap()
await loginAsBob()
await element(by.id('bottomBarSearchBtn')).tap()
await element(by.id('searchTextInput')).typeText('alice')
await element(by.id('searchAutoCompleteResult-alice.test')).tap()
await element(by.id('profilePager-selector')).swipe('left')
await element(by.id('profilePager-selector-3')).tap()
await element(by.id('list-Good Ppl')).tap()
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Report List')).tap()
await expect(element(by.id('reportModal'))).toBeVisible()
await expect(element(by.text('Report List'))).toBeVisible()
await element(
by.id('reportReasonRadios-com.atproto.moderation.defs#reasonRude'),
).tap()
await element(by.id('sendReportBtn')).tap()
await expect(element(by.id('reportModal'))).not.toBeVisible()
})
})
-110
View File
@@ -1,110 +0,0 @@
/* eslint-env detox/detox */
import {beforeAll, describe, it} from '@jest/globals'
import {expect} from 'detox'
import {createServer, loginAsAlice, openApp} from '../util'
describe('Home screen', () => {
beforeAll(async () => {
await createServer('?users&follows&posts&feeds')
await openApp({permissions: {notifications: 'YES'}})
})
it('Login', async () => {
await loginAsAlice()
await element(by.id('homeScreenFeedTabs-Following')).tap()
})
it('Can go to feeds page using feeds button in tab bar', async () => {
await element(by.id('homeScreenFeedTabs-Feeds ✨')).tap()
await expect(element(by.text('Discover New Feeds'))).toBeVisible()
})
it('Feeds button disappears after pinning a feed', async () => {
await element(by.id('bottomBarProfileBtn')).tap()
await element(by.id('profilePager-selector')).swipe('left')
await element(by.id('profilePager-selector-4')).tap()
await element(by.id('feed-alice-favs')).tap()
await element(by.id('pinBtn')).tap()
await element(by.id('bottomBarHomeBtn')).tap()
await expect(
element(by.id('homeScreenFeedTabs-Feeds ✨')),
).not.toBeVisible()
})
it('Can like posts', async () => {
const carlaPosts = by.id('feedItem-by-carla.test')
await expect(
element(by.id('likeCount').withAncestor(carlaPosts)).atIndex(0),
).not.toExist()
await element(by.id('likeBtn').withAncestor(carlaPosts)).atIndex(0).tap()
await expect(
element(by.id('likeCount').withAncestor(carlaPosts)).atIndex(0),
).toHaveText('1')
await element(by.id('likeBtn').withAncestor(carlaPosts)).atIndex(0).tap()
await expect(
element(by.id('likeCount').withAncestor(carlaPosts)).atIndex(0),
).not.toExist()
})
it('Can repost posts', async () => {
const carlaPosts = by.id('feedItem-by-carla.test')
await expect(
element(by.id('repostCount').withAncestor(carlaPosts)).atIndex(0),
).not.toExist()
await element(by.id('repostBtn').withAncestor(carlaPosts)).atIndex(0).tap()
await expect(element(by.id('repostModal'))).toBeVisible()
await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap()
await expect(element(by.id('repostModal'))).not.toBeVisible()
await expect(
element(by.id('repostCount').withAncestor(carlaPosts)).atIndex(0),
).toHaveText('1')
await element(by.id('repostBtn').withAncestor(carlaPosts)).atIndex(0).tap()
await expect(element(by.id('repostModal'))).toBeVisible()
await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap()
await expect(element(by.id('repostModal'))).not.toBeVisible()
await expect(
element(by.id('repostCount').withAncestor(carlaPosts)).atIndex(0),
).not.toExist()
})
// TODO skipping because the test env PDS isnt setup correctly to handle the report -prf
// it('Can report posts', async () => {
// const carlaPosts = by.id('feedItem-by-carla.test')
// await element(by.id('postDropdownBtn').withAncestor(carlaPosts))
// .atIndex(0)
// .tap()
// await element(by.text('Report post')).tap()
// await element(by.id('com.atproto.moderation.defs#reasonSpam')).tap()
// await element(by.id('sendReportBtn')).tap()
// })
it('Can swipe between feeds', async () => {
await element(by.id('homeScreen')).swipe('left', 'fast', 0.75)
await expect(element(by.id('customFeedPage'))).toBeVisible()
await element(by.id('homeScreen')).swipe('right', 'fast', 0.75)
await expect(element(by.id('followingFeedPage'))).toBeVisible()
})
it('Can tap between feeds', async () => {
await element(by.id('homeScreenFeedTabs-alice-favs')).tap()
await expect(element(by.id('customFeedPage'))).toBeVisible()
await element(by.id('homeScreenFeedTabs-Following')).tap()
await expect(element(by.id('followingFeedPage'))).toBeVisible()
})
it('Can delete posts', async () => {
const alicePosts = by.id('feedItem-by-alice.test')
await expect(element(alicePosts.withDescendant(by.text('Post')))).toExist()
await element(by.id('postDropdownBtn').withAncestor(alicePosts))
.atIndex(0)
.tap()
await element(by.text('Delete post')).tap()
await expect(element(by.id('confirmModal'))).toBeVisible()
await element(by.id('confirmBtn')).tap()
await expect(
element(alicePosts.withDescendant(by.text('Post'))),
).not.toExist()
})
})
-47
View File
@@ -1,47 +0,0 @@
/* eslint-env detox/detox */
import {beforeAll, describe, it} from '@jest/globals'
import {expect} from 'detox'
import {createServer, loginAsAlice, openApp} from '../util'
describe('invite-codes', () => {
let service: string
let inviteCode = ''
beforeAll(async () => {
service = await createServer('?users&invite')
await openApp({permissions: {notifications: 'YES'}})
})
it('I can fetch invite codes', async () => {
await loginAsAlice()
await element(by.id('e2eOpenInviteCodesModal')).tap()
await expect(element(by.id('inviteCodesModal'))).toBeVisible()
const attrs = await element(by.id('inviteCode-0-code')).getAttributes()
inviteCode = attrs.text
await element(by.id('closeBtn')).tap()
await element(by.id('e2eSignOut')).tap()
})
it('I can create a new account with the invite code', async () => {
await element(by.id('e2eOpenLoggedOutView')).tap()
await element(by.id('createAccountButton')).tap()
await device.takeScreenshot('1- opened create account screen')
await element(by.id('selectServiceButton')).tap()
await device.takeScreenshot('2- selected other server')
await element(by.id('customSelectBtn')).tap()
await element(by.id('customServerTextInput')).typeText(service)
await element(by.id('customServerTextInput')).tapReturnKey()
await element(by.id('doneBtn')).tap()
await device.takeScreenshot('3- input test server URL')
await element(by.id('inviteCodeInput')).typeText(inviteCode)
await element(by.id('emailInput')).typeText('example@test.com')
await element(by.id('passwordInput')).typeText('hunter2')
await device.takeScreenshot('4- entered account details')
await element(by.id('nextBtn')).tap()
await element(by.id('handleInput')).typeText('e2e-test')
await device.takeScreenshot('4- entered handle')
await element(by.id('nextBtn')).tap()
await expect(element(by.id('onboardingInterests'))).toBeVisible()
})
})
-23
View File
@@ -1,23 +0,0 @@
/* eslint-env detox/detox */
import {describe, beforeAll, it} from '@jest/globals'
import {expect} from 'detox'
import {openApp, login, createServer} from '../util'
describe('Login', () => {
let service: string
beforeAll(async () => {
service = await createServer('?users')
await openApp({permissions: {notifications: 'YES'}})
})
it('As Alice, I can login', async () => {
await element(by.id('e2eOpenLoggedOutView')).tap()
await expect(element(by.id('signInButton'))).toBeVisible()
await login(service, 'alice', 'hunter2', {
takeScreenshots: true,
})
await device.takeScreenshot('5- opened home screen')
})
})
-163
View File
@@ -1,163 +0,0 @@
/* eslint-env detox/detox */
import {describe, beforeAll, it} from '@jest/globals'
import {expect} from 'detox'
import {openApp, loginAsAlice, createServer} from '../util'
describe('Mergefeed', () => {
beforeAll(async () => {
await createServer('?mergefeed')
await openApp({permissions: {notifications: 'YES'}})
})
it('Login', async () => {
await element(by.id('e2eOpenLoggedOutView')).tap()
await loginAsAlice()
await element(by.id('e2eToggleMergefeed')).tap()
await element(by.id('bottomBarFeedsBtn')).tap()
await element(by.id('feed-alice-favs-toggleSave')).tap()
await element(by.id('e2eGotoHome')).tap()
})
it('Sees the expected mix of posts with default filters', async () => {
await element(by.id('followingFeedPage-feed-flatlist')).swipe(
'down',
'slow',
1,
0.5,
0.5,
)
// followed users
await expect(
element(
by.id('postText').withAncestor(by.id('feedItem-by-carla.test')),
).atIndex(0),
).toHaveText('Post 9')
await expect(
element(
by.id('postText').withAncestor(by.id('feedItem-by-bob.test')),
).atIndex(0),
).toHaveText('Post 9')
await element(by.id('followingFeedPage-feed-flatlist')).swipe(
'up',
'fast',
1,
0.5,
0.5,
)
// feed users
await expect(
element(
by.id('postText').withAncestor(by.id('feedItem-by-dan.test')),
).atIndex(0),
).toHaveText('Post 0')
})
it('Sees the expected mix of posts with replies disabled', async () => {
await element(by.id('followingFeedPage-feed-flatlist')).swipe(
'down',
'fast',
1,
0.5,
0.5,
)
await element(by.id('followingFeedPage-feed-flatlist')).swipe(
'down',
'fast',
1,
0.5,
0.5,
)
await element(by.id('viewHeaderHomeFeedPrefsBtn')).tap()
await element(by.id('toggleRepliesBtn')).tap()
await element(by.id('confirmBtn')).tap()
await element(by.id('followingFeedPage-feed-flatlist')).swipe(
'down',
'slow',
1,
0.5,
0.5,
)
// followed users
await expect(
element(
by.id('postText').withAncestor(by.id('feedItem-by-carla.test')),
).atIndex(0),
).toHaveText('Post 9')
await expect(
element(
by.id('postText').withAncestor(by.id('feedItem-by-bob.test')),
).atIndex(0),
).toHaveText('Post 9')
await element(by.id('followingFeedPage-feed-flatlist')).swipe(
'up',
'fast',
1,
0.5,
0.5,
)
// feed users
await expect(
element(
by.id('postText').withAncestor(by.id('feedItem-by-dan.test')),
).atIndex(0),
).toHaveText('Post 0')
})
it('Sees the expected mix of posts with no follows', async () => {
await element(by.id('followingFeedPage-feed-flatlist')).swipe(
'down',
'fast',
1,
0.5,
0.5,
)
await element(by.id('bottomBarSearchBtn')).tap()
await element(by.id('searchTextInput')).typeText('bob')
await element(by.id('searchAutoCompleteResult-bob.test')).tap()
await expect(element(by.id('profileView'))).toBeVisible()
await element(by.id('unfollowBtn')).tap()
await element(by.id('profileHeaderBackBtn')).tap()
// have to wait for the toast to clear
await waitFor(element(by.id('searchTextInputClearBtn')))
.toBeVisible()
.withTimeout(5000)
await element(by.id('searchTextInputClearBtn')).tap()
await element(by.id('searchTextInput')).typeText('carla')
await element(by.id('searchAutoCompleteResult-carla.test')).tap()
await expect(element(by.id('profileView'))).toBeVisible()
await element(by.id('unfollowBtn')).tap()
await element(by.id('profileHeaderBackBtn')).tap()
await element(by.id('bottomBarHomeBtn')).tap()
await element(by.id('followingFeedPage-feed-flatlist')).swipe(
'down',
'slow',
1,
0.5,
0.5,
)
await element(by.id('followingFeedPage-feed-flatlist')).swipe(
'down',
'slow',
1,
0.5,
0.5,
)
// followed users NOT present
await expect(element(by.id('feedItem-by-carla.test'))).not.toExist()
await expect(element(by.id('feedItem-by-bob.test'))).not.toExist()
// feed users
await expect(
element(
by.id('postText').withAncestor(by.id('feedItem-by-dan.test')),
).atIndex(0),
).toHaveText('Post 0')
})
})
-189
View File
@@ -1,189 +0,0 @@
/* eslint-env detox/detox */
import {describe, beforeAll, it} from '@jest/globals'
import {expect} from 'detox'
import {openApp, loginAsAlice, loginAsBob, createServer} from '../util'
describe('Mod lists', () => {
beforeAll(async () => {
await createServer('?users&follows&labels')
await openApp({
permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'},
})
})
it('Login and view my modlists', async () => {
await loginAsAlice()
await element(by.id('e2eGotoModeration')).tap()
await element(by.id('moderationlistsBtn')).tap()
await expect(element(by.id('list-Muted Users'))).toBeVisible()
await element(by.id('list-Muted Users')).tap()
await expect(
element(by.id('user-muted-by-list-account.test')),
).toBeVisible()
})
it('Toggle mute subscription', async () => {
await element(by.id('unmuteBtn')).tap()
await element(by.id('subscribeBtn')).tap()
await element(by.text('Mute accounts')).tap()
await element(by.id('confirmBtn')).tap()
})
it('Edit display name and description via the edit modlist modal', async () => {
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Edit list details')).tap()
await expect(element(by.id('createOrEditListModal'))).toBeVisible()
await element(by.id('editNameInput')).clearText()
await element(by.id('editNameInput')).typeText('Bad Ppl')
await element(by.id('editDescriptionInput')).clearText()
await element(by.id('editDescriptionInput')).typeText('They bad')
await element(by.id('saveBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
await expect(element(by.id('headerTitle'))).toHaveText('Bad Ppl')
await expect(element(by.id('listDescription'))).toHaveText('They bad')
// have to wait for the toast to clear
await waitFor(element(by.id('headerDropdownBtn')))
.toBeVisible()
.withTimeout(5000)
})
it('Remove description via the edit modlist modal', async () => {
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Edit list details')).tap()
await expect(element(by.id('createOrEditListModal'))).toBeVisible()
await element(by.id('editDescriptionInput')).clearText()
await element(by.id('saveBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
await expect(element(by.id('listDescription'))).not.toBeVisible()
// have to wait for the toast to clear
await waitFor(element(by.id('headerDropdownBtn')))
.toBeVisible()
.withTimeout(5000)
})
// DISABLED e2e environment is real finicky about avatar uploads -prf
// it('Set avi via the edit modlist modal', async () => {
// await expect(element(by.id('userAvatarFallback'))).toExist()
// await element(by.id('headerDropdownBtn')).tap()
// await element(by.text('Edit list details')).tap()
// await expect(element(by.id('createOrEditListModal'))).toBeVisible()
// await element(by.id('changeAvatarBtn')).tap()
// await element(by.text('Library')).tap()
// await sleep(3e3)
// await element(by.id('saveBtn')).tap()
// await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
// await expect(element(by.id('userAvatarImage'))).toExist()
// // have to wait for the toast to clear
// await waitFor(element(by.id('headerDropdownBtn')))
// .toBeVisible()
// .withTimeout(5000)
// })
// it('Remove avi via the edit modlist modal', async () => {
// await expect(element(by.id('userAvatarImage'))).toExist()
// await element(by.id('headerDropdownBtn')).tap()
// await element(by.text('Edit list details')).tap()
// await expect(element(by.id('createOrEditListModal'))).toBeVisible()
// await element(by.id('changeAvatarBtn')).tap()
// await element(by.text('Remove')).tap()
// await element(by.id('saveBtn')).tap()
// await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
// await expect(element(by.id('userAvatarFallback'))).toExist()
// // have to wait for the toast to clear
// await waitFor(element(by.id('headerDropdownBtn')))
// .toBeVisible()
// .withTimeout(5000)
// })
it('Delete the modlist', async () => {
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Delete List')).tap()
await element(by.id('confirmBtn')).tap()
await expect(element(by.id('listsEmpty'))).toBeVisible()
})
it('Create a new modlist', async () => {
await element(by.id('newModListBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).toBeVisible()
await element(by.id('editNameInput')).typeText('Bad Ppl')
await element(by.id('editDescriptionInput')).typeText('They bad')
await element(by.id('saveBtn')).tap()
await expect(element(by.id('createOrEditListModal'))).not.toBeVisible()
await expect(element(by.id('headerTitle'))).toHaveText('Bad Ppl')
await expect(element(by.id('listDescription'))).toHaveText('They bad')
})
it('Adds and removes users on modlists from the list', async () => {
await element(by.id('addUserBtn')).tap()
await expect(element(by.id('listAddUserModal'))).toBeVisible()
await waitFor(element(by.id('user-warn-posts.test-addBtn')))
.toBeVisible()
.withTimeout(5000)
await element(by.id('user-warn-posts.test-addBtn')).tap()
await element(by.id('doneBtn')).tap()
await expect(element(by.id('listAddUserModal'))).not.toBeVisible()
await element(by.id('listItems-flatlist')).swipe(
'down',
'slow',
1,
0.5,
0.5,
)
await expect(element(by.id('user-warn-posts.test'))).toBeVisible()
await element(by.id('user-warn-posts.test-editBtn')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
await element(by.id('user-warn-posts.test-addBtn')).tap()
await element(by.id('doneBtn')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
})
it('Shows the modlist on my profile', async () => {
await element(by.id('bottomBarProfileBtn')).tap()
await element(by.id('profilePager-selector')).swipe('left')
await element(by.id('profilePager-selector-5')).tap()
await element(by.id('list-Bad Ppl')).tap()
})
it('Adds and removes users on modlists from the profile', async () => {
await element(by.id('bottomBarSearchBtn')).tap()
await element(by.id('searchTextInput')).typeText('bob')
await element(by.id('searchAutoCompleteResult-bob.test')).tap()
await expect(element(by.id('profileView'))).toBeVisible()
await element(by.id('profileHeaderDropdownBtn')).tap()
await element(by.text('Add to Lists')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
await element(by.id('user-bob.test-addBtn')).tap()
await element(by.id('doneBtn')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
await element(by.id('profileHeaderDropdownBtn')).tap()
await element(by.text('Add to Lists')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).toBeVisible()
await element(by.id('user-bob.test-addBtn')).tap()
await element(by.id('doneBtn')).tap()
await expect(element(by.id('userAddRemoveListsModal'))).not.toBeVisible()
})
it('Can report a mute list', async () => {
await element(by.id('e2eGotoSettings')).tap()
await element(by.id('signOutBtn')).tap()
await loginAsBob()
await element(by.id('bottomBarSearchBtn')).tap()
await element(by.id('searchTextInput')).typeText('alice')
await element(by.id('searchAutoCompleteResult-alice.test')).tap()
await element(by.id('profilePager-selector')).swipe('left')
await element(by.id('profilePager-selector-3')).tap()
await element(by.id('list-Bad Ppl')).tap()
await element(by.id('headerDropdownBtn')).tap()
await element(by.text('Report List')).tap()
await expect(element(by.id('reportModal'))).toBeVisible()
await expect(element(by.text('Report List'))).toBeVisible()
await element(
by.id('reportReasonRadios-com.atproto.moderation.defs#reasonRude'),
).tap()
await element(by.id('sendReportBtn')).tap()
await expect(element(by.id('reportModal'))).not.toBeVisible()
})
})
-196
View File
@@ -1,196 +0,0 @@
/* eslint-env detox/detox */
import {beforeAll, describe, it} from '@jest/globals'
import {expect} from 'detox'
import {createServer, loginAsAlice, openApp, sleep} from '../util'
describe('Profile screen', () => {
beforeAll(async () => {
await createServer('?users&posts&feeds')
await openApp({
permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'},
})
})
it('Login and navigate to my profile', async () => {
await loginAsAlice()
await element(by.id('bottomBarProfileBtn')).tap()
})
it('Can see feeds', async () => {
await element(by.id('profilePager-selector')).swipe('left')
await element(by.id('profilePager-selector-4')).tap()
await expect(element(by.id('feed-alice-favs'))).toBeVisible()
await element(by.id('profilePager-selector')).swipe('right')
await element(by.id('profilePager-selector-0')).tap()
})
it('Open and close edit profile modal', async () => {
await element(by.id('profileHeaderEditProfileButton')).tap()
await expect(element(by.id('editProfileModal'))).toBeVisible()
await element(by.id('editProfileCancelBtn')).tap()
await expect(element(by.id('editProfileModal'))).not.toBeVisible()
})
it('Edit display name and description via the edit profile modal', async () => {
await element(by.id('profileHeaderEditProfileButton')).tap()
await expect(element(by.id('editProfileModal'))).toBeVisible()
await element(by.id('editProfileDisplayNameInput')).clearText()
await element(by.id('editProfileDisplayNameInput')).typeText('Alicia')
await element(by.id('editProfileDescriptionInput')).clearText()
await element(by.id('editProfileDescriptionInput')).typeText(
'One cool hacker',
)
await element(by.id('editProfileSaveBtn')).tap()
await expect(element(by.id('editProfileModal'))).not.toBeVisible()
await expect(element(by.id('profileHeaderDisplayName'))).toHaveText(
'Alicia',
)
await expect(element(by.id('profileHeaderDescription'))).toHaveText(
'One cool hacker',
)
})
it('Remove display name and description via the edit profile modal', async () => {
await element(by.id('profileHeaderEditProfileButton')).tap()
await expect(element(by.id('editProfileModal'))).toBeVisible()
await element(by.id('editProfileDisplayNameInput')).clearText()
await element(by.id('editProfileDescriptionInput')).clearText()
await element(by.id('editProfileSaveBtn')).tap()
await expect(element(by.id('editProfileModal'))).not.toBeVisible()
await expect(element(by.id('profileHeaderDisplayName'))).toHaveText(
'alice.test',
)
await expect(element(by.id('profileHeaderDescription'))).not.toExist()
})
it('Set avi and banner via the edit profile modal', async () => {
await expect(element(by.id('userBannerFallback'))).toExist()
await expect(element(by.id('userAvatarFallback'))).toExist()
await element(by.id('profileHeaderEditProfileButton')).tap()
await expect(element(by.id('editProfileModal'))).toBeVisible()
await element(by.id('changeBannerBtn')).tap()
await element(by.text('Upload from Library')).tap()
await sleep(3e3)
await element(by.id('changeAvatarBtn')).tap()
await element(by.text('Upload from Library')).tap()
await sleep(3e3)
await element(by.id('editProfileSaveBtn')).tap()
await expect(element(by.id('editProfileModal'))).not.toBeVisible()
await expect(element(by.id('userBannerImage'))).toExist()
await expect(element(by.id('userAvatarImage'))).toExist()
})
it('Remove avi and banner via the edit profile modal', async () => {
await expect(element(by.id('userBannerImage'))).toExist()
await expect(element(by.id('userAvatarImage'))).toExist()
await element(by.id('profileHeaderEditProfileButton')).tap()
await expect(element(by.id('editProfileModal'))).toBeVisible()
await element(by.id('changeBannerBtn')).tap()
await element(by.text('Remove Banner')).tap()
await element(by.id('changeAvatarBtn')).tap()
await element(by.text('Remove Avatar')).tap()
await element(by.id('editProfileSaveBtn')).tap()
await expect(element(by.id('editProfileModal'))).not.toBeVisible()
await expect(element(by.id('userBannerFallback'))).toExist()
await expect(element(by.id('userAvatarFallback'))).toExist()
})
it('Navigate to another user profile', async () => {
await element(by.id('bottomBarSearchBtn')).tap()
// have to wait for the toast to clear
await waitFor(element(by.id('searchTextInput')))
.toBeVisible()
.withTimeout(5000)
await element(by.id('searchTextInput')).typeText('bob')
await element(by.id('searchAutoCompleteResult-bob.test')).tap()
await expect(element(by.id('profileView'))).toBeVisible()
})
it('Can follow/unfollow another user', async () => {
await element(by.id('followBtn')).tap()
await expect(element(by.id('unfollowBtn'))).toBeVisible()
await element(by.id('unfollowBtn')).tap()
await expect(element(by.id('followBtn'))).toBeVisible()
})
it('Can mute/unmute another user', async () => {
await expect(element(by.id('profileHeaderAlert'))).not.toExist()
await element(by.id('profileHeaderDropdownBtn')).tap()
await element(by.text('Mute Account')).tap()
await expect(element(by.id('profileHeaderAlert'))).toBeVisible()
await element(by.id('profileHeaderDropdownBtn')).tap()
await element(by.text('Unmute Account')).tap()
await expect(element(by.id('profileHeaderAlert'))).not.toExist()
})
// TODO skipping because the test env PDS isnt setup correctly to handle the report -prf
// it('Can report another user', async () => {
// await element(by.id('profileHeaderDropdownBtn')).tap()
// await element(by.text('Report Account')).tap()
// await expect(element(by.id('reportModal'))).toBeVisible()
// await element(
// by.id('reportReasonRadios-com.atproto.moderation.defs#reasonSpam'),
// ).tap()
// await element(by.id('sendReportBtn')).tap()
// await expect(element(by.id('reportModal'))).not.toBeVisible()
// })
it('Can like posts', async () => {
await element(by.id('postsFeed-flatlist')).swipe(
'down',
'slow',
1,
0.5,
0.5,
)
const posts = by.id('feedItem-by-bob.test')
await expect(
element(by.id('likeCount').withAncestor(posts)).atIndex(0),
).not.toExist()
await element(by.id('likeBtn').withAncestor(posts)).atIndex(0).tap()
await expect(
element(by.id('likeCount').withAncestor(posts)).atIndex(0),
).toHaveText('1')
await element(by.id('likeBtn').withAncestor(posts)).atIndex(0).tap()
await expect(
element(by.id('likeCount').withAncestor(posts)).atIndex(0),
).not.toExist()
})
it('Can repost posts', async () => {
const posts = by.id('feedItem-by-bob.test')
await expect(
element(by.id('repostCount').withAncestor(posts)).atIndex(0),
).not.toExist()
await element(by.id('repostBtn').withAncestor(posts)).atIndex(0).tap()
await expect(element(by.id('repostModal'))).toBeVisible()
await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap()
await expect(element(by.id('repostModal'))).not.toBeVisible()
await expect(
element(by.id('repostCount').withAncestor(posts)).atIndex(0),
).toHaveText('1')
await element(by.id('repostBtn').withAncestor(posts)).atIndex(0).tap()
await expect(element(by.id('repostModal'))).toBeVisible()
await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap()
await expect(element(by.id('repostModal'))).not.toBeVisible()
await expect(
element(by.id('repostCount').withAncestor(posts)).atIndex(0),
).not.toExist()
})
// TODO skipping because the test env PDS isnt setup correctly to handle the report -prf
// it('Can report posts', async () => {
// const posts = by.id('feedItem-by-bob.test')
// await element(by.id('postDropdownBtn').withAncestor(posts)).atIndex(0).tap()
// await element(by.text('Report post')).tap()
// await expect(element(by.id('reportModal'))).toBeVisible()
// await element(
// by.id('reportReasonRadios-com.atproto.moderation.defs#reasonSpam'),
// ).tap()
// await element(by.id('sendReportBtn')).tap()
// await expect(element(by.id('reportModal'))).not.toBeVisible()
// })
})
-25
View File
@@ -1,25 +0,0 @@
/* eslint-env detox/detox */
import {describe, beforeAll, it} from '@jest/globals'
import {expect} from 'detox'
import {openApp, loginAsAlice, createServer} from '../util'
describe('Search screen', () => {
beforeAll(async () => {
await createServer('?users')
await openApp({
permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'},
})
})
it('Login', async () => {
await loginAsAlice()
})
it('Navigate to another user profile via autocomplete', async () => {
await element(by.id('bottomBarSearchBtn')).tap()
await element(by.id('searchTextInput')).typeText('bob')
await element(by.id('searchAutoCompleteResult-bob.test')).tap()
await expect(element(by.id('profileView'))).toBeVisible()
})
})
-36
View File
@@ -1,36 +0,0 @@
/* eslint-env detox/detox */
import {describe, beforeAll, it} from '@jest/globals'
import {expect} from 'detox'
import {openApp, loginAsAlice, createServer, sleep} from '../util'
describe('Self-labeling', () => {
beforeAll(async () => {
await createServer('?users')
await openApp({
permissions: {notifications: 'YES', medialibrary: 'YES', photos: 'YES'},
})
})
it('Login', async () => {
await loginAsAlice()
await element(by.id('homeScreenFeedTabs-Following')).tap()
})
it('Post an image with the porn label', async () => {
await element(by.id('composeFAB')).tap()
await element(by.id('composerTextInput')).typeText('Post with an image')
await element(by.id('openGalleryBtn')).tap()
await sleep(3e3)
await element(by.id('labelsBtn')).tap()
await element(by.id('pornLabelBtn')).tap()
await element(by.id('confirmBtn')).tap()
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
const posts = by.id('feedItem-by-alice.test')
await element(by.id('e2eRefreshHome')).tap()
await expect(
element(by.id('contentHider-embed').withAncestor(posts)).atIndex(0),
).toExist()
})
})
-33
View File
@@ -1,33 +0,0 @@
/* eslint-env detox/detox */
import {openApp, loginAsAlice, createServer} from '../util'
describe('Shell', () => {
beforeAll(async () => {
await createServer('?users')
await openApp({permissions: {notifications: 'YES'}})
})
it('Login', async () => {
await loginAsAlice()
await element(by.id('homeScreenFeedTabs-Following')).tap()
})
it('Can swipe the shelf open', async () => {
await element(by.id('homeScreen')).swipe('right', 'fast', 0.75)
await expect(element(by.id('drawer'))).toBeVisible()
await element(by.id('drawer')).swipe('left', 'fast', 0.75)
await expect(element(by.id('drawer'))).not.toBeVisible()
})
it('Can open the shelf by pressing the header avi', async () => {
await element(by.id('viewHeaderDrawerBtn')).tap()
await expect(element(by.id('drawer'))).toBeVisible()
})
it('Can navigate using the shelf', async () => {
await element(by.id('menuItemButton-Notifications')).tap()
await expect(element(by.id('drawer'))).not.toBeVisible()
await expect(element(by.id('notificationsScreen'))).toBeVisible()
})
})
-103
View File
@@ -1,103 +0,0 @@
/* eslint-env detox/detox */
import {describe, beforeAll, it} from '@jest/globals'
import {expect} from 'detox'
import {openApp, loginAsAlice, loginAsBob, createServer} from '../util'
describe('Thread muting', () => {
beforeAll(async () => {
await createServer('?users&follows')
await openApp({permissions: {notifications: 'YES'}})
})
it('Login, create a thread, and log out', async () => {
await loginAsAlice()
await element(by.id('homeScreenFeedTabs-Following')).tap()
await element(by.id('composeFAB')).tap()
await element(by.id('composerTextInput')).typeText('Test thread')
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('Login, reply to the thread, and log out', async () => {
await loginAsBob()
await element(by.id('homeScreenFeedTabs-Following')).tap()
const alicePosts = by.id('feedItem-by-alice.test')
await element(by.id('replyBtn').withAncestor(alicePosts)).atIndex(0).tap()
await element(by.id('composerTextInput')).typeText('Reply 1')
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('Login, confirm notification exists, mute thread, and log out', async () => {
await loginAsAlice()
await element(by.id('bottomBarNotificationsBtn')).tap()
const bobNotifs = by.id('feedItem-by-bob.test')
await expect(
element(by.id('postText').withAncestor(bobNotifs)).atIndex(0),
).toHaveText('Reply 1')
await element(by.id('postDropdownBtn').withAncestor(bobNotifs))
.atIndex(0)
.tap()
await element(by.text('Mute thread')).tap()
// have to wait for the toast to clear
await waitFor(element(by.id('viewHeaderDrawerBtn')))
.toBeVisible()
.withTimeout(5000)
})
it('Login, reply to the thread twice, and log out', async () => {
await loginAsBob()
await element(by.id('bottomBarProfileBtn')).tap()
await element(by.id('profilePager-selector-1')).tap()
const bobPosts = by.id('feedItem-by-bob.test')
await element(by.id('replyBtn').withAncestor(bobPosts)).atIndex(0).tap()
await element(by.id('composerTextInput')).typeText('Reply 2')
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
const alicePosts = by.id('feedItem-by-alice.test')
await element(by.id('replyBtn').withAncestor(alicePosts)).atIndex(0).tap()
await element(by.id('composerTextInput')).typeText('Reply 3')
await element(by.id('composerPublishBtn')).tap()
await expect(element(by.id('composeFAB'))).toBeVisible()
await element(by.id('bottomBarHomeBtn')).tap()
})
it('Login, confirm notifications dont exist, unmute the thread, confirm notifications exist', async () => {
await loginAsAlice()
await element(by.id('bottomBarNotificationsBtn')).tap()
const bobNotifs = by.id('feedItem-by-bob.test')
await expect(
element(by.id('postText').withAncestor(bobNotifs)).atIndex(0),
).not.toExist()
await element(by.id('bottomBarHomeBtn')).tap()
const alicePosts = by.id('feedItem-by-alice.test')
await element(by.id('postDropdownBtn').withAncestor(alicePosts))
.atIndex(0)
.tap()
await element(by.text('Unmute thread')).tap()
// TODO
// the swipe down to trigger PTR isnt working and I dont want to block on this
// -prf
// await element(by.id('bottomBarNotificationsBtn')).tap()
// await element(by.id('notifsFeed')).swipe('down', 'fast')
// await waitFor(element(by.id('postText').withAncestor(bobNotifs)))
// .toBeVisible()
// .withTimeout(5000)
// await expect(
// element(by.id('postText').withAncestor(bobNotifs)).atIndex(0),
// ).toHaveText('Reply 2')
// await expect(
// element(by.id('postText').withAncestor(bobNotifs)).atIndex(1),
// ).toHaveText('Reply 3')
// await expect(
// element(by.id('postText').withAncestor(bobNotifs)).atIndex(2),
// ).toHaveText('Reply 1')
})
})
-131
View File
@@ -1,131 +0,0 @@
/* eslint-env detox/detox */
import {beforeAll, describe, it} from '@jest/globals'
import {expect} from 'detox'
import {createServer, loginAsAlice, openApp} from '../util'
describe('Thread screen', () => {
beforeAll(async () => {
await createServer('?users&follows&thread')
await openApp({permissions: {notifications: 'YES'}})
})
it('Login & navigate to thread', async () => {
await loginAsAlice()
await element(by.id('homeScreenFeedTabs-Following')).tap()
await element(by.id('feedItem-by-bob.test')).atIndex(0).tap()
await expect(
element(
by
.id('postThreadItem-by-bob.test')
.withDescendant(by.text('Thread root')),
),
).toBeVisible()
await expect(
element(
by
.id('postThreadItem-by-carla.test')
.withDescendant(by.text('Thread reply')),
),
).toBeVisible()
})
it('Can like the root post', async () => {
const post = by.id('postThreadItem-by-bob.test')
await expect(
element(by.id('likeCount-expanded').withAncestor(post)).atIndex(0),
).not.toExist()
await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap()
await expect(
element(by.id('likeCount-expanded').withAncestor(post)).atIndex(0),
).toHaveText('1 like')
await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap()
await expect(
element(by.id('likeCount-expanded').withAncestor(post)).atIndex(0),
).not.toExist()
})
it('Can like a reply post', async () => {
const post = by.id('postThreadItem-by-carla.test')
await expect(
element(by.id('likeCount').withAncestor(post)).atIndex(0),
).not.toExist()
await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap()
await expect(
element(by.id('likeCount').withAncestor(post)).atIndex(0),
).toHaveText('1')
await element(by.id('likeBtn').withAncestor(post)).atIndex(0).tap()
await expect(
element(by.id('likeCount').withAncestor(post)).atIndex(0),
).not.toExist()
})
it('Can repost the root post', async () => {
const post = by.id('postThreadItem-by-bob.test')
await expect(
element(by.id('repostCount-expanded').withAncestor(post)).atIndex(0),
).not.toExist()
await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap()
await expect(element(by.id('repostModal'))).toBeVisible()
await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap()
await expect(element(by.id('repostModal'))).not.toBeVisible()
await expect(
element(by.id('repostCount-expanded').withAncestor(post)).atIndex(0),
).toHaveText('1 repost')
await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap()
await expect(element(by.id('repostModal'))).toBeVisible()
await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap()
await expect(element(by.id('repostModal'))).not.toBeVisible()
await expect(
element(by.id('repostCount-expanded').withAncestor(post)).atIndex(0),
).not.toExist()
})
it('Can repost a reply post', async () => {
const post = by.id('postThreadItem-by-carla.test')
await expect(
element(by.id('repostCount').withAncestor(post)).atIndex(0),
).not.toExist()
await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap()
await expect(element(by.id('repostModal'))).toBeVisible()
await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap()
await expect(element(by.id('repostModal'))).not.toBeVisible()
await expect(
element(by.id('repostCount').withAncestor(post)).atIndex(0),
).toHaveText('1')
await element(by.id('repostBtn').withAncestor(post)).atIndex(0).tap()
await expect(element(by.id('repostModal'))).toBeVisible()
await element(by.id('repostBtn').withAncestor(by.id('repostModal'))).tap()
await expect(element(by.id('repostModal'))).not.toBeVisible()
await expect(
element(by.id('repostCount').withAncestor(post)).atIndex(0),
).not.toExist()
})
// TODO skipping because the test env PDS isnt setup correctly to handle the report -prf
// it('Can report the root post', async () => {
// const post = by.id('postThreadItem-by-bob.test')
// await element(by.id('postDropdownBtn').withAncestor(post)).atIndex(0).tap()
// await element(by.text('Report post')).tap()
// await expect(element(by.id('reportModal'))).toBeVisible()
// await element(
// by.id('reportReasonRadios-com.atproto.moderation.defs#reasonSpam'),
// ).tap()
// await element(by.id('sendReportBtn')).tap()
// await expect(element(by.id('reportModal'))).not.toBeVisible()
// })
// TODO skipping because the test env PDS isnt setup correctly to handle the report -prf
// it('Can report a reply post', async () => {
// const post = by.id('postThreadItem-by-carla.test')
// await element(by.id('postDropdownBtn').withAncestor(post)).atIndex(0).tap()
// await element(by.text('Report post')).tap()
// await expect(element(by.id('reportModal'))).toBeVisible()
// await element(
// by.id('reportReasonRadios-com.atproto.moderation.defs#reasonSpam'),
// ).tap()
// await element(by.id('sendReportBtn')).tap()
// await expect(element(by.id('reportModal'))).not.toBeVisible()
// })
})
-141
View File
@@ -1,141 +0,0 @@
import {execSync} from 'child_process'
import {resolveConfig} from 'detox/internals'
import http from 'http'
const platform = device.getPlatform()
export async function openApp(opts: any) {
opts = opts || {}
const config = await resolveConfig()
if (device.getPlatform() === 'ios') {
// disable password autofill
execSync(
`plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO ~/Library/Developer/CoreSimulator/Devices/${device.id}/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles/Library/ConfigurationProfiles/UserSettings.plist`,
)
execSync(
`plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO ~/Library/Developer/CoreSimulator/Devices/${device.id}/data/Library/UserConfigurationProfiles/EffectiveUserSettings.plist`,
)
execSync(
`plutil -replace restrictedBool.allowPasswordAutoFill.value -bool NO ~/Library/Developer/CoreSimulator/Devices/${device.id}/data/Library/UserConfigurationProfiles/PublicInfo/PublicEffectiveUserSettings.plist`,
)
}
if (config.configurationName.split('.').includes('debug')) {
return await openAppForDebugBuild(platform, opts)
} else {
return await device.launchApp({
...opts,
newInstance: true,
})
}
}
export async function isVisible(id: string) {
try {
await expect(element(by.id(id))).toBeVisible()
return true
} catch (e) {
return false
}
}
export async function login(
service: string,
username: string,
password: string,
{takeScreenshots} = {takeScreenshots: false},
) {
await element(by.id('signInButton')).tap()
if (takeScreenshots) {
await device.takeScreenshot('1- opened sign-in screen')
}
if (await isVisible('chooseAccountForm')) {
await element(by.id('chooseNewAccountBtn')).tap()
}
await element(by.id('selectServiceButton')).tap()
if (takeScreenshots) {
await device.takeScreenshot('2- opened service selector')
}
await element(by.id('customSelectBtn')).tap()
await element(by.id('customServerTextInput')).typeText(service)
await element(by.id('customServerTextInput')).tapReturnKey()
await element(by.id('doneBtn')).tap()
if (takeScreenshots) {
await device.takeScreenshot('3- input custom service')
}
await element(by.id('loginUsernameInput')).typeText(username)
await element(by.id('loginPasswordInput')).typeText(password)
if (takeScreenshots) {
await device.takeScreenshot('4- entered username and password')
}
await element(by.id('loginNextButton')).tap()
}
export async function loginAsAlice() {
await element(by.id('e2eSignInAlice')).tap()
}
export async function loginAsBob() {
await element(by.id('e2eSignInBob')).tap()
}
async function openAppForDebugBuild(platform: string, opts: any) {
const deepLinkUrl = // Local testing with packager
/*process.env.EXPO_USE_UPDATES
? // Testing latest published EAS update for the test_debug channel
getDeepLinkUrl(getLatestUpdateUrl())
: */ getDeepLinkUrl(getDevLauncherPackagerUrl(platform))
if (platform === 'ios') {
await device.launchApp({
...opts,
newInstance: true,
})
sleep(3000)
await device.openURL({
url: deepLinkUrl,
})
} else {
await device.launchApp({
...opts,
newInstance: true,
url: deepLinkUrl,
})
}
await sleep(3000)
}
export async function createServer(path = ''): Promise<string> {
return new Promise(function (resolve, reject) {
var req = http.request(
{
method: 'POST',
host: 'localhost',
port: 1986,
path: `/${path}`,
},
function (res) {
const body: Buffer[] = []
res.on('data', chunk => body.push(chunk))
res.on('end', function () {
try {
resolve(Buffer.concat(body).toString())
} catch (e) {
reject(e)
}
})
},
)
req.on('error', reject)
req.end()
})
}
const getDeepLinkUrl = (url: string) =>
`expo+bluesky://expo-development-client/?url=${encodeURIComponent(url)}`
const getDevLauncherPackagerUrl = (platform: string) =>
`http://localhost:8081/index.bundle?platform=${platform}&dev=true&minify=false&disableOnboarding=1`
export const sleep = (t: number) => new Promise(res => setTimeout(res, t))
+125 -31
View File
@@ -3,7 +3,7 @@ import {RichText} from '@atproto/api'
import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player'
import {cleanError} from '../../src/lib/strings/errors'
import {createFullHandle, makeValidHandle} from '../../src/lib/strings/handles'
import {enforceLen, pluralize} from '../../src/lib/strings/helpers'
import {enforceLen} from '../../src/lib/strings/helpers'
import {detectLinkables} from '../../src/lib/strings/rich-text-detection'
import {shortenLinks} from '../../src/lib/strings/rich-text-manip'
import {ago} from '../../src/lib/strings/time'
@@ -127,35 +127,6 @@ describe('detectLinkables', () => {
})
})
describe('pluralize', () => {
const inputs: [number, string, string?][] = [
[1, 'follower'],
[1, 'member'],
[100, 'post'],
[1000, 'repost'],
[10000, 'upvote'],
[100000, 'other'],
[2, 'man', 'men'],
]
const outputs = [
'follower',
'member',
'posts',
'reposts',
'upvotes',
'others',
'men',
]
it('correctly pluralizes a set of words', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const output = pluralize(...input)
expect(output).toEqual(outputs[i])
}
})
})
describe('makeRecordUri', () => {
const inputs: [string, string, string][] = [
['alice.test', 'app.bsky.feed.post', '3jk7x4irgv52r'],
@@ -171,7 +142,12 @@ describe('makeRecordUri', () => {
})
})
describe('ago', () => {
// FIXME: Reenable after fixing non-deterministic test.
describe.skip('ago', () => {
const oneYearDate = new Date(
new Date().setMonth(new Date().getMonth() - 11),
).setDate(new Date().getDate() - 28)
const inputs = [
1671461038,
'04 Dec 1995 00:12:00 GMT',
@@ -180,7 +156,32 @@ describe('ago', () => {
new Date().setMinutes(new Date().getMinutes() - 10),
new Date().setHours(new Date().getHours() - 1),
new Date().setDate(new Date().getDate() - 1),
new Date().setDate(new Date().getDate() - 20),
new Date().setDate(new Date().getDate() - 25),
new Date().setDate(new Date().getDate() - 28),
new Date().setDate(new Date().getDate() - 29),
new Date().setDate(new Date().getDate() - 30),
new Date().setMonth(new Date().getMonth() - 1),
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
new Date().getDate() - 20,
),
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
new Date().getDate() - 25,
),
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
new Date().getDate() - 28,
),
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
new Date().getDate() - 29,
),
new Date().setMonth(new Date().getMonth() - 11),
new Date(new Date().setMonth(new Date().getMonth() - 11)).setDate(
new Date().getDate() - 20,
),
new Date(new Date().setMonth(new Date().getMonth() - 11)).setDate(
new Date().getDate() - 25,
),
oneYearDate,
]
const outputs = [
new Date(1671461038).toLocaleDateString(),
@@ -190,7 +191,20 @@ describe('ago', () => {
'10m',
'1h',
'1d',
'20d',
'25d',
'28d',
'29d',
'1mo',
'1mo',
'1mo',
'1mo',
'2mo',
'2mo',
'11mo',
'11mo',
'11mo',
new Date(oneYearDate).toLocaleDateString(),
]
it('correctly calculates how much time passed, in a string', () => {
@@ -466,6 +480,26 @@ describe('parseEmbedPlayerFromUrl', () => {
'https://media.tenor.com/someID/someName.gif',
'https://media.tenor.com/someID',
'https://media.tenor.com',
'https://www.flickr.com/photos/username/albums/72177720308493661',
'https://flickr.com/photos/username/albums/72177720308493661',
'https://flickr.com/photos/username/albums/72177720308493661/',
'https://flickr.com/photos/username/albums/72177720308493661//',
'https://flic.kr/s/aHBqjAES3i',
'https://flickr.com/foetoes/username/albums/3903',
'https://flickr.com/albums/3903',
'https://flic.kr/s/OolI',
'https://flic.kr/t/aHBqjAES3i',
'https://www.flickr.com/groups/898944@N23/pool',
'https://flickr.com/groups/898944@N23/pool',
'https://flickr.com/groups/898944@N23/pool/',
'https://flickr.com/groups/898944@N23/pool//',
'https://flic.kr/go/8WJtR',
'https://www.flickr.com/groups/898944@N23/',
'https://www.flickr.com/groups',
]
const outputs = [
@@ -763,6 +797,66 @@ describe('parseEmbedPlayerFromUrl', () => {
undefined,
undefined,
undefined,
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/photosets/72177720308493661',
},
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/photosets/72177720308493661',
},
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/photosets/72177720308493661',
},
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/photosets/72177720308493661',
},
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/photosets/72177720308493661',
},
undefined,
undefined,
undefined,
undefined,
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/groups/898944@N23',
},
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/groups/898944@N23',
},
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/groups/898944@N23',
},
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/groups/898944@N23',
},
{
type: 'flickr_album',
source: 'flickr',
playerUri: 'https://embedr.flickr.com/groups/898944@N23',
},
undefined,
undefined,
]
it('correctly grabs the correct id from uri', () => {
+36 -2
View File
@@ -91,6 +91,29 @@ module.exports = function (config) {
entitlements: {
'com.apple.security.application-groups': 'group.app.bsky',
},
privacyManifests: {
NSPrivacyAccessedAPITypes: [
{
NSPrivacyAccessedAPIType:
'NSPrivacyAccessedAPICategoryFileTimestamp',
NSPrivacyAccessedAPITypeReasons: ['C617.1', '3B52.1', '0A2A.1'],
},
{
NSPrivacyAccessedAPIType: 'NSPrivacyAccessedAPICategoryDiskSpace',
NSPrivacyAccessedAPITypeReasons: ['E174.1', '85F4.1'],
},
{
NSPrivacyAccessedAPIType:
'NSPrivacyAccessedAPICategorySystemBootTime',
NSPrivacyAccessedAPITypeReasons: ['35F9.1'],
},
{
NSPrivacyAccessedAPIType:
'NSPrivacyAccessedAPICategoryUserDefaults',
NSPrivacyAccessedAPITypeReasons: ['CA92.1', '1C8F.1'],
},
],
},
},
androidStatusBar: {
barStyle: 'light-content',
@@ -152,7 +175,6 @@ module.exports = function (config) {
checkAutomatically: 'NEVER',
channel: UPDATES_CHANNEL,
},
assetBundlePatterns: ['**/*'],
plugins: [
'expo-localization',
Boolean(process.env.SENTRY_AUTH_TOKEN) && 'sentry-expo',
@@ -160,7 +182,7 @@ module.exports = function (config) {
'expo-build-properties',
{
ios: {
deploymentTarget: '13.4',
deploymentTarget: '14.0',
newArchEnabled: false,
},
android: {
@@ -177,14 +199,17 @@ module.exports = function (config) {
{
icon: './assets/icon-android-notification.png',
color: '#1185fe',
sounds: PLATFORM === 'ios' ? ['assets/dm.aiff'] : ['assets/dm.mp3'],
},
],
'./plugins/withAndroidManifestPlugin.js',
'./plugins/withAndroidManifestFCMIconPlugin.js',
'./plugins/withAndroidManifestLaunchModePlugin.js',
'./plugins/withAndroidStylesWindowBackgroundPlugin.js',
'./plugins/withAndroidStylesAccentColorPlugin.js',
'./plugins/withAndroidSplashScreenStatusBarTranslucentPlugin.js',
'./plugins/shareExtension/withShareExtensions.js',
'./plugins/notificationsExtension/withNotificationsExtension.js',
].filter(Boolean),
extra: {
eas: {
@@ -201,6 +226,15 @@ module.exports = function (config) {
],
},
},
{
targetName: 'BlueskyNSE',
bundleIdentifier: 'xyz.blueskyweb.app.BlueskyNSE',
entitlements: {
'com.apple.security.application-groups': [
'group.app.bsky',
],
},
},
],
},
},
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M12 2a7.307 7.307 0 0 0-7.298 6.943l-.19 3.798-1.321 2.641A1.809 1.809 0 0 0 4.809 18H7.1a5.002 5.002 0 0 0 9.8 0h2.291a1.809 1.809 0 0 0 1.618-2.618l-1.32-2.641-.19-3.798A7.308 7.308 0 0 0 12 2Zm0 18a3.001 3.001 0 0 1-2.83-2h5.66A3.001 3.001 0 0 1 12 20Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 398 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="M4.702 8.943a7.307 7.307 0 0 1 14.596 0l.19 3.798 1.321 2.641A1.809 1.809 0 0 1 19.191 18H16.9a5.002 5.002 0 0 1-9.8 0H4.809a1.809 1.809 0 0 1-1.618-2.618l1.32-2.641.19-3.798ZM9.17 18a3.001 3.001 0 0 0 5.658 0H9.171ZM12 4a5.307 5.307 0 0 0-5.3 5.042l-.19 3.798a2 2 0 0 1-.21.795L5.119 16h13.764l-1.183-2.365a2 2 0 0 1-.208-.795l-.19-3.798A5.308 5.308 0 0 0 12 4Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 505 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="m19.785 8.815 1.034 7.761L7.595 3.352a7.853 7.853 0 0 1 12.19 5.463ZM4 19h3.354c.904 1.748 2.607 3 4.646 3 2.038 0 3.742-1.252 4.646-3h.94l2.707 2.707a1 1 0 0 0 1.414-1.414l-18-18a1 1 0 0 0-1.414 1.414l2.666 2.666a7.842 7.842 0 0 0-.743 2.442l-1.207 9.053A1 1 0 0 0 4 19Zm8 1c-.823 0-1.613-.363-2.222-1h4.443c-.608.637-1.398 1-2.221 1Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 478 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="M2.293 2.293a1 1 0 0 1 1.414 0l18 18a1 1 0 0 1-1.414 1.414L17.586 19h-.94c-.904 1.748-2.607 3-4.646 3-2.039 0-3.742-1.252-4.646-3H4a1 1 0 0 1-.991-1.132l1.207-9.053c.116-.87.372-1.69.743-2.442L2.293 3.707a1 1 0 0 1 0-1.414Zm4.19 5.604c-.134.376-.23.772-.285 1.183L5.142 17h10.444L6.483 7.897ZM9.778 19c.61.637 1.399 1 2.222 1s1.613-.363 2.222-1H9.778ZM8.834 2.666a7.853 7.853 0 0 1 10.95 6.15l.645 4.832a1 1 0 0 1-1.983.265l-.644-4.833A5.853 5.853 0 0 0 9.64 4.495a1 1 0 0 1-.807-1.83Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 628 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 2a7.853 7.853 0 0 0-7.784 6.815l-1.207 9.053A1 1 0 0 0 4 19h3.354c.904 1.748 2.607 3 4.646 3 2.039 0 3.742-1.252 4.646-3H20a1 1 0 0 0 .991-1.132l-1.207-9.053A7.853 7.853 0 0 0 12 2Zm2.222 17H9.778c.61.637 1.399 1 2.222 1s1.613-.363 2.222-1Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 387 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="M4.216 8.815a7.853 7.853 0 0 1 15.568 0l1.207 9.053A1 1 0 0 1 20 19h-3.354c-.904 1.748-2.607 3-4.646 3-2.039 0-3.742-1.252-4.646-3H4a1 1 0 0 1-.991-1.132l1.207-9.053ZM9.778 19c.61.637 1.399 1 2.222 1s1.613-.363 2.222-1H9.778ZM12 4a5.853 5.853 0 0 0-5.802 5.08L5.142 17h13.716l-1.056-7.92A5.853 5.853 0 0 0 12 4Z" 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="M2.002 7a4 4 0 0 1 4-4h12a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H12.28l-4.762 2.858A1 1 0 0 1 6.002 21v-2a4 4 0 0 1-4-4V7Zm4-2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h1a1 1 0 0 1 1 1v1.234l3.486-2.092a1 1 0 0 1 .514-.142h6a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-12Z" clip-rule="evenodd"/></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" fill-rule="evenodd" d="M3 7a3 3 0 1 1 6 0 3 3 0 0 1-6 0Zm0 10a3 3 0 1 1 6 0 3 3 0 0 1-6 0Zm10-1a1 1 0 1 0 0 2h7a1 1 0 1 0 0-2h-7Zm-1-9a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 302 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="M6 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2ZM3 7a3 3 0 1 1 6 0 3 3 0 0 1-6 0Zm9 0a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1Zm-6 9a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-3 1a3 3 0 1 1 6 0 3 3 0 0 1-6 0Zm9 0a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1Z" clip-rule="evenodd"/></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="M3.004 4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2v5a1 1 0 0 0 .43.822c.57.395 1.176.031 1.685-.255.428-.24.998-.614 1.569-1.15 1.154-1.082 2.316-2.832 2.316-5.417V5a1 1 0 0 0-1-1h-7ZM14.004 4a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2v5a1 1 0 0 0 .43.822c.57.395 1.176.031 1.685-.255.428-.24.998-.614 1.569-1.15 1.154-1.082 2.316-2.832 2.316-5.417V5a1 1 0 0 0-1-1h-7Z"/></svg>

After

Width:  |  Height:  |  Size: 450 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="M2.004 5a1 1 0 0 1 1-1h7a1 1 0 0 1 1 1v8c0 2.585-1.162 4.335-2.316 5.417-.571.536-1.14.91-1.569 1.15a7.01 7.01 0 0 1-.738.36l-.016.006-.006.002h-.002l-.001.001L6.004 19l.351.936A1 1 0 0 1 5.004 19v-5h-2a1 1 0 0 1-1-1V5Zm5 12.234c.104-.085.21-.177.316-.276.846-.793 1.684-2.043 1.684-3.958V6h-5v6h2a1 1 0 0 1 1 1v4.234Zm6-12.234a1 1 0 0 1 1-1h7a1 1 0 0 1 1 1v8c0 2.585-1.162 4.335-2.316 5.417-.571.536-1.14.91-1.569 1.15a7.018 7.018 0 0 1-.738.36l-.016.006-.006.002h-.002l-.001.001-.352-.936.351.936A1 1 0 0 1 16.004 19v-5h-2a1 1 0 0 1-1-1V5Zm5 12.234V13a1 1 0 0 0-1-1h-2V6h5v7c0 1.915-.838 3.165-1.684 3.958-.106.1-.212.191-.316.276Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 775 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="M2.003 5.999a2 2 0 0 1 2-1.999h5c1.104 0 2 .893 2 1.999V13c0 2.585-1.16 4.335-2.315 5.417-.571.536-1.14.91-1.569 1.15a7.01 7.01 0 0 1-.738.36l-.016.006-.006.002h-.002l-.001.001L6.004 19l.351.936a1 1 0 0 1-1.351-.935L5 14H4a2 2 0 0 1-2-2.001l.002-6Zm5 11.236L7 12.999A1 1 0 0 0 6 12H4l.003-6h5v7c0 1.915-.837 3.165-1.683 3.958-.106.1-.213.192-.317.277Zm6-11.235a2 2 0 0 1 2-2h5c1.104 0 2 .893 2 1.999V13c0 2.585-1.16 4.335-2.315 5.417-.571.536-1.14.91-1.569 1.15a7.018 7.018 0 0 1-.738.36l-.016.006-.006.002h-.002l-.001.001-.352-.936.351.936A1 1 0 0 1 16.004 19v-5h-1a2 2 0 0 1-2-2V6Zm7 0h-5v6h2a1 1 0 0 1 1 1v4.234c.105-.085.211-.177.317-.276.846-.793 1.684-2.043 1.684-3.958V6Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 821 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="M4.4 9.493C4.14 10.28 4 11.124 4 12a8 8 0 1 0 10.899-7.459l-.953 3.81a1 1 0 0 1-.726.727l-3.444.866-.772 1.533a1 1 0 0 1-1.493.35L4.4 9.493Zm.883-1.84L7.756 9.51l.44-.874a1 1 0 0 1 .649-.52l3.306-.832.807-3.227a7.993 7.993 0 0 0-7.676 3.597ZM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12Zm8.43.162a1 1 0 0 1 .77-.29l1.89.121a1 1 0 0 1 .494.168l2.869 1.928a1 1 0 0 1 .336 1.277l-.973 1.946a1 1 0 0 1-.894.553h-2.92a1 1 0 0 1-.831-.445L9.225 14.5a1 1 0 0 1 .126-1.262l1.08-1.076Zm.915 1.913.177-.177 1.171.074 1.914 1.286-.303.607h-1.766l-1.194-1.79Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 714 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="M17.293 2.293a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1 0 1.414l-9 9A1 1 0 0 1 12 16H9a1 1 0 0 1-1-1v-3a1 1 0 0 1 .293-.707l9-9ZM10 12.414V14h1.586l8-8L18 4.414l-8 8ZM3 4a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2H5v14h14v-6a1 1 0 1 1 2 0v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 393 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="M17.657 6.343A8 8 0 1 0 6.343 17.657 8 8 0 0 0 17.657 6.343ZM4.929 4.93c3.905-3.905 10.237-3.905 14.142 0 3.905 3.905 3.905 10.237 0 14.142-3.905 3.905-10.237 3.905-14.142 0-3.905-3.905-3.905-10.237 0-14.142Zm3.536 9.192a1 1 0 0 1 1.414 0 3 3 0 0 0 4.243 0 1 1 0 0 1 1.414 1.415 5 5 0 0 1-7.071 0 1 1 0 0 1 0-1.415Z M10.5 9.5c0 .828-.56 1.5-1.25 1.5S8 10.328 8 9.5 8.56 8 9.25 8s1.25.672 1.25 1.5ZM16 9.5c0 .828-.56 1.5-1.25 1.5s-1.25-.672-1.25-1.5.56-1.5 1.25-1.5S16 8.672 16 9.5Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 623 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="M9.186 2.512a1.5 1.5 0 0 0-1.674 1.302L7.176 6.5H4a1.5 1.5 0 1 0 0 3h2.8l-.624 5H4a1.5 1.5 0 0 0 0 3h1.8l-.288 2.314a1.5 1.5 0 1 0 2.976.372l.336-2.686h4.977l-.29 2.314a1.5 1.5 0 1 0 2.977.372l.336-2.686H20a1.5 1.5 0 0 0 0-3h-2.8l.624-5H20a1.5 1.5 0 0 0 0-3h-1.8l.288-2.314a1.5 1.5 0 1 0-2.976-.372L15.176 6.5h-4.977l.29-2.314a1.5 1.5 0 0 0-1.303-1.674ZM9.2 14.5l.625-5h4.977l-.625 5H9.199Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 533 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M12.63 1.724a1 1 0 0 0-1.26 0l-8 6.5A1 1 0 0 0 3 9v11a1 1 0 0 0 1 1h5a1 1 0 0 0 1-1v-6h4v6a1 1 0 0 0 1 1h5a1 1 0 0 0 1-1V9a1 1 0 0 0-.37-.776l-8-6.5Z"/></svg>

After

Width:  |  Height:  |  Size: 252 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.37 1.724a1 1 0 0 1 1.26 0l8 6.5A1 1 0 0 1 21 9v11a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1v-5h-2v5a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V9a1 1 0 0 1 .37-.776l8-6.5ZM5 9.476V19h4v-5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v5h4V9.476l-7-5.688-7 5.688Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 367 B

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3 5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5Zm16 0H5v7.213l1.246-.932.044-.03a3 3 0 0 1 3.863.454c1.468 1.58 2.941 2.749 4.847 2.749 1.703 0 2.855-.555 4-1.618V5Zm0 10.357c-1.112.697-2.386 1.097-4 1.097-2.81 0-4.796-1.755-6.313-3.388a1 1 0 0 0-1.269-.164L5 14.712V19h14v-3.643ZM15 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-3 1a3 3 0 1 1 6 0 3 3 0 0 1-6 0Z" clip-rule="evenodd"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 1v7.213l1.246-.932.044-.03a3 3 0 0 1 3.863.454c1.468 1.58 2.941 2.749 4.847 2.749 1.703 0 2.855-.555 4-1.618V5H5Zm14 10.357c-1.112.697-2.386 1.097-4 1.097-2.81 0-4.796-1.755-6.313-3.388a1 1 0 0 0-1.269-.164L5 14.712V19h14v-3.643ZM15 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-3 1a3 3 0 1 1 6 0 3 3 0 0 1-6 0Z" clip-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 514 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="M5 11a6 6 0 1 1 12 0 6 6 0 0 1-12 0Zm6-8a8 8 0 1 0 4.906 14.32l3.387 3.387a1 1 0 0 0 1.414-1.414l-3.387-3.387A8 8 0 0 0 11 3Zm4 8a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 301 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="M4 12a8 8 0 1 1 4.445 7.169 1 1 0 0 0-.629-.088l-3.537.662.7-3.415a1 1 0 0 0-.09-.66A7.961 7.961 0 0 1 4 12Zm8-10C6.477 2 2 6.477 2 12c0 1.523.341 2.968.951 4.262l-.93 4.537a1 1 0 0 0 1.163 1.184l4.68-.876A9.968 9.968 0 0 0 12 22c5.523 0 10-4.477 10-10S17.523 2 12 2ZM7.5 13.25a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5Zm4.5 0a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5Zm4.5 0a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 567 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="M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10a9.968 9.968 0 0 1-4.136-.893l-4.68.876a1 1 0 0 1-1.164-1.184l.931-4.537A9.965 9.965 0 0 1 2 12Zm4.25 0a1.25 1.25 0 1 0 2.5 0 1.25 1.25 0 0 0-2.5 0Zm4.5 0a1.25 1.25 0 1 0 2.5 0 1.25 1.25 0 0 0-2.5 0Zm5.75 1.25a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 453 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" d="M8.004 5a1 1 0 0 0-.43-.822c-.57-.395-1.176-.031-1.685.255-.428.24-.998.614-1.569 1.15C3.166 6.665 2.004 8.415 2.004 11v8a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1v-8a1 1 0 0 0-1-1h-2V5ZM19.004 5a1 1 0 0 0-.43-.822c-.57-.395-1.176-.031-1.685.255-.428.24-.998.614-1.569 1.15-1.154 1.082-2.316 2.832-2.316 5.417v8a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1v-8a1 1 0 0 0-1-1h-2V5Z"/></svg>

After

Width:  |  Height:  |  Size: 455 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="M7.574 4.178a1 1 0 0 1 .43.822v5h2a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1h-7a1 1 0 0 1-1-1v-8c0-2.585 1.162-4.335 2.316-5.417a8.163 8.163 0 0 1 1.569-1.15 7.029 7.029 0 0 1 .738-.36l.016-.005.005-.003h.003v-.001c.001 0 .002 0 .353.936l-.351-.936a1 1 0 0 1 .92.114Zm-1.57 2.588a5.99 5.99 0 0 0-.316.276C4.842 7.835 4.004 9.085 4.004 11v7h5v-6h-2a1 1 0 0 1-1-1V6.766Zm12.57-2.588a1 1 0 0 1 .43.822v5h2a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1h-7a1 1 0 0 1-1-1v-8c0-2.585 1.162-4.335 2.316-5.417a8.166 8.166 0 0 1 1.569-1.15 7.038 7.038 0 0 1 .738-.36l.016-.005.005-.003h.003v-.001c.001 0 .002 0 .353.936l-.351-.936a1 1 0 0 1 .92.114Zm-1.57 2.588c-.105.085-.21.177-.316.276-.846.793-1.684 2.043-1.684 3.958v7h5v-6h-2a1 1 0 0 1-1-1V6.766Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 857 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="M7.5 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM12 12c-4.758 0-8.083 3.521-8.496 7.906A1 1 0 0 0 4.5 21H15a3 3 0 1 1 0-6c0-.824.332-1.571.87-2.113C14.739 12.32 13.435 12 12 12Zm6 2a1 1 0 0 1 1 1v2h2a1 1 0 1 1 0 2h-2v2a1 1 0 1 1-2 0v-2h-2a1 1 0 1 1 0-2h2v-2a1 1 0 0 1 1-1Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 412 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 4a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5ZM7.5 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM5.678 19c.71-2.909 3.092-5 6.322-5 .621 0 1.206.077 1.748.218a1 1 0 1 0 .504-1.936A8.931 8.931 0 0 0 12 12c-4.758 0-8.083 3.521-8.496 7.906A1 1 0 0 0 4.5 21H11a1 1 0 1 0 0-2H5.678ZM18 14a1 1 0 0 1 1 1v2h2a1 1 0 1 1 0 2h-2v2a1 1 0 1 1-2 0v-2h-2a1 1 0 1 1 0-2h2v-2a1 1 0 0 1 1-1Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 508 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="M16.293 2.293a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1 0 1.414l-3 3a1 1 0 0 1-1.414-1.414L17.586 7H5v4a1 1 0 1 1-2 0V6a1 1 0 0 1 1-1h13.586l-1.293-1.293a1 1 0 0 1 0-1.414ZM21 13v5a1 1 0 0 1-1 1H6.414l1.293 1.293a1 1 0 1 1-1.414 1.414l-3-3a1 1 0 0 1 0-1.414l3-3a1 1 0 0 1 1.414 1.414L6.414 17H19v-4a1 1 0 1 1 2 0Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 446 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="M16.793 2.293a1 1 0 0 1 1.414 0L20.5 4.586a2 2 0 0 1 0 2.828l-2.293 2.293a1 1 0 0 1-1.414-1.414L18.086 7H7a2 2 0 0 0-2 2v2a1 1 0 1 1-2 0V9a4 4 0 0 1 4-4h11.086l-1.293-1.293a1 1 0 0 1 0-1.414ZM20 12a1 1 0 0 1 1 1v2a4 4 0 0 1-4 4H5.914l1.293 1.293a1 1 0 1 1-1.414 1.414L3.5 19.414a2 2 0 0 1 0-2.828l2.293-2.293a1 1 0 0 1 1.414 1.414L5.914 17H17a2 2 0 0 0 2-2v-2a1 1 0 0 1 1-1Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 517 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="M9.996 2.869A1.951 1.951 0 0 1 11.62 2h.76c.653 0 1.262.326 1.624.869l1.141 1.712 1.749-.404a1.951 1.951 0 0 1 1.819.522l.588.589c.476.475.673 1.162.522 1.818l-.404 1.749 1.712 1.141c.543.362.869.971.869 1.624v.76c0 .653-.326 1.262-.869 1.624l-1.712 1.141.404 1.749a1.951 1.951 0 0 1-.522 1.819l-.588.588a1.951 1.951 0 0 1-1.819.522l-1.749-.404-1.141 1.712A1.951 1.951 0 0 1 12.38 22h-.76a1.951 1.951 0 0 1-1.624-.869L8.855 19.42l-1.749.404a1.951 1.951 0 0 1-1.818-.522l-.59-.588a1.951 1.951 0 0 1-.52-1.819l.403-1.749-1.712-1.141A1.951 1.951 0 0 1 2 12.38v-.76c0-.653.326-1.262.869-1.624L4.58 8.855l-.404-1.749A1.951 1.951 0 0 1 4.7 5.288l.589-.59a1.951 1.951 0 0 1 1.818-.52l1.749.403 1.141-1.712ZM8.5 12a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 886 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 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10Zm3-12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm-3 10a7.976 7.976 0 0 1-5.714-2.4C7.618 16.004 9.605 15 12 15c2.396 0 4.383 1.005 5.714 2.6A7.976 7.976 0 0 1 12 20Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 366 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 0 0-5.935 13.365C7.56 15.895 9.612 15 12 15c2.388 0 4.44.894 5.935 2.365A8 8 0 0 0 12 4Zm4.412 14.675C15.298 17.636 13.792 17 12 17c-1.791 0-3.298.636-4.412 1.675A7.96 7.96 0 0 0 12 20a7.96 7.96 0 0 0 4.412-1.325ZM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10a9.98 9.98 0 0 1-3.462 7.567A9.965 9.965 0 0 1 12 22a9.965 9.965 0 0 1-6.538-2.433A9.98 9.98 0 0 1 2 12Zm10-4a2 2 0 1 0 0 4 2 2 0 0 0 0-4Zm-4 2a4 4 0 1 1 8 0 4 4 0 0 1-8 0Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 581 B

+7 -4
View File
@@ -8,9 +8,6 @@ module.exports = function (api) {
{
lazyImports: true,
native: {
// We should be able to remove this after upgrading Expo
// to a version that includes https://github.com/expo/expo/pull/24672.
unstable_transformProfile: 'hermes-stable',
// Disable ESM -> CJS compilation because Metro takes care of it.
// However, we need it in Jest tests since those run without Metro.
disableImportExportTransform: !isTestEnv,
@@ -19,6 +16,13 @@ module.exports = function (api) {
],
],
plugins: [
'macros',
[
'babel-plugin-react-compiler',
{
runtimeModule: 'react-compiler-runtime',
},
],
[
'module:react-native-dotenv',
{
@@ -46,7 +50,6 @@ module.exports = function (api) {
},
},
],
'macros',
'react-native-reanimated/plugin', // NOTE: this plugin MUST be last
],
env: {
+1 -1
View File
@@ -15,6 +15,6 @@
"parserOptions": {
"sourceType": "module",
"ecmaVersion": "latest",
"project": "./tsconfig.json"
"project": "./bskyembed/tsconfig.json"
}
}
+3 -2
View File
@@ -193,7 +193,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">
<img src={infoIcon as string} className="w-4 h-4 shrink-0 mt-0.5" />
<img src={infoIcon} className="w-4 h-4 shrink-0 mt-0.5" />
<p className="text-sm text-textLight">{children}</p>
</div>
)
@@ -293,7 +293,8 @@ function ExternalEmbed({
return (
<Link
href={content.external.uri}
className="w-full rounded-lg overflow-hidden border flex flex-col items-stretch">
className="w-full rounded-lg overflow-hidden border flex flex-col items-stretch"
disableTracking>
{content.external.thumb && (
<img
src={content.external.thumb}
+5 -3
View File
@@ -3,10 +3,12 @@ import {h} from 'preact'
export function Link({
href,
className,
disableTracking,
...props
}: {
href: string
className?: string
disableTracking?: boolean
} & h.JSX.HTMLAttributes<HTMLAnchorElement>) {
const searchParam = new URLSearchParams(window.location.search)
const ref_url = searchParam.get('ref_url')
@@ -19,9 +21,9 @@ export function Link({
return (
<a
href={`${
href.startsWith('http') ? href : `https://bsky.app${href}`
}?${newSearchParam.toString()}`}
href={`${href.startsWith('http') ? href : `https://bsky.app${href}`}${
disableTracking ? '' : `?${newSearchParam.toString()}`
}`}
target="_blank"
rel="noopener noreferrer nofollow"
onClick={evt => evt.stopPropagation()}
+24 -9
View File
@@ -1,4 +1,9 @@
import {AppBskyFeedDefs, AppBskyFeedPost, RichText} from '@atproto/api'
import {
AppBskyFeedDefs,
AppBskyFeedPost,
AppBskyRichtextFacet,
RichText,
} from '@atproto/api'
import {h} from 'preact'
import replyIcon from '../../assets/bubble_filled_stroke2_corner2_rounded.svg'
@@ -56,7 +61,7 @@ export function Post({thread}: Props) {
<Link
href={href}
className="transition-transform hover:scale-110 shrink-0 self-start">
<img src={logo as string} className="h-8" />
<img src={logo} className="h-8" />
</Link>
</div>
<PostContent record={record} />
@@ -71,7 +76,7 @@ export function Post({thread}: Props) {
<div className="border-t w-full pt-2.5 flex items-center gap-5 text-sm cursor-pointer">
{!!post.likeCount && (
<div className="flex items-center gap-2 cursor-pointer">
<img src={likeIcon as string} className="w-5 h-5" />
<img src={likeIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px">
{post.likeCount}
</p>
@@ -79,14 +84,14 @@ export function Post({thread}: Props) {
)}
{!!post.repostCount && (
<div className="flex items-center gap-2 cursor-pointer">
<img src={repostIcon as string} className="w-5 h-5" />
<img src={repostIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px">
{post.repostCount}
</p>
</div>
)}
<div className="flex items-center gap-2 cursor-pointer">
<img src={replyIcon as string} className="w-5 h-5" />
<img src={replyIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px">Reply</p>
</div>
<div className="flex-1" />
@@ -118,16 +123,23 @@ function PostContent({record}: {record: AppBskyFeedPost.Record | null}) {
let counter = 0
for (const segment of rt.segments()) {
if (segment.isLink() && segment.link) {
if (
segment.link &&
AppBskyRichtextFacet.validateLink(segment.link).success
) {
richText.push(
<Link
key={counter}
href={segment.link.uri}
className="text-blue-400 hover:underline">
className="text-blue-400 hover:underline"
disableTracking={!segment.link.uri.startsWith('https://bsky.app')}>
{segment.text}
</Link>,
)
} else if (segment.isMention() && segment.mention) {
} else if (
segment.mention &&
AppBskyRichtextFacet.validateMention(segment.mention).success
) {
richText.push(
<Link
key={counter}
@@ -136,7 +148,10 @@ function PostContent({record}: {record: AppBskyFeedPost.Record | null}) {
{segment.text}
</Link>,
)
} else if (segment.isTag() && segment.tag) {
} else if (
segment.tag &&
AppBskyRichtextFacet.validateTag(segment.tag).success
) {
richText.push(
<Link
key={counter}
+2 -2
View File
@@ -112,7 +112,7 @@ function LandingPage() {
<Link
href="https://bsky.social/about"
className="transition-transform hover:scale-110">
<img src={logo as string} className="h-10" />
<img src={logo} className="h-10" />
</Link>
<h1 className="text-4xl font-bold text-center">Embed a Bluesky Post</h1>
@@ -125,7 +125,7 @@ function LandingPage() {
placeholder={DEFAULT_POST}
/>
<img src={arrowBottom as string} className="w-6" />
<img src={arrowBottom} className="w-6" />
{loading ? (
<Skeleton />
+2 -2
View File
@@ -52,7 +52,7 @@ function PwiOptOut({thread}: {thread: AppBskyFeedDefs.ThreadViewPost}) {
<Link
href={href}
className="transition-transform hover:scale-110 absolute top-4 right-4">
<img src={logo as string} className="h-6" />
<img src={logo} className="h-6" />
</Link>
<div className="w-full py-12 gap-4 flex flex-col items-center">
<p className="max-w-80 text-center w-full text-textLight">
@@ -75,7 +75,7 @@ function ErrorMessage() {
<Link
href="https://bsky.app/"
className="transition-transform hover:scale-110 absolute top-4 right-4">
<img src={logo as string} className="h-6" />
<img src={logo} className="h-6" />
</Link>
<p className="my-16 text-center w-full text-textLight">
Post not found, it may have been deleted.
+4 -2
View File
@@ -5,7 +5,6 @@ import (
"fmt"
"net/http"
"strings"
"time"
appbsky "github.com/bluesky-social/indigo/api/bsky"
"github.com/bluesky-social/indigo/atproto/syntax"
@@ -13,6 +12,9 @@ import (
"github.com/labstack/echo/v4"
)
// time.RFC822Z, but with four digit year. used for RSS pubData.
var FullYearRFC822Z = "02 Jan 2006 15:04 -0700"
type ItemGUID struct {
XMLName xml.Name `xml:"guid"`
Value string `xml:",chardata"`
@@ -107,7 +109,7 @@ func (srv *Server) WebProfileRSS(c echo.Context) error {
pubDate := ""
createdAt, err := syntax.ParseDatetimeLenient(rec.CreatedAt)
if nil == err {
pubDate = createdAt.Time().Format(time.RFC822Z)
pubDate = createdAt.Time().Format(FullYearRFC822Z)
}
posts = append(posts, Item{
Link: fmt.Sprintf("https://%s/profile/%s/post/%s", req.Host, pv.Handle, aturi.RecordKey().String()),
+21 -7
View File
@@ -47,6 +47,14 @@
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif;
}
#preload {
width: 100px;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
/* Buttons and inputs have a font set by UA, so we'll have to reset that */
button, input, textarea {
font: inherit;
@@ -262,13 +270,19 @@
</head>
<body>
{%- block body_all %}
<div id="root"></div>
<noscript>
<h1 lang="en">JavaScript Required</h1>
<p lang="en">This is a heavily interactive web application, and JavaScript is required. Simple HTML interfaces are possible, but that is not what this is.
<p lang="en">Learn more about Bluesky at <a href="https://bsky.social">bsky.social</a> and <a href="https://atproto.com">atproto.com</a>.
{% block noscript_extra %}{% endblock %}
</noscript>
<div id="root">
<div id="preload">
<!-- Bluesky SVG -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 320"><path fill="#0085ff" d="M180 142c-16.3-31.7-60.7-90.8-102-120C38.5-5.9 23.4-1 13.5 3.4 2.1 8.6 0 26.2 0 36.5c0 10.4 5.7 84.8 9.4 97.2 12.2 41 55.7 55 95.7 50.5-58.7 8.6-110.8 30-42.4 106.1 75.1 77.9 103-16.7 117.3-64.6 14.3 48 30.8 139 116 64.6 64-64.6 17.6-97.5-41.1-106.1 40 4.4 83.5-9.5 95.7-50.5 3.7-12.4 9.4-86.8 9.4-97.2 0-10.3-2-27.9-13.5-33C336.5-1 321.5-6 282 22c-41.3 29.2-85.7 88.3-102 120Z"/></svg>
</div>
</div>
<noscript>
<h1 lang="en">JavaScript Required</h1>
<p lang="en">This is a heavily interactive web application, and JavaScript is required. Simple HTML interfaces are possible, but that is not what this is.
<p lang="en">Learn more about Bluesky at <a href="https://bsky.social">bsky.social</a> and <a href="https://atproto.com">atproto.com</a>.
{% block noscript_extra %}{% endblock %}
</noscript>
{% endblock -%}
</body>
</html>
+5 -9
View File
@@ -4,7 +4,10 @@
- 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`
- Check if you've installed Cocoapods through `homebrew`. If you have, remove it:
- `brew info cocoapods`
- If output says `Installed`:
@@ -16,10 +19,6 @@
- Add `eval "$(rbenv init - zsh)"` to your `~/.zshrc`
- From inside the project directory:
- `bundler install` (this will install Cocoapods)
- Setup your environment [for e2e testing using detox](https://wix.github.io/Detox/docs/introduction/getting-started):
- `yarn global add detox-cli`
- `brew tap wix/brew`
- `brew install applesimutils`
- 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
@@ -120,10 +119,7 @@ To open the [Developer Menu](https://docs.expo.dev/debugging/tools/#developer-me
### Running E2E Tests
- Make sure you've set your environment following the above
- Make sure Metro and the dev server are running
- Run `yarn e2e`
- Find the artifacts in the `artifact` folder
See [testing.md](./testing.md).
### Polyfills
+81
View File
@@ -0,0 +1,81 @@
# OTA Deployments
## Overview
![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
(iOS) or delivered in Slack (Android).
## Production Deployments
### Prerequisites
- Remove any internal client from your device and download the client from the App Store/Google Play. This will help for
testing as well as retrieving the build number.
- You should have signed in to EAS locally through npx eas login. You will need to modify the build number in a
subsequent step.
- Identify the build number of the production app you want to deploy an update for. iOS and Android build numbers are
divergent, so you will need to find both
![app-build-number](./img/app-build-number.png)
- 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.
### Preparation
- 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.
### Deployment
- Update the build number through EAS
- 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 number to the appropriate build number 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`
- 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”
In about five minutes, the new deployment should be available for download. To test:
- 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.
Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

+10 -4
View File
@@ -3,13 +3,19 @@
Make sure you've copied `.env.example` to `.env.test` and provided any required
values.
### Using Maestro E2E tests
## Using Maestro
1. Install Maestro by following [these instructions](https://maestro.mobile.dev/getting-started/installing-maestro). This will help us run the E2E tests.
2. You can write Maestro tests in `__e2e__/maestro` directory by creating a new `.yaml` file or by modifying an existing one.
3. You can also use [Maestro Studio](https://maestro.mobile.dev/getting-started/maestro-studio) which automatically generates commands by recording your actions on the app. Therefore, you can create realistic tests without having to manually write any code. Use the `maestro studio` command to start recording your actions.
2. You can write Maestro tests in `/.maestro/flows/` directory by creating a new `.yml` file or by modifying an existing one.
3. You can also use [Maestro Studio](https://maestro.mobile.dev/getting-started/maestro-studio) which automatically generates commands by recording your actions on the app. Therefore, you can create realistic tests without having to manually write any code. Use the `maestro studio` command to start recording your actions.
### Running Maestro tests
### Using Flashlight for Performance Testing
- In one tab, run `yarn e2e:mock-server`
- In a second tab, run `yarn e2e:metro`
- In a third tab, run `yarn e2e:run`
## Using Flashlight for Performance Testing
1. Make sure Maestro is installed (optional: only for automated testing) by following the instructions above
2. Install Flashlight by following [these instructions](https://docs.flashlight.dev/)
3. The simplest way to get started is by running `yarn perf:measure` which will run a live preview of the performance test results. You can [see a demo here](https://github.com/bamlab/flashlight/assets/4534323/4038a342-f145-4c3b-8cde-17949bf52612)
+14
View File
@@ -46,6 +46,20 @@
"EXPO_PUBLIC_ENV": "production"
}
},
"production-apk": {
"extends": "base",
"distribution": "internal",
"ios": {
"autoIncrement": false
},
"android": {
"autoIncrement": false
},
"channel": "production",
"env": {
"EXPO_PUBLIC_ENV": "production"
}
},
"testflight": {
"extends": "base",
"ios": {
+7 -2
View File
@@ -1,10 +1,10 @@
/* global jest */
import {configure} from '@testing-library/react-native'
import 'react-native-gesture-handler/jestSetup'
// IMPORTANT: this is what's used in the native runtime
import 'react-native-url-polyfill/auto'
import {configure} from '@testing-library/react-native'
configure({asyncUtilTimeout: 20000})
jest.mock('@react-native-async-storage/async-storage', () =>
@@ -90,3 +90,8 @@ jest.mock('sentry-expo', () => ({
}))
jest.mock('crypto', () => ({}))
jest.mock('expo-application', () => ({
nativeApplicationVersion: '1.0.0',
nativeBuildVersion: '1',
}))

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