Compare commits

...

664 Commits

Author SHA1 Message Date
Paul Frazee c16f5d2335 Speed up transition speeds a bit 2023-03-10 18:29:37 -06:00
Paul Frazee 320d69920e Fix drawer behaviors 2023-03-10 18:22:58 -06:00
Paul Frazee d4d1fb820b Handle all navigations from the state layer 2023-03-10 15:25:01 -06:00
Paul Frazee 330a1a0be4 Handle notifee card presses 2023-03-10 15:08:29 -06:00
Paul Frazee 3df953b73d Remove react-native-gesture-handler (no longer used) 2023-03-10 14:47:54 -06:00
Paul Frazee 97c5d4d965 Implement not-found page 2023-03-10 14:24:10 -06:00
Paul Frazee b2300a8381 Fix tsc 2023-03-10 14:14:39 -06:00
Paul Frazee 5accb619ac Restore the error boundary 2023-03-10 13:28:50 -06:00
Paul Frazee ebb0b11774 Restructure the shell folder and fix the header positioning 2023-03-10 13:24:50 -06:00
Paul Frazee 3b0d72b776 Replace the navigation model with react-navigation 2023-03-10 01:01:51 -06:00
Paul Frazee bf1f743382 Factor out some helpers 2023-03-09 21:39:08 -06:00
Paul Frazee de5ee3c768 Fixes to drawer and bottombar 2023-03-09 21:32:44 -06:00
Paul Frazee 0d92dd8306 Update mobile menu to be react-native drawer 2023-03-09 21:16:58 -06:00
Paul Frazee 5b3eeaf747 Update BottomBar for react navigation 2023-03-09 20:43:43 -06:00
Paul Frazee df4dee6db2 Convert all screens to react navigation 2023-03-09 20:02:54 -06:00
Paul Frazee 6a4961caa5 WIP Switch to react-navigation 3 2023-03-09 18:45:59 -06:00
Paul Frazee bf951421ea WIP Switch to react-navigation 2 2023-03-09 14:54:49 -06:00
Paul Frazee 34050e05be WIP Switch to react-navigation 2023-03-09 13:45:20 -06:00
Paul Frazee ce7817d2fb 1.7 2023-03-08 22:07:12 -06:00
Paul Frazee 0c7f61046c Get Web compiling for expo 2023-03-08 17:59:25 -06:00
Paul Frazee 2c41458963 Fix icon fill 2023-03-08 17:32:52 -06:00
Paul Frazee 3560291329 Modify some dependency versions to make expo happy 2023-03-08 17:27:07 -06:00
Paul Frazee d073c66c5d Tweak plist 2023-03-08 14:36:26 -06:00
Paul Frazee 15a18d9dd3 Disable the 'require cycle' warning 2023-03-08 14:32:11 -06:00
Paul Frazee 7c481c343e Finish adding expo 2023-03-08 14:28:50 -06:00
Paul Frazee 360322f475 Fix tsc 2023-03-08 13:57:58 -06:00
Paul Frazee 18347bdb22 WIP - adding expo 2 2023-03-08 13:53:00 -06:00
Paul Frazee bc46714ca5 WIP - adding expo 2023-03-08 13:00:54 -06:00
Paul Frazee 150db9bcc3 Fix lint 2023-03-07 17:18:49 -06:00
Paul Frazee f297ad6946 Another set of UI updates (FAB returns, a few others) (#281)
* Bring back the FAB and move compose out of the footer

* Increase the touch target sizes of the header back btns (close #279)

* Trigger 'load more' sooner (close #280)
2023-03-07 17:17:44 -06:00
Paul Frazee 30b01ade2c Big batch of UI updates (#276)
* Replace react-native-root-toast with a custom toast that fits the visual style

* Tune dark mode colors

* Tune colors a bit more

* Move the reply prompt to a fixed position in the footer

* Fully hide muted posts but give a control to show anyway (close #270)

* Improve thread rendering (better clarity on reply lines)

* Add follower/following counts to side menu

* Fix issues with display name overflows
2023-03-07 15:52:24 -06:00
Paul Frazee 1044c8bb8b Handle-change modal with custom domain support (#273)
* Dont append the server's domain name when a custom domain is used

* Update the settings look & feel and add a tool to remove accounts from the switcher

* Try not rendering the bottomsheet when no modal is active.

There are cases where the bottomsheet decides to show itself when
it's not supposed to. It seems obvious to do what this change is
doing -- just dont render bottomsheet if no modal is active -- but
previously we experienced issues with that approach. This time it
seems to be working, so we're gonna yolo try it.

* Implement a handle-change modal with support for custom domains (closes #65)
2023-03-06 21:37:48 -06:00
Paul Frazee d6568c33e0 Fix typo 2023-03-06 15:46:44 -06:00
Paul Frazee 42f88d13bc Fix: fetch follows before everything else to avoid rendering follow buttons wrongly 2023-03-06 15:40:52 -06:00
Paul Frazee 77db31b913 Tune the menu's dark mode bg color 2023-03-06 15:39:58 -06:00
Paul Frazee 75f34c5bb8 Fix the darkmode icon in the menu 2023-03-06 15:38:52 -06:00
Paul Frazee e574c8404a Onboarding tweaks (#272)
* Small fix to side menu rendering

* Change onboarding to use an explicit 'is onboarding' mode to more clearly control the flow

* Add a progress bar to the welcome banner

* Dont show the 'unfollow button' on posts in weird times (close #271)

* Improve the empty state of the feed

* Only suggest recent posts
2023-03-06 15:34:22 -06:00
Paul Frazee be4bb79502 Show replies in the main feed if they have 2 or more upvotes (#269) 2023-03-06 14:49:42 -06:00
Paul Frazee 9f29bd78c9 Factor out the bottom bar and layer it under the side menu (close #243) (#268) 2023-03-06 11:59:06 -06:00
Paul Frazee 87ac7c42cd 1.6 2023-03-06 10:55:45 -06:00
Paul Frazee c6d1aa2c9c Look & feel updates: replace the "FAB" with a footer menu item, update the side menu (#263)
* Remove old tab controls from the mobile shell

* Add 'compose' and 'profile' to the footer; remove the FAB

* Fix lint

* Tune the footer icons

* Tune the 'current' state of footer icons

* Add 2xl text styles

* Tune the footer icons a bit more

* Fix lint

* More footer tuning
2023-03-06 10:54:56 -06:00
Paul Frazee 7417ea3714 1.5 2023-03-03 14:44:00 -08:00
Paul Frazee 4e42d05f56 Add an x button to the search to clear the input 2023-03-03 14:38:59 -08:00
Paul Frazee d5e3fa2d4a Turn links to posts into quote posts (#262)
* Turn links to posts into quote posts

* Fix lint
2023-03-03 16:30:33 -06:00
arcalinea 44cc4c58dd New user constants (#260)
* update users

* update

* With constructed intro feed, only grab 20 random suggested users to avoid perf issues

* Don't 'check for latest' in the feed with the suggestions feed

* Show/hide the welcome banner on account change (close #257)

---------

Co-authored-by: Jay Graber <arcalinea@gmail.com>
Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2023-03-03 15:37:17 -06:00
Paul Frazee 33be8a1d59 Move the translate item to the top of the menu 2023-03-03 13:19:00 -08:00
Paul Frazee 6488aade12 Add translate link to post menu (#261)
* Add a google translate menu item to posts

* Fix: make sure the dropdown menu is always visible (when low on the screen)
2023-03-03 15:13:31 -06:00
Paul Frazee c9441963a5 Remove replies from the home feed (#259)
* Remove replies from the home feed (close #252)

* Increase the 'load more' threshhold
2023-03-03 14:43:18 -06:00
Paul Frazee d7b8394b14 Fix dark mode ellipsis on posts 2023-03-03 12:05:38 -08:00
Paul Frazee 98e3b96b23 Edit profile fixes (#258)
* Fix: only clear banner or avi when requested in edit profile

* Set the default snap points to 90% to ensure the modal never fails to raise
2023-03-03 14:02:40 -06:00
Paul Frazee 401739a4b0 1.4 2023-03-02 17:02:46 -08:00
Ansh c1126bf5d5 72-delete-avatar-and-cover (#255)
* allow to delete profile pic

* allow for removing banner
2023-03-02 18:53:18 -06:00
Ansh 645aad0833 make authorAvatar optional prop (#254) 2023-03-02 18:51:13 -06:00
Paul Frazee 08178f01b1 Minor improvements to web autocomplete in composer 2023-03-02 16:43:19 -08:00
Ansh ee7fca7381 73-post-embeds (#253)
* update api to 0.1.3

* add repost modal with reposting functionality

* add quote post UI

* allow creation and view of quote posts

* Validate the post record before rendering a quote post

* Use createdAt in quote posts for now

* add web modal support

* Tune the quote post rendering

* Make did and declarationCid optional in postmeta

* Make did and declarationCid optional in postmeta

* dont allow image or link preview if quote post

* Handle no-text quote posts

* Tune the repost modal

* Tweak composer post text

* Fix lint

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2023-03-02 18:09:48 -06:00
Paul Frazee 5a59784fe7 Quick fixes to dark mode character counter colors 2023-03-02 13:59:44 -08:00
Paul Frazee 34cc7cb5f8 Increase network timeouts (closes #248) (#249)
* Increase network timeouts (close #248)

* Fix: on post error only update the ext link card if it's in use
2023-03-02 13:31:16 -06:00
Paul Frazee 9e9a446c03 Trim whitespace from the invite code (close #245) (#247) 2023-03-02 12:42:52 -06:00
Ansh d1dacfa8b0 New onboarding (#241)
* delete old onboarding files and code

* add custom FollowButton component to Post, FeedItem, & ProfileCard

* move building suggested feed into helper lib

* show suggested posts/feed if follower list is empty

* Update tsconfig.json

* add pagination to getting new onboarding

* remove unnecessary console log

* fix naming, add better null check for combinedCursor

* In locally-combined feeds, correctly produce an undefined cursor when out of data

* Minor refactors of the suggested posts lib functions

* Show 'follow button' style of post meta in certain conditions only

* Only show follow btn in posts on the main feed and the discovery feed

* Add a welcome notice to the home feed

* Tune the timing of when the welcome banner shows or hides

* Make the follow button an observer (closes #244)

* Update postmeta to keep the follow btn after press until next render

* A couple of fixes that ensure consistent welcome screen

* Fix lint

* Rework the welcome banner

* Fix cache invalidation of follows model on user switch

* Show welcome banner while loading

* Update the home onboarding feed to get top posts from hardcode recommends

* Drop unused helper function

* Update happy path tests

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2023-03-02 12:21:33 -06:00
Paul Frazee 9bbf9ae7f4 A couple various fixes (#242)
* Fix: set the status bar color for dark mode when logging in

* Add some logging

* Improve read/unread tracking behaviors in notifications
2023-03-01 16:54:50 -06:00
Paul Frazee 1561ff64c4 1.3 2023-03-01 09:13:43 -08:00
Paul Frazee d53caa390b Fixes to dark mode (#238) 2023-03-01 10:35:56 -06:00
Paul Frazee a6e9ebec6e Fix tests for march 1st 2023-03-01 08:35:25 -08:00
Paul Frazee aca5cfd202 Add a temporary lexicon refactor guard (#235)
* Add a temporary lexicon refactor guard

* Fix test

* Fix tsconfig formatting
2023-02-28 11:57:49 -06:00
Paul Frazee 6885bccdff Remove leftover log 2023-02-28 09:08:36 -08:00
Paul Frazee 23bbfebfda Add analytics identify() call with hashed email 2023-02-28 09:03:44 -08:00
Paul Frazee a2c8f727b9 Fix analytics in native build 2023-02-27 11:08:01 -06:00
Paul Frazee dd00191782 Better fix to native modals 2023-02-27 10:59:19 -06:00
Paul Frazee 9b78718276 Fix to native modals 2023-02-27 10:54:44 -06:00
Paul Frazee 9450694742 Fix tsconfig for jsx 2023-02-27 10:52:22 -06:00
Paul Frazee 7712cd2ea0 Fix import 2023-02-27 10:47:39 -06:00
Paul Frazee 26031d4ac3 Fix lint 2023-02-27 10:45:59 -06:00
Paul Frazee f460e39e71 Fix tests 2023-02-27 10:44:42 -06:00
Paul Frazee 52cefa2f92 Sync browser navigation with app 2023-02-24 17:47:53 -06:00
Paul Frazee f0c71b1790 Clean up desktop web header search 2023-02-24 12:25:02 -06:00
Paul Frazee 274fa773df Hold off on customizing web feed rendering for now 2023-02-24 11:51:35 -06:00
Paul Frazee 8322aa9f4d Simplify the desktop search screen 2023-02-24 11:49:25 -06:00
Paul Frazee d97c82a0b9 Fixes to lineheight on web to counteract emoji issues 2023-02-24 11:40:43 -06:00
Paul Frazee 8b67d26a2d Remove the desktop right column for now 2023-02-24 11:29:27 -06:00
Paul Frazee 8ea64e9564 Fix region sizing on web 2023-02-24 10:10:21 -06:00
Paul Frazee 0ef938ff49 Replace some old modal models that got missed 2023-02-24 10:07:01 -06:00
Michael Staub f38225243b fix: webpack flags 2023-02-23 16:35:11 -08:00
Michael Staub 4d08884e0e Merge branch 'rnw' of github.com:bluesky-social/social-app into rnw 2023-02-23 16:34:25 -08:00
Michael Staub 742dff16eb fix: commit yarn.lock file 2023-02-23 16:33:06 -08:00
Michael Staub 30d895fa2e fix: webpack hot reloading 2023-02-23 16:32:56 -08:00
Michael Staub 629ac2d426 feat: implement DesktopSearch component 2023-02-23 16:32:46 -08:00
Paul Frazee 6dd10c1b91 Update modal com name 2023-02-23 17:29:34 -06:00
Paul Frazee 3c6046c7b7 Rework modals to support multiple active 2023-02-23 17:22:03 -06:00
Paul Frazee b86959b9af Add setImmediate polyfill to web, fixing dropdown items 2023-02-23 16:42:52 -06:00
Paul Frazee d84f3a10f1 Implement image uploading in the web composer 2023-02-23 16:02:31 -06:00
Michael Staub 63fb4d2805 fix: browser history 2023-02-23 13:52:12 -08:00
Paul Frazee 1f96e33827 Show a 'not available for mobile web' screen (temporary) 2023-02-23 12:39:10 -06:00
Paul Frazee f55c25feb7 Tweak approach to the viewheader 2023-02-23 12:26:25 -06:00
Paul Frazee 60c25cef98 Web: go lighter for now, ditch the composer prompt in feed 2023-02-23 10:48:50 -06:00
Paul Frazee b0109448d8 Missed in last commit 2023-02-23 10:25:24 -06:00
Paul Frazee df4c31d602 Move all of the web left-nav shell into the header 2023-02-23 10:19:21 -06:00
Paul Frazee 560c6183fb Change web shell to use permanent header 2023-02-23 09:38:02 -06:00
Paul Frazee 4a468d3513 Update web header and search 2023-02-23 01:07:20 -06:00
Paul Frazee e6d22bdf90 Rework web shell ui 2023-02-22 23:37:14 -06:00
Paul Frazee cfd563c782 Fix temporary web useAnalytics hook 2023-02-22 21:23:22 -06:00
Paul Frazee 8ef6b108a3 Fix ref forwarding in web 2023-02-22 21:21:17 -06:00
Paul Frazee f42e08008f Merge main into the Web PR (#230)
* Update to RN 71.1.0 (#100)

* Update to RN 71

* Adds missing lint plugin

* Add missing native changes

* Bump @atproto/api@0.0.7 (#112)

* Image not loading on swipe (#114)

* Adds prefetching to images

* Adds image prefetch

* bugfix for images not showing on swipe

* Fixes prefetch bug

* Update src/view/com/util/PostEmbeds.tsx

---------

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

* Fixes to session management (#117)

* Update session-management to solve incorrectly dropped sessions

* Reset the nav on account switch

* Reset the feed on me.load()

* Update tests to reflect new account-switching behavior

* Increase max image resolutions and sizes (#118)

* Slightly increase the hitslop for post controls

* Fix character counter color in dark mode

* Update login to use new session.create api, which enables email login (close #93) (#119)

* Replaces the alert with dropdown for profile image and banner (#123)

* replaces the alert with dropdown for profile image and banner

* lint

* Fix to ordering of images in the embed grid (#121)

* Add explicit link-embed controls to the composer (#120)

* Add explicit link-embed controls

* Update the target rez/size of link embed thumbs

* Remove the alert before publishing without a link card

* [Draft] Fixes image failing on reupload issue (#128)

* Fixes image failing on reupload issue

* Use tmp folder instead of documents

* lint

* Image performance improvements (#126)

* Switch out most images for FastImage

* Add image loading placeholders

* Fix tests

* Collection of fixes to list rendering (#127)

* Fix bug that caused endless spinners in profile feeds

* Bundle fetches of suggested actors into one update

* Fixes to suggested follow rendering

* Fix missing replacement of flex:1 to height:100

* Fixes to navigation swipes (#129)

* Nav swipe: increase the distance traveled in response to gesture movement.

This causes swipes to feel faster and more responsive.

* Fix: fully clamp the swipe against the edge

* Improve the performance of swipes by skipping the interaction manager

* Adds dark mode to the edit screen (#130)

* Adds dark mode to edit screen

* lint

* lint

* lint

* Reduce render cost of post controls and improve perceived responsiveness (#132)

* Move post control animations into conditional render and increase perceived responsiveness

* Remove log

* Adds dark mode to the dropdown (#131)

* Adds dark mode to the bottom sheet

* Make background button lighter (like before)

* lint

* Fix bug in lightbox rendering (#133)

* Fix layout in onboarding to not overflow the footer

* Configure feed FlatList (removeClippedSubviews=true) to improve scroll performance (#136)

* Disable like/repost animations to see if theyre causing #135 (#137)

* Composer: mention tagging now works in middle of text (close #105) (#139)

* Implement account deletion (#141)

* Fix photo & camera permission management (#140)

* Check photo & camera perms and alert the user if not available (close #64)

- Adds perms checks with a prompt to update settings if needed
- Moves initial access of photos in the composer so that the initial prompt
  occurs at an intuitive time.

* Add react-native-permissions test mock

* Fix issue causing multiple access requests

* Use longer var names

* Update podfile.lock

* Lint fix

* Move photo perm request in composer to the gallery btn instead of when the carousel is opened

* Adds more tracking all around the app (#142)

* Adds more tracking all around the app

* more events

* lint

* using better analytics naming

* missed file

* more fixes

* Calculate image aspect ratio on load (#146)

* Calculate image aspect ratio on load

* Move aspect ratio bounds to constants

* Adds detox testing and instructions (#147)

* Adds detox testing and instructions

* lint

* lint

* Error cleanup (close #79) (#148)

* Avoid surfacing errors to the user when it's not critical

* Remove now-unused GetAssertionsView

* Apply cleanError() consistently

* Give a better error message for Upstream Failures (http status 502)

* Hide errors in notifications because they're not useful

* More e2e tests (create account) (#150)

* Adds respots under the 'post' tab under profile (#158)

* Adds dark mode to delete account screen (#159)

* 87 dark mode edit profile (#162)

* Adds dark mode to delete account screen

* Adds one more missed darkmode

* more fixes

* Remove fallback gradient on external links without thumbs (#164)

* Remove fallback gradient on external links without thumbs

* Remove fallback gradient on external links without thumbs in the composer preview

* Fix refresh behavior around a series of models (repost, graph, vote) (#163)

* Fix refresh behavior around a series of models (repost, graph, vote)

* Fix cursor behavior in reposted-by view

* Fixes issue where retrying on image upload fails (#166)

* Fixes issue where retrying on image upload fails

* Lint, longer test time

* Longer waitfor time in tests

* even longer timeout

* longer timeout

* missed file

* Update src/view/com/composer/ComposePost.tsx

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

* Update src/view/com/composer/ComposePost.tsx

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

---------

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

* 154 cached image profile (#167)

* Fixes issue where retrying on image upload fails

* Lint, longer test time

* Longer waitfor time in tests

* even longer timeout

* longer timeout

* missed file

* Fixes image cache error on second try for profile screen

* lint

* lint

* lint

* Refactor session management to use a new "Agent" API (#165)

* Add the atp-agent implementation (temporarily in this repo)

* Rewrite all session & API management to use the new atp-agent

* Update tests for the atp-agent refactor

* Refactor management of session-related state. Includes:
- More careful management of when state is cleared or fetched
- Debug logging to help trace future issues
- Clearer APIs overall

* Bubble session-expiration events to the user and display a toast to explain

* Switch to the new @atproto/api@0.1.0

* Minor aesthetic cleanup in SessionModel

* Wire up ReportAccount and ReportPost (#168)

* Fixes embeds for youtube channels (#169)

* Bump app ios version to 1.1 (needed after app store submission)

* Fix potential issues with promise guards when an error occurs (#170)

* Refactor models to use bundleAsync and lock regions (#171)

* Fix to an edge case with feed re-ordering for threads (#172)

* 151 fix youtube channel embed (#173)

* Fixes embeds for youtube channels

* Tests for youtube extract meta

* lint

* Add 'doesnt use non-exempt encryption' to ios config

* Rework the search UI and add  (#174)

* Add search tab and move icon to footer

* Remove subtitles from view header

* Remove unused code

* Clean up UI of search screen

* Search: give better user feedback to UI state and add a cancel button

* Add WhoToFollow section to search

* Add a temporary SuggestedPosts solution using the patented 'bsky team algo'

* Trigger reload of suggested content in search on open

* Wait five min between reloading discovery content

* Reduce weight of solid search icon in footer

* Fix lint

* Fix tests

* 151 feat youtube embed iframe (#176)

* youtube embed iframe temp commit

* Fixes styling and code cleanup

* lint

* Now clicking between the pause and settings button doesn't trigger the parent

* use modest branding (less yt logos)

* Stop playing the video once there's a navigation event

* Make sure the iframe is unmounted on any navigation event

* fixes tests

* lint

* Add scroll-to-top for all screens (#177)

* Adds hardcoded suggested list (#178)

* Adds hardcoded suggested list

* Update suggested-actors-view to support page sizes smaller than the hardcoded list

---------

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

* more robust centering of the play button (#181)

Co-authored-by: Aryan Goharzad <arrygoo@gmail.com>

* Bundle of UI modifications (#175)

* Adjust visual balance of SuggestedPosts and WhoToFollow

* Fix bug in the discovery load trigger

* Adjust search header aesthetic and have it scroll away

* More visual balance tweaks on the search page

* Even more visual balance tweaks on the search page

* Hide the footer on scroll in search

* Ditch the composer prompt buttons in the home feed

* Center the view header title

* Hide header on scroll on the home feed

* Fix e2e tests

* Fix home feed positioning (closes #189) (#195)

* Fix home feed positioning for floating header

* Fix positioning of errors in home feed

* Fix lint

* Don't show new-content notification for reposts (close #179) (#197)

* Show the splash screen during session resumption (close #186) (#199)

* Fix to suggested follows: chunk the hardcoded fetches to 25 at a time (close #196) (#198)

* UI updates to the floating action button (#201)

* Update FAB to use a plus icon and not drop shadow

* Update FAB positioning to be more consistent in different shell modes

* Animate the FAB's repositioning

* Remove the 'loading' placeholder from images as it degraded feed perf (#202)

* Remove the 'loading' placeholder from images as it degraded feed perf

* Remove references

* Fix RN bug that causes home feed not to load more; also fix home feed load view. (#208)

RN has a bug where rendering a flatlist with an empty array appears to break its
virtual list windowing behaviors. See https://stackoverflow.com/a/67873596

* Only give the loading spinner on the home feed during PTR (#207)

(cherry picked from commit b7a5da12fdfacef74873b5cf6d75f20d259bde0e)

* Implement our own lifecycle tracking to ensure it never fires while the app is backgrounded (close #193) (#211)

* Push notification fixes (#210)

* Fix to when screen analytics events are firing

* Fix: dont trigger update state when backgrounded

* Small fix to notifee API usage

* Fix: properly load notification info for push card

* Add feedback link to main menu (close #191) (#212)

* Add "follows you" information and sync follow state between views (#215)

* Bump @atproto/api@0.1.2 and update API usage

* Add 'follows you' pill to profile header (close #110)

* Add 'follows you' to followers and follows (close #103)

* Update reposted-by and liked-by views to use the same components as followers and following

* Create a local follows cache MyFollowsModel to keep views in sync (close #205)

* Add incremental hydration to the MyFollows model

* Fix tests

* Update deps

* Fix lint

* Fix to paginated fetches

* Fix reference

* Fix potential state-desync issue

* Fixes to notifications (#216)

* Improve push-notification for follows

* Refresh notifications on screen open (close #214)

* Avoid showing loader more than needed in post threads

* Refactor notification polling to handle view-state more effectively

* Delete a bunch of tests taht werent adding value

* Remove the accounts integration test; we'll use the e2e test instead

* Load latest in notifications when the screen is open rather than full refresh

* Randomize hard-coded suggested follows (#226)

* Ensure follows are loaded before filtering hardcoded suggestions

* Randomize hard-coded suggested profiles (close #219)

* Sanitizes posts on publish and render (#217)

* Sanatizes posts on publish and render

* lint

* lint and added sanitize to thread view as well

* adjusts indices based on replaced text

* Woops, fixes a bug

* bugfix + cleanup

* comment

* lint

* move sanitize text to later in the flow

* undo changes to compose post

* Add RichText library building upon the sanitizePost library method

* Add lodash.clonedeep dep

* Switch to RichText processing on record load & render

* Fix lint

---------

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

* A group of notifications fixes (#227)

* Fix: don't group together notifications that can't visually be grouped (close #221)

* Mark all notifications read on PTR

* Small optimization: useCallback and useMemo in posts feed

* Add loading spinner to footer of notifications (close #222)

* Fix to scrolling to posts within a thread (#228)

* Fix: render the entire thread at start so that scrollToIndex works always (close #270)

* Visual fixes to thread 'load more'

* A few small perf improvements to thread rendering

* Fix lint

* 1.2

* Remove unused logger lib

* Remove state-mock

* Type fixes

* Reorganize the folder structure for lib and switch to typescript path aliases

* Move build-flags into lib

* Move to the state path alias

* Add view path alias

* Fix lint

* iOS build fixes

* Wrap analytics in native/web splitter and re-enable in all view code

* Add web version of react-native-webview

* Add web split for version number

* Fix BlurView import for web

* Add web split for fastimage

* Create web split for permissions lib

* Fix for web high priority images

---------

Co-authored-by: Aryan Goharzad <arrygoo@gmail.com>
2023-02-22 14:23:57 -06:00
Paul Frazee 879e5ca11b Break out the web/native image picking code and make some progress on the web version 2023-01-27 15:51:24 -06:00
Paul Frazee 392c1083c8 Fix import paths 2023-01-27 00:19:58 -06:00
Paul Frazee b3dd3e29dc Implement basic web composer 2023-01-27 00:16:07 -06:00
Paul Frazee 23b7e2d8e0 Update 'load latest' btn for web 2023-01-26 23:24:37 -06:00
Paul Frazee a8defc4c63 Update compose prompts for web 2023-01-26 23:04:38 -06:00
Paul Frazee 871a6621f6 Add the user profile to the left nav 2023-01-26 22:40:39 -06:00
Paul Frazee b5efaa1de5 Implement modals for web 2023-01-26 22:25:38 -06:00
Paul Frazee cdcce39776 Implement web toast 2023-01-26 22:08:10 -06:00
Paul Frazee 83efaa189b Add lightbox for web 2023-01-26 21:54:47 -06:00
Paul Frazee 72f1ca3954 Update login/create-account and onboard for web 2023-01-26 21:03:50 -06:00
Paul Frazee c1681b40ff Update layouts on a bunch of views 2023-01-26 20:33:47 -06:00
Paul Frazee 6a098cf4a8 Fix background in web scroll elements and update settings screen for web 2023-01-26 20:16:37 -06:00
Paul Frazee 4ccb10c09c Add web version of the header 2023-01-26 20:04:11 -06:00
Paul Frazee eb71c77533 Fix repost icon on web 2023-01-26 19:50:04 -06:00
Paul Frazee c4fb2cdee5 Add right column of web shell and tweak left column 2023-01-26 19:49:16 -06:00
Paul Frazee bd8c7ab106 Add left column of web shell 2023-01-26 19:06:46 -06:00
Paul Frazee 6b457d8d04 Fix to blurviews 2023-01-26 18:15:43 -06:00
Paul Frazee 9282df591a Add web layout components 2023-01-26 17:55:15 -06:00
Paul Frazee 50b272c636 Fix: move imports and constants for the api-polyfill over from their old location 2023-01-26 17:38:25 -06:00
Paul Frazee 0627a7d1a7 Get MVP of web app running 2023-01-26 12:53:46 -06:00
Paul Frazee 3a6c0624ab Add web polyfills 2023-01-26 12:36:27 -06:00
Paul Frazee e7452f8065 Update web build and web-specific components; RNW now builds 2023-01-26 12:12:27 -06:00
Paul Frazee 280339ae37 Fix all type errors 2023-01-26 11:25:52 -06:00
Paul Frazee 759f022351 Bump podfile.lock 2023-01-26 09:51:05 -06:00
Paul Frazee 59b096196c Brand tuning: switch from "blueprint B" to "cloud imagery" (#96)
* Switch app icon to bluesky image

* Update splash screen to clouds

* Update login screen to use branding

* Lighten the shadows in the brand imagery
2023-01-25 19:01:16 -06:00
Paul Frazee f39a27ed66 Fix: dont dedup reposts that are in threads, as that can cause rendering issues (close #71) 2023-01-25 17:57:53 -06:00
Paul Frazee d0bca3c576 Add a sanity check to avoid bad references, close #77 2023-01-25 17:49:22 -06:00
Paul Frazee 03b44c0e45 Fix pagination and rendering of suggested follows (#95) 2023-01-25 17:46:14 -06:00
Aryan Goharzad 10c9b26475 Saves image on long press (#83)
* Saves image on long press

* Adds save on long press

* Forking lightbox

* move to wrapper only to the bottom sheet to reduce impact of this change

* lint

* lint

* lint

* Use official `share` API

* Clean up cache after download

* comment

* comment

* Reduce swipe close velocity

* Updates per feedback

* lint

* bugfix

* Adds delayed press-in for TouchableOpacity
2023-01-25 17:25:34 -06:00
Aryan Goharzad 3e6a6960d4 Adds darkmode support for "Liked by" screen (#94)
* Adds darkmode support for "Liked by" screen

* changes based on feedback

* variable naming
2023-01-25 16:54:22 -06:00
Paul Frazee 5635bde707 Push notification & session management cleanup (#92)
* Add some temporary logging to help suss out the session drop issue

* Fix to session resumption: copy session tokens during a resumeSession attempt

* Factor out notifee display into a lib and add to storybook

* Tune the bg notifications fetch to only get what is needed

* Fix: run account update inside a mobx action

* Remove debugging logs for sessions

* Fixes to bg notifications fetch
2023-01-25 11:31:09 -06:00
Paul Frazee 1a8c6ac71e Fix missing config for background fetch 2023-01-24 19:59:40 -06:00
Paul Frazee 3bb220f8be Initial pass at push notifications + some fixes to the session management (#91)
* Fix: test the session during resume to ensure it's valid

* Don't delete sessions for now

* Add notifee and request notif permissions on first login

* Set unread notifications badge on app icon

* Trigger a notifee card on new notifications

* Experimental: use react-native-background-fetch to check for notifications

* Add missing mocks

* Fix to resumeSession()
2023-01-24 19:32:24 -06:00
Paul Frazee 8187a07aee Add basic analytics (#89)
* Add basic analytics

* Fix: add mock for analytics
2023-01-24 13:58:35 -06:00
Paul Frazee d054a69bcf Resolve all remaining lint issues (#88)
* Rework 'navIdx' variables from number arrays to strings to avoid equality-check failures in react hooks

* Resolve all remaining lint issues

* Fix tests

* Use node v18 in gh action test
2023-01-24 13:00:11 -06:00
Aryan Goharzad 4b1fe49132 more prettier and lint cleanup (#82)
* more prettier and lint cleanup

* Fixes more lint issues

* lint

* ignore more files

* remove todos

* lint
2023-01-24 11:03:18 -06:00
Paul Frazee b2c139dbc0 Account switcher (#85)
* Update the account-create and signin views to use the design system.

Also:
- Add borderDark to the theme
- Start to an account selector in the signin flow

* Dark mode fixes in signin ui

* Track multiple active accounts and provide account-switching UI

* Add test tooling for an in-memory pds

* Add complete integration tests for login and the account switcher
2023-01-24 09:06:27 -06:00
Aryan Goharzad 02488f06d8 Removes white space from around images (#81)
* Removes white space from around images

* Add a subtle border
2023-01-23 20:17:37 -06:00
Aryan Goharzad b0d367a3b8 Lints some errors and warnings (#76) 2023-01-20 13:43:28 -06:00
Aryan Goharzad 19c9ffa352 Fixes embed links for twitter and tiktok (#74) 2023-01-20 12:54:30 -06:00
Paul Frazee cfc7d17db3 Only use cursors supplied by the server (ref #59) 2023-01-20 10:39:00 -06:00
Paul Frazee 71b24952c7 Sanity check selector swipes 2023-01-20 10:15:59 -06:00
Paul Frazee d7aed0b199 More layout fixes in notifications 2023-01-20 08:40:41 -06:00
Paul Frazee 2823524388 Spacing fix of expanded notifications 2023-01-20 08:36:15 -06:00
Paul Frazee fd8083350c Fix font color of expanded notifs 2023-01-20 08:35:35 -06:00
Paul Frazee 1411f33393 Fix text color in composer 2023-01-19 20:08:43 -06:00
Paul Frazee 8840293c92 Fix a case where the 'aborted' error message was getting through 2023-01-19 17:55:00 -06:00
Paul Frazee 83fa99a4fe Fix: taps on images in the composer now register even when input is focused 2023-01-19 17:46:45 -06:00
Paul Frazee 64473f5c98 Fix: new post doesnt open images selector 2023-01-19 17:37:24 -06:00
Paul Frazee a45424fdb1 Add the ability to paste images into the composer (#56) 2023-01-19 17:36:49 -06:00
Paul Frazee 14d3389a63 Fix error logs 2023-01-19 17:05:36 -06:00
Paul Frazee 311c7b52c8 Fixes to likes list 2023-01-19 16:54:30 -06:00
Paul Frazee a8fd747187 Fixes to reposted-by list 2023-01-19 16:50:16 -06:00
Paul Frazee 259610ab37 Fixes to follows listing 2023-01-19 16:39:40 -06:00
Paul Frazee 44b4ec22d7 Fixes to the followers list view 2023-01-19 16:38:12 -06:00
Paul Frazee f3dd6a89a1 Update podfile.lock 2023-01-19 16:37:21 -06:00
Paul Frazee a60473b93f Fix: ensure all views can scroll to the bottom 2023-01-19 15:21:06 -06:00
Paul Frazee c8c5ab05cd Update load latest to match sizing and aesthetic better 2023-01-19 15:10:15 -06:00
Paul Frazee 38219721c9 Fix html extraction tests 2023-01-19 14:30:33 -06:00
Paul Frazee 9d6e23b6e7 Visual tweaks to post prompts 2023-01-19 14:28:11 -06:00
Paul Frazee ce69d13ec4 Fix weird bar at top of composer in dark mode 2023-01-19 14:17:15 -06:00
Paul Frazee 4875c2edaf Fix bad ref 2023-01-19 14:17:00 -06:00
Paul Frazee e39759a9a4 Change post prompt to a set of buttons (#55) 2023-01-19 14:08:53 -06:00
Aryan Goharzad 547b663bb6 Fixes youtube embed issues (#50)
* fixes youtube embed

* move extractMetaHtml test to its own file

* tests cleanup

* Add fallback for youtube meta data

* lint

* Check for youtube in the url domain

* use hostname instead of full url to check for link domain

* checks only for domain
2023-01-19 12:53:11 -06:00
Paul Frazee 6ab5776f95 Improve link meta fetching for bsky links (#54)
* Add share dropdown item to profiles

* Temporary improvement for links to content on the network

* Enlarge text slightly on embed cards
2023-01-19 12:30:28 -06:00
Aryan Goharzad 9b40d4c8cc Adding action for linting (#51)
* Adding action for linting

* Configuring eslint

* Update lint.yml

* Update lint.yml

* Update lint.yml

* adds yarn jest to package.json

* test report

* debugging tests

* trying force exit

* force exit

* test1

* forceexit

* using another reporter

* jest debugging

* separated lints & tests

* test

* Cleanup

* Add  /src/third-party, /ios, and /android to ignore list
2023-01-19 12:28:52 -06:00
Paul Frazee a0a81da164 Clean up the settings page 2023-01-19 11:49:53 -06:00
Paul Frazee 0220adaefb Improve the 'expand avis' animation in the notifications 2023-01-19 11:41:24 -06:00
Paul Frazee 481dee52b1 Fix missing key in list 2023-01-19 11:35:37 -06:00
Paul Frazee 78d74a3d7c Add the ability to expand/collapse users in notifications 2023-01-19 11:34:07 -06:00
Paul Frazee 83ca9059fa Tune the empty state visuals 2023-01-19 10:50:21 -06:00
Paul Frazee 8da491cc3b Tweak compose prompt spacing 2023-01-19 10:40:55 -06:00
Paul Frazee 8d1b3adb6a Post layout tweaks (#53)
* Increase left margin on feed and embiggen avis

* Decrease feed margins a bit

* Tweak post bottom margin

* Update loading placeholder to match feed

* Update 'view full thread' positioning

* Update postthread to match feed layout

* Update notifications and individual post to match new layout

* Add missing aborted check
2023-01-19 10:35:57 -06:00
Paul Frazee 626f85651f Update composer to preview external link cards (#52)
* Fetch external link metadata during compose so the user can preview and remove the embed

* Add missing mocks

* Update tests to match recent changes
2023-01-18 18:14:46 -06:00
Paul Frazee 2acc7ed107 Enlarge avatars in the notifications 2023-01-18 17:06:17 -06:00
Paul Frazee 14a2be33af Remove log 2023-01-18 16:52:00 -06:00
Paul Frazee a642a3fe8f Handle post deletions by removing from active views (close #37) 2023-01-18 16:45:48 -06:00
Paul Frazee b90f7eaefb Fix image compression (close #41) 2023-01-18 14:54:55 -06:00
Paul Frazee 455515cae1 Keep the composer image selector open after choosing an image 2023-01-18 14:47:59 -06:00
Paul Frazee e3fc3b997a Hackfix around 'images too large' issue 2023-01-18 14:47:42 -06:00
Paul Frazee 3c529e743f Update compose prompt for isual balance and to include image button 2023-01-18 13:57:53 -06:00
Paul Frazee 9d7f968cdd Lighten the button gradients a bit 2023-01-18 13:30:50 -06:00
Paul Frazee b5769f9aed Fix to text consistency in composer 2023-01-18 13:22:34 -06:00
Paul Frazee ac98b322ca Focus the text input on tap during the composer 2023-01-18 13:21:23 -06:00
Paul Frazee c499f5f96a Remove all links from post meta to ensure taps are more consistent 2023-01-18 13:10:08 -06:00
Paul Frazee d719b502d3 Prettier profile headers (no standard header) 2023-01-18 12:56:53 -06:00
Paul Frazee 02e24c23a6 Move the grays from a red undertone to blue 2023-01-18 12:40:51 -06:00
Paul Frazee c57ae4cea4 Update gradients to use a more consistent blue theme 2023-01-18 12:32:48 -06:00
Paul Frazee 2536d6bf10 Rework all typography 2023-01-18 11:15:40 -06:00
Paul Frazee 060ce2c725 Merge branch 'improved-lightbox' into main 2023-01-17 21:18:25 -06:00
Paul Frazee a8d2935cf2 Fix an issue that caused the shelf menu to show up at random 2023-01-17 21:01:52 -06:00
Paul Frazee d6fb1528a0 Remove leftover code 2023-01-17 20:47:43 -06:00
Paul Frazee 2e3d170d1e Improve lightbox... and update to React Native 0.71.0 (#49)
* Switch to a better lightbox implementation (close #42)

* Upgrade to react-native 0.71.0

* Update (or remove low-value) tests
2023-01-17 20:40:02 -06:00
Paul Frazee 4690e28cde Update (or remove low-value) tests 2023-01-17 20:38:15 -06:00
Paul Frazee 66a754ad22 Upgrade to react-native 0.71.0 2023-01-17 20:21:11 -06:00
Paul Frazee 83a74f0f6e Switch to a better lightbox implementation (close #42) 2023-01-17 19:34:12 -06:00
Paul Frazee 811b8cfc4c Add images to the post in the right order 2023-01-17 18:35:48 -06:00
Paul Frazee a81d9cfca6 Give a more sensible default crop in the post image picker (related #39) 2023-01-17 18:35:37 -06:00
Paul Frazee c7ef5cd741 Add profile menuitem to main menu (close #47) 2023-01-17 16:55:43 -06:00
Paul Frazee 41f6afc528 Fix to extraneous home feed polling 2023-01-17 16:49:11 -06:00
Paul Frazee 37cb821d6b Visual improvements to post embeds for external links 2023-01-17 16:42:32 -06:00
Paul Frazee 203bfc4c7c Group together notifications more aggressively 2023-01-17 16:25:10 -06:00
Paul Frazee 779556f36d Fix left-alignment on notifications 2023-01-17 16:22:34 -06:00
Paul Frazee cf575cca68 Increase the profile bio line-count cutoff significantly to only catch very silly newline abuse (close #48) 2023-01-17 16:18:41 -06:00
Paul Frazee 97e6bdbe40 More adjustments to the repost icon 2023-01-17 13:25:04 -06:00
Paul Frazee 5f0101a360 Enlarge repost icon arrows 2023-01-17 13:21:11 -06:00
Paul Frazee a3bb305229 Rework repost icon to match line widths 2023-01-17 13:17:38 -06:00
Paul Frazee 808b33e7a7 Refer to upvotes as 'likes' in the UI (will change in the protocol soon) 2023-01-17 12:35:47 -06:00
Paul Frazee ac917ba829 Fix notification descriptions and render images for your own posts in notifs 2023-01-17 12:12:17 -06:00
Paul Frazee 6c3f2d3505 Lighten post controls a little in light-mode and add them to the theme 2023-01-17 11:20:07 -06:00
Paul Frazee 742a43658f Lighten borders slightly 2023-01-17 11:14:47 -06:00
Paul Frazee 0307e2e932 Fix an issue that caused the feed to rearrange on loadmore 2023-01-17 10:58:51 -06:00
Paul Frazee 7c1add25a1 Remove duplicate posts caused by reposts 2023-01-17 10:45:37 -06:00
Paul Frazee feeab9205b Add loading spinners to lightbox views (close #38) 2023-01-17 10:40:09 -06:00
Paul Frazee 1023653d97 Shrink the header back down but use bolder title text 2023-01-17 10:32:40 -06:00
Paul Frazee 077f2fe093 Remove scenes (#36)
* Remove scenes from the main menu

* Remove scenes from the profile view

* Remove 'scenes explainer' from onboarding flow

* Remove scene-related modals

* Remove member/membership code

* Remove all scenes-related items from notifications

* Remove scene-related code from posts feed

* Remove scene-related API helpers

* Update tests
2023-01-17 10:11:30 -06:00
João Ferreiro d636ec6339 Unit Testing (#35)
* add testing lib

* remove coverage folder from git

* finished basic test setup

* fix tests typescript and import paths

* add first snapshot

* testing utils

* rename test files; update script flags; ++tests

* testing utils functions

* testing downloadAndResize wip

* remove download test

* specify unwanted coverage paths;
remove update snapshots flag

* fix strings tests

* testing downloadAndResize method

* increasing testing

* fixing snapshots wip

* fixed shell mobile snapshot

* adding snapshots for the screens

* fix onboard snapshot

* fix typescript issues

* fix TabsSelector snapshot

* Account for testing device's locale in ago() tests

* Remove platform detection on regex

* mocking store state wip

* mocking store state

* increasing test coverage

* increasing test coverage

* increasing test coverage on src/screens

* src/screens (except for profile) above 80% cov

* testing profile screen wip

* increase coverage on Menu and TabsSelector

* mocking profile ui state wip

* mocking profile ui state wip

* fixing mobileshell tests wip

* snapshots using testing-library

* fixing profile tests wip

* removing mobile shell tests

* src/view/com tests wip

* remove unnecessary patch-package

* fixed profile test error

* clear mocks after every test

* fix base mocked store values (getters)

* fix base mocked store values
(hasLoaded, nonReplyFeed)

* profile screen above 80% coverage

* testing custom hooks

* improving composer coverage

* fix tests after merge

* finishing composer coverage

* improving src/com/discover coverage

* improve src/view/com/login coverage
fix SuggestedFollows tests
adding some comments

* fix SuggestedFollows tests

* improve src/view/com/profile coverage
extra minor fixes

* improve src/view/com/notifications coverage

* update coverage ignore patterns

* rename errorMessageTryAgainButton
increase SuggestedFollows converage

* improve src/view/com/posts coverage

* improve src/view/com/onboard coverage

* update snapshot

* improve src/view/com/post coverage

* improve src/view/com/post-thread coverage
rename ErrorMessage tests
test Debug and Log components

* init testing state

* testing root-store

* updating comments

* small fixes

* removed extra console logs

* improve src/state/models coverage
refactor rootStore
rename some spies

* adding cleanup method after tests

* improve src/state/models coverage

* improve src/state/models coverage

* improve src/state/models coverage

* improve src/state/models coverage

* test setInterval in setupState

* Clean up tests and update Home screen state management

* Remove some tests we dont need

* Remove snapshot tests

* Remove any tests that dont demonstrate clear value

* Cleanup

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2023-01-17 10:06:00 -06:00
Paul Frazee 98c9a6ad32 Remove the avi from the compose prompt 2023-01-16 17:37:18 -06:00
Paul Frazee 33a4d2cbe5 Enlarge the view header 2023-01-16 17:21:35 -06:00
Paul Frazee 8a5bc60819 Dark mode color fixes 2023-01-16 17:11:15 -06:00
Paul Frazee f492fd4d41 Readd the FAB for composing new posts 2023-01-16 17:07:33 -06:00
Paul Frazee ed7204ab71 Round the corners on single-image embeds a bit more 2023-01-16 16:58:30 -06:00
Paul Frazee 9aeaa38f3b More spacing and sizing tweaks, including larger post controls 2023-01-16 16:54:35 -06:00
Paul Frazee b3f9ed7981 Enlarge post text slightly 2023-01-16 16:42:07 -06:00
Paul Frazee b8ab064fcc More spacing fixes, especially for the repost info 2023-01-16 16:34:52 -06:00
Paul Frazee 58bf9cb8cd Spacing fixes 2023-01-16 16:30:05 -06:00
Paul Frazee 8a67e8d102 Fix visual consistency of 'reply to' in post and use display name 2023-01-16 16:24:16 -06:00
Paul Frazee 5d6fc56349 Fix missing metrics in post threads 2023-01-16 16:22:24 -06:00
Paul Frazee 77ed2129d3 Move menu controls into post footers and improve meta info rendering 2023-01-16 16:09:51 -06:00
Aryan Goharzad fcebe8e0b0 Readme Cleanup (#40)
* Readme Cleanup

Updates instructions for starting the dev/staging servers

* Update README.md

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2023-01-16 15:40:34 -06:00
Paul Frazee 6df617003a Fix: remove duplicates in the TL caused by rendering reply parents 2023-01-16 14:49:58 -06:00
Paul Frazee 6953bf9d22 Fix image compression for avis and banner images 2023-01-12 15:07:32 -06:00
Paul Frazee 9396595595 Add scrolling to menu 2023-01-03 14:35:33 -06:00
Paul Frazee cf13b5cd4c Bump deps to pull in some bugfixes 2023-01-03 14:31:12 -06:00
Paul Frazee e24ab48b73 Indicate images in notifications 2023-01-03 13:14:10 -06:00
Paul Frazee bbee08eb22 Implement validation and proper type detection 2023-01-03 13:08:56 -06:00
Paul Frazee c68f291128 Improve handling around connection failures during login 2023-01-03 12:17:07 -06:00
Paul Frazee 32b3575074 Add 'is 13' checkbox to account creation 2023-01-03 11:49:40 -06:00
Paul Frazee 11f972c640 Fix to feed update 2023-01-03 11:26:51 -06:00
Paul Frazee 61cf754fd5 Fix session hydration during load 2023-01-03 11:08:39 -06:00
Paul Frazee 00b50c71b5 Fix bug in error handling 2023-01-03 11:08:29 -06:00
Paul Frazee 66eb6f2888 Introduce error boundaries around all screens 2023-01-02 21:49:14 -06:00
Paul Frazee bc571ee998 Improve error logging 2023-01-02 21:39:15 -06:00
Paul Frazee c758996034 Bump api@0.0.5 and use the type guard helpers 2023-01-02 20:56:35 -06:00
Paul Frazee 1f26494c94 Implement logging system 2023-01-02 17:38:13 -06:00
Paul Frazee 74bfc10e36 Dont mute posts for a user when viewing their profile 2023-01-02 13:45:27 -06:00
Paul Frazee e194e5de91 Implement account muting 2023-01-02 13:40:14 -06:00
Paul Frazee 09f96da982 Fix to loading state 2022-12-30 15:58:28 -06:00
Paul Frazee 6e48d63dda Fix the status bar coloring 2022-12-30 15:56:54 -06:00
Paul Frazee eec636897c Add dark mode toggle 2022-12-30 15:48:34 -06:00
Paul Frazee 777f30562b Integrate composer into design system 2022-12-30 15:42:09 -06:00
Paul Frazee 16e4bc66bd Various small fixes 2022-12-30 15:32:07 -06:00
Paul Frazee 98c5312a29 Integrate search into suggested follows 2022-12-30 15:21:09 -06:00
Paul Frazee 9971f1f035 Dont autofocus the search input 2022-12-30 15:12:36 -06:00
Paul Frazee dec9d97171 Integrate settings into design system and some various fixes/tweaks 2022-12-30 15:11:47 -06:00
Paul Frazee 355749e605 Integrate menu into design system 2022-12-30 15:08:10 -06:00
Paul Frazee 6268736bfa Integrate notifications into the design system 2022-12-30 13:34:10 -06:00
Paul Frazee a270d750c8 Integrate profile listings into design system 2022-12-30 13:20:55 -06:00
Paul Frazee 0eb4c7495e Update profile header to use design system 2022-12-30 13:13:10 -06:00
Paul Frazee b438318b92 Integrate the shell into the design system 2022-12-30 12:49:07 -06:00
Paul Frazee 01aaa6123f Integrate ViewSelector into design system 2022-12-30 12:40:16 -06:00
Paul Frazee 486a1f082c Integrate composer prompt into design system 2022-12-30 12:35:37 -06:00
Paul Frazee f943cbd04a Integrate ViewHeader into the design system 2022-12-30 12:29:11 -06:00
Paul Frazee c54fa5b2e4 Update threads to use design system 2022-12-30 12:19:45 -06:00
Paul Frazee 54c0115181 Improve image layout 2022-12-30 11:55:25 -06:00
Paul Frazee bb3a2fddfc Tune post controls 2022-12-28 19:37:30 -06:00
Paul Frazee 5135a13812 Update posts in feed to use the theming system 2022-12-28 19:20:02 -06:00
Paul Frazee 059c3b362d Update notifications 2022-12-28 15:53:06 -06:00
Paul Frazee 090ceb4c53 Tighten up spacing and dividers 2022-12-28 15:50:28 -06:00
Paul Frazee 7796203c25 Fix letter spacing 2022-12-28 15:08:14 -06:00
Paul Frazee 44ae514d89 Add a design system (#34)
* Add theming system

* Add standard Button control and update RadioButtons

* Unify radiobutton with design system

* Update debug screen to have multiple views

* Add ToggleButton

* Update error controls to use design system

* Add typography to <Text> element

* Move DropdownButton into the design system

* Clean out old code

* Move Text into design system

* Add 'inverted' color palette

* Move LoadingPlaceholder into the design system
2022-12-28 14:06:01 -06:00
Paul Frazee 12d8e06a1e Increase image resolutions 2022-12-26 17:41:12 -06:00
Paul Frazee de65d9198a Start with highest quality compression and find a suitable size (#33) 2022-12-26 12:01:40 -06:00
Paul Frazee 41bf8e15cd Bump @atproto/api@0.0.3 2022-12-22 14:43:54 -06:00
João Ferreiro adeb1d5cec Unit testing (#32)
* add testing lib

* remove coverage folder from git

* finished basic test setup

* fix tests typescript and import paths

* add first snapshot

* testing utils

* rename test files; update script flags; ++tests

* testing utils functions

* testing downloadAndResize wip

* remove download test

* specify unwanted coverage paths;
remove update snapshots flag

* fix strings tests

* testing downloadAndResize method

* increasing testing

* fixing snapshots wip

* fixed shell mobile snapshot

* adding snapshots for the screens

* fix onboard snapshot

* fix typescript issues

* fix TabsSelector snapshot

* Account for testing device's locale in ago() tests

* Remove platform detection on regex

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2022-12-22 09:32:39 -06:00
Paul Frazee 61511d5161 Unvendor the api and switch to @atproto/api 2022-12-22 09:17:07 -06:00
Paul Frazee aee205b0ab Fix issue which caused parent posts to fail at mobx reactivity 2022-12-21 14:37:22 -06:00
Paul Frazee e59763b50a Update to use new getTimeline, getAuthorFeed, and getPostThread output models 2022-12-20 22:54:56 -06:00
Paul Frazee 5168d44926 Replace removed hasIndexes behavior 2022-12-20 16:32:04 -06:00
Paul Frazee def3156c33 Get the composer into a passable visual state on android when the keyboard is open 2022-12-20 14:55:50 -06:00
Paul Frazee a290891f70 Fix post-meta truncation on android 2022-12-20 14:50:04 -06:00
Paul Frazee a96562e89c Fixes to text input colors on android 2022-12-20 14:29:50 -06:00
Paul Frazee 279d41fcd1 Wrap all <Text> in a helper that ensures black color is applied by default 2022-12-20 12:49:44 -06:00
Paul Frazee 4932505c5e Use consistent rendering of avis and post metas in threads 2022-12-20 10:33:56 -06:00
Paul Frazee 629b7d8c9b Proper fix to the previous panic fix: put threads at the end when they should be there 2022-12-20 09:20:53 -06:00
Paul Frazee 5c71f8e32a Fix to error condition that breaks the feed 2022-12-20 09:02:38 -06:00
Paul Frazee 395a8838be A couple more android updates 2022-12-19 19:43:28 -06:00
João Ferreiro 17903b817d rn-fetch-blob android setup 2022-12-19 19:26:54 -06:00
João Ferreiro 54f05bfcf6 minor fix 2022-12-19 19:26:54 -06:00
João Ferreiro b1a058d098 fixing remaining text colors on android 2022-12-19 19:25:58 -06:00
João Ferreiro 27657541f2 fixing modal & keyboard interaction on android 2022-12-19 19:23:24 -06:00
João Ferreiro 73ea67f5c0 initial android fixes 2022-12-19 19:20:44 -06:00
João Ferreiro d065b62f52 fix camera permissions 2022-12-19 19:19:00 -06:00
João Ferreiro eb03170736 fix android runtime 2022-12-19 19:19:00 -06:00
João Ferreiro 6f734f7978 fix android build 2022-12-19 19:19:00 -06:00
Paul Frazee 9235d6c13b Remove prefetch of feed (it wasnt working) 2022-12-19 19:16:56 -06:00
Paul Frazee bc54c8d7c6 Tighten up the post control hit regions 2022-12-19 19:13:26 -06:00
Paul Frazee 3b8dbbff12 Tighten up the home feed 2022-12-19 19:12:43 -06:00
Paul Frazee e8bb545023 Enable image-only posts 2022-12-19 18:51:13 -06:00
Paul Frazee f0b30e26d4 Fix to thread ordering in the feed: correctly identify the starts of threads when adjacent 2022-12-19 13:22:18 -06:00
Paul Frazee cbfa9f62a4 Improve thread rendering 2022-12-18 18:54:05 -06:00
Paul Frazee fefd8cc8a0 Add WIP 'report account' modal 2022-12-18 17:45:23 -06:00
Paul Frazee 09765a5d36 Add WIP 'report post' modal 2022-12-18 17:28:28 -06:00
Paul Frazee e325b72c62 Reduce confusing visual feedback while scrolling 2022-12-18 16:43:18 -06:00
Paul Frazee 055a4d8e98 Add zooming to the lightbox 2022-12-16 16:32:54 -06:00
Paul Frazee 1e28ae6d2a Prefetch feed refreshes to speed up 'load more posts' 2022-12-16 15:37:13 -06:00
Paul Frazee 16343a2936 Fixes to the composer UX around images and scrolling 2022-12-16 14:48:37 -06:00
Paul Frazee 18cc2183cc Add swipe gestures to the lightbox 2022-12-16 11:57:45 -06:00
Paul Frazee 5e711c799b Implement 'forgot password' flow 2022-12-15 17:45:03 -06:00
Paul Frazee ca4b9d3a60 Split login screen into component files 2022-12-15 14:06:05 -06:00
Paul Frazee ebd03ffe2a Just do full renders of parent posts in the feed 2022-12-15 11:43:05 -06:00
Paul Frazee ee4f0673f1 Dont use ??= 2022-12-15 10:21:25 -06:00
Paul Frazee 33145f2e71 Improve handling of connection loss 2022-12-14 16:03:10 -06:00
Paul Frazee 721fd84a7e Fix state-tracking 2022-12-14 15:49:45 -06:00
Paul Frazee a06fd7dfd4 Reset feeds on login 2022-12-14 15:49:38 -06:00
Paul Frazee bd6bb4df06 Add haptic feedback to likes and reposts 2022-12-14 15:46:21 -06:00
Paul Frazee bb4dc3c3a5 Add post embeds (images and external links) 2022-12-14 15:35:15 -06:00
Paul Frazee 7b7fe7ccd8 Move posts feed to root store (me) and ensure new posts always update the feed 2022-12-13 15:52:18 -06:00
Paul Frazee 316679ae68 Fix: avoid dup keynames in posts feed 2022-12-13 15:51:54 -06:00
Paul Frazee b34cae6db4 Enlarge feed avis slightly 2022-12-13 15:40:55 -06:00
Paul Frazee 52e31394ab Ensure load more is always visible 2022-12-13 15:36:05 -06:00
Paul Frazee 84f18e03fa Use avatar in viewheader when cant go back 2022-12-13 15:35:45 -06:00
Paul Frazee 30761594ec Fix: avoid duplicate key names in notifications 2022-12-13 15:35:11 -06:00
Paul Frazee 87258a2439 Fix issue that caused repost & trend data to get lost on feed updates 2022-12-13 15:17:18 -06:00
Paul Frazee 6e31e928a9 Hide main menu drawer on click outside 2022-12-13 15:01:14 -06:00
Paul Frazee d0587c81f8 Use full available screen 2022-12-13 14:58:25 -06:00
Paul Frazee 29018f06b9 Fix: show avatars in all notifications 2022-12-13 14:53:00 -06:00
Paul Frazee 171cb6b3d3 Debug: disable feed reordering to isolate bugs 2022-12-13 11:15:32 -06:00
Paul Frazee 3e37c27310 Reposition 'load latest' based on minimal shell mode 2022-12-13 11:15:18 -06:00
Paul Frazee 06c3ebe2d4 Hide footer on scroll down (minimal shell mode) 2022-12-12 16:04:14 -06:00
Paul Frazee d336cd58b1 Improvements to service selection during login 2022-12-12 15:13:45 -06:00
Paul Frazee 684f67a8e0 Add profile image lightbox 2022-12-12 14:54:56 -06:00
Paul Frazee a7b23613d3 Improve session management 2022-12-12 14:39:02 -06:00
Paul Frazee a6db1a9ee3 Add banner image upload to profiles 2022-12-12 13:47:18 -06:00
Paul Frazee 0f065b2c27 Improvements to 'edit profile' error messages 2022-12-12 13:17:40 -06:00
Paul Frazee 7399e37bba Add 'loading more' spinner to feeds 2022-12-12 11:22:54 -06:00
Paul Frazee 7ce4c821e5 Tune the swipe gesture to detect more easily 2022-12-12 11:11:37 -06:00
Paul Frazee 68dd96128a More aesthetic and perf improvements to the menu drawer 2022-12-12 10:48:36 -06:00
Paul Frazee 6e55149281 Fix duplicate 'end of feed' issue 2022-12-12 09:56:19 -06:00
Paul Frazee 3aca890da6 Improve aesthetic of main menu swipeout (use screen mask) 2022-12-09 11:46:49 -06:00
Paul Frazee 4798d44110 Add main menu button 2022-12-09 11:22:19 -06:00
Paul Frazee 37b2b40aa1 Show 'processing' spinner in edit profile modal 2022-12-08 16:08:15 -06:00
Paul Frazee f9e287b12c Turn the main menu into a 'drawer' instead of a screen in the history 2022-12-08 15:34:22 -06:00
Paul Frazee 96dc9e398b Switch to temporary 'fixed tabs' model for default and notifications 2022-12-08 14:21:28 -06:00
Paul Frazee 2f0157dd33 Add avatar images and fix some type signatures 2022-12-08 13:45:23 -06:00
Paul Frazee f608712308 Replace reanimated for tabs selector 2022-12-07 17:08:49 -06:00
Paul Frazee 3807f216fe Cleanup 2022-12-07 16:59:10 -06:00
Paul Frazee 6b1a5374ae Replace navigational 'back swipe' gesture with new HorzSwipe util 2022-12-07 16:56:14 -06:00
Paul Frazee 71b7158ff9 Add HorzSwipe gesture and integrate it into the ViewSelector 2022-12-07 15:51:06 -06:00
Paul Frazee 26f06d768c Switch to react-native default animation tools for composer and post controls 2022-12-06 17:43:54 -06:00
Paul Frazee 383a40bc03 Fix mention-creation and implement mentions in notifications 2022-12-06 13:47:52 -06:00
Paul Frazee 8413fccdb5 Better empty state in profiles 2022-12-06 13:09:18 -06:00
Paul Frazee 3161703d8a Ensure all feed views can refresh 2022-12-06 13:04:40 -06:00
Paul Frazee 4c097d89c5 Add build version to menu 2022-12-06 12:40:40 -06:00
Paul Frazee 0b50ae3e61 Add context to replies when appearing in the feed 2022-12-06 12:29:13 -06:00
Paul Frazee 063583bb6f Implement terms-of-service and privacy-policy links in signup 2022-12-06 11:39:46 -06:00
Paul Frazee f2da9f2d0a Update API build 2022-12-06 11:39:30 -06:00
João Ferreiro fc7fa8a354 Upload profile image (#29)
* add editable button profile picture

* add editable button cover picture

* upload profile photos (save them locally)

* rollback pbxproj changes

* rollback podfile checksum (for git only)

* move edit photos onto edit profile modal

* adjust edit icon and image cropping size

* added temporary (react state) image

* added IMAGES_ENABLED flag

* minor lint fix

* save local photos on edit profile upload (wip)

* save profile photos on profile view state (wip)

* remove unecessary computed

* save photo in state before pushing it to viewmodel

* refactor profile pictures's state

* remove unnecessary isMe prop

* removing old comments

* tweak icon size & position

* A few styling tweaks and a fix to mobx state management

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2022-12-06 10:57:15 -06:00
Paul Frazee 709a970cdc Fix to unicode zero-width characters in expanded posts 2022-12-06 10:15:59 -06:00
Paul Frazee 5d7814897c Never allow undefined values in me model 2022-12-06 10:11:45 -06:00
Paul Frazee 1e2ee001a8 Rework the 'main menu' to be a screen that's always in history 2022-12-06 10:11:32 -06:00
Paul Frazee 11423fc25c Add missing usage descriptions for ios 2022-12-06 10:08:27 -06:00
Paul Frazee 160fc31b47 Enlarge the small emoji-only replies 2022-12-05 15:40:33 -06:00
Paul Frazee 3389e0dc4a Dismiss keyboard in search on scroll 2022-12-05 15:22:23 -06:00
Paul Frazee ae8162974e Add 'copy post text' tool 2022-12-05 15:03:42 -06:00
Paul Frazee b33269a535 Better sized and more informative character counter 2022-12-05 13:59:13 -06:00
Paul Frazee d8280b6ad9 Switch to System font to fix emoji rendering 2022-12-05 13:44:24 -06:00
Paul Frazee 935cc8f675 Fix: never attempt update on 0 items 2022-12-05 13:36:13 -06:00
Paul Frazee 3bd6e9c84c Increase touch-size of the 'load new posts' button 2022-12-05 13:33:31 -06:00
Paul Frazee f1b9114af0 Ensure the UI always renders, even in bad network conditions (close #6) 2022-12-05 13:25:04 -06:00
Paul Frazee 95e5b169c8 Merge branch 'upload-image' into main 2022-12-05 11:25:33 -06:00
Paul Frazee 09791a3b3c Remove loading-placeholder animation; according to some issues, animated linear-gradients may cause crashes 2022-12-05 10:50:46 -06:00
Paul Frazee c7a5642e48 Fix 'swipe back to nothing' bug 2022-12-05 10:39:34 -06:00
Paul Frazee 6c23972620 Make 'backswipe' a little easier to trigger 2022-12-05 10:25:53 -06:00
Paul Frazee 211af98aaf Enlarge click targets for post controls and view header 2022-12-05 10:18:38 -06:00
Paul Frazee bc404572cb Hide images behind a build flag until ready 2022-12-02 10:48:57 -06:00
João Ferreiro b824ac710b Upload image in composer (#27)
* upload images in composer v1

* fix android compile

* reafctor image carousel into new component;
fix photo overlapping text in composer

* revert android changes

* further refactoring code into different components

* move show carousel out of the component

* fixing add photo using camera

* fix typescript issue; force mediatype photo

* change post test with photo attached;
remove auto linking settings

* use runInAction in getPhotos model

* react-hooks/exhaustive-deps fixes

* crop every photo;
make use of useCallback

* moving placeholder condition

* Cleanup

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
2022-12-02 10:41:01 -06:00
Paul Frazee 372cd80175 Cleanup 2022-12-02 10:40:22 -06:00
João Ferreiro d0c9f95c7e moving placeholder condition 2022-11-29 18:32:07 +00:00
João Ferreiro 91a06f2390 crop every photo;
make use of useCallback
2022-11-29 18:26:16 +00:00
João Ferreiro ffd333164b react-hooks/exhaustive-deps fixes 2022-11-29 17:51:06 +00:00
João Ferreiro a6e8bb39b8 use runInAction in getPhotos model 2022-11-29 17:46:55 +00:00
João Ferreiro 8d87fbd56a change post test with photo attached;
remove auto linking settings
2022-11-29 16:45:44 +00:00
João Ferreiro a129ddba27 Merge branch 'main' into upload-image 2022-11-29 16:19:38 +00:00
João Ferreiro 211b9fc2f2 fix typescript issue; force mediatype photo 2022-11-29 16:19:15 +00:00
João Ferreiro 8b6bb6999d fixing add photo using camera 2022-11-29 16:11:17 +00:00
Paul Frazee 524cb062a2 Improvements to link and mention detection regarding surrounding punctuation 2022-11-29 10:01:57 -06:00
João Ferreiro be71989e45 move show carousel out of the component 2022-11-29 16:00:21 +00:00
João Ferreiro edb5a8ddb2 Merge branch 'main' into upload-image 2022-11-29 15:36:26 +00:00
João Ferreiro fb461c0344 further refactoring code into different components 2022-11-29 15:35:49 +00:00
Paul Frazee a8608d0170 Relax the requirement that post entities match their value 2022-11-29 09:35:10 -06:00
Paul Frazee 628f69605c Decode html entities in link embeds 2022-11-29 09:29:57 -06:00
João Ferreiro 537770b39d revert android changes 2022-11-29 15:25:32 +00:00
João Ferreiro 44eca8a550 reafctor image carousel into new component;
fix photo overlapping text in composer
2022-11-29 10:59:32 +00:00
João Ferreiro 3a79e46a4a Merge branch 'main' into upload-image 2022-11-29 10:29:19 +00:00
Paul Frazee 6f56a8c539 Improve handling of deleted posts 2022-11-28 16:37:39 -06:00
Paul Frazee 2ac28aa2de Fixes to edit profile modal 2022-11-28 14:51:49 -06:00
Paul Frazee 53c55b2d7a Fix jank in notifications loading-state rendering 2022-11-28 14:22:19 -06:00
Paul Frazee 31e0fa898a Use a persistent notifications model to improve load times of the notifications view 2022-11-28 14:19:49 -06:00
Paul Frazee 1ec46a00e2 Improve unread notification styling 2022-11-28 13:56:05 -06:00
Paul Frazee d98fbbbe4d Batch notification loads to avoid layout reflows due to async 2022-11-28 13:45:49 -06:00
João Ferreiro ef02ec9ab1 fix android compile 2022-11-28 16:56:23 +00:00
João Ferreiro 72fe122005 Merge branch 'main' into upload-image 2022-11-28 16:56:05 +00:00
João Ferreiro 4b960bc320 upload images in composer v1 2022-11-28 16:46:58 +00:00
Paul Frazee 090ea1a3f4 Slow down and enlarge post-ctrl animations (close #11) 2022-11-28 10:40:25 -06:00
Paul Frazee 983f2349e0 Fix toast positioning (close #9) 2022-11-28 10:38:16 -06:00
Paul Frazee 8af98b4a52 Set a page-size on notifications 2022-11-28 10:22:52 -06:00
Paul Frazee d821803050 Fix a couple incorrect link detections ('e.g.' and 'foo.jpg') (close #13) 2022-11-28 10:22:08 -06:00
Paul Frazee 35ead0155e Remove the 'warning color' from the character counter 2022-11-28 09:58:40 -06:00
Paul Frazee 5b908f5358 Tune post-thread expanded view: add reply prompt, fix spacing and sizing 2022-11-28 09:49:41 -06:00
Paul Frazee 099fea6624 Enlarge the 'load more posts' prompt 2022-11-28 09:30:31 -06:00
Paul Frazee a2ef0b5a68 Enlarge the view header, left align the title, and add a compose button 2022-11-28 09:29:35 -06:00
Paul Frazee 38c17e06bb Update composer to shrink fonts and use more consistent visuals; also autofocus the input 2022-11-28 09:14:04 -06:00
Paul Frazee c7c0c04b66 Increase information density and enlarge some click targets 2022-11-28 09:13:37 -06:00
Paul Frazee bc7364acca Fix 'load more' showing up incorrectly 2022-11-28 08:30:34 -06:00
Paul Frazee 1e9d265403 Add link embeds to posts 2022-11-23 17:01:00 -06:00
Paul Frazee 02689c5533 Implement a link metadata fetching util function 2022-11-23 16:29:17 -06:00
Paul Frazee d0f6da2a51 Include reposts in no-replies view of feeds 2022-11-23 16:27:49 -06:00
Paul Frazee 2e9a858e3d Remove webcrypto polyfill, as it's no longer needed 2022-11-23 15:04:44 -06:00
Paul Frazee 8e46204617 Detect links in profile bios 2022-11-23 14:53:33 -06:00
Paul Frazee b844e479a1 Add replying-to context to threads 2022-11-23 14:22:40 -06:00
Paul Frazee f7ccf14211 Ensure threads group together posts by op 2022-11-23 13:45:50 -06:00
Paul Frazee 814ddb194a Disable landscape orientation in iPhones 2022-11-23 13:34:45 -06:00
Paul Frazee d7103412e5 Fix: Adjust home TL post dedup to ensure polling works correctly 2022-11-23 13:29:26 -06:00
Paul Frazee ad4c413ae4 Show parent post in composer when replying (close #3) 2022-11-23 13:28:29 -06:00
Paul Frazee f0ed5d7c28 Fix: dont detect double dots as urls 2022-11-23 13:15:38 -06:00
Paul Frazee e8304bb77d Fix keyboard issues in search 2022-11-23 13:12:29 -06:00
Paul Frazee 5ae10f17c5 Turn composer character counter into a countdown 2022-11-23 13:07:09 -06:00
Paul Frazee 4b8de11046 Handle bsky.app links natively 2022-11-23 10:51:20 -06:00
Paul Frazee 27f94052e9 Longer shortened URLs 2022-11-23 10:44:55 -06:00
Paul Frazee 8004d038ab Add threading to post feeds 2022-11-23 10:39:28 -06:00
Paul Frazee ff9d7346ec Fallback to display name in search results 2022-11-22 16:18:10 -06:00
Paul Frazee c0298dc7b7 Implement user search 2022-11-22 16:14:58 -06:00
Paul Frazee ab0f4f8288 Keep fetching suggestions to reach a full list 2022-11-22 15:53:23 -06:00
Paul Frazee 148fa29875 Farewell, todos.txt 2022-11-22 14:31:46 -06:00
Paul Frazee f13c42c078 Add support for links with no scheme in composer 2022-11-22 14:30:35 -06:00
Paul Frazee a079605049 Fix to tests 2022-11-22 14:30:13 -06:00
Paul Frazee 56d98abe64 Shorten rendered URLs in posts 2022-11-22 13:16:40 -06:00
Paul Frazee dab5a36a58 Fix to thread reply lines (fill full space) 2022-11-22 13:04:54 -06:00
Paul Frazee 65e80556e8 Add bottom padding to threads 2022-11-22 12:58:08 -06:00
Paul Frazee b60406f960 Scroll to highlighted post in threads 2022-11-22 12:56:56 -06:00
Paul Frazee 4d2c2c5f2a Add compose prompt to home feed empty state 2022-11-22 12:29:50 -06:00
Paul Frazee deb7c1bba7 Add 'posts & replies' view to profiles 2022-11-22 12:26:53 -06:00
Paul Frazee 8b1134dc75 Turn home button into a 'go back to start of nav history' 2022-11-22 12:19:38 -06:00
Paul Frazee a83da7367c Change post prompt to 'Whats up?' 2022-11-22 12:16:08 -06:00
Paul Frazee ec3ba2ebc8 Shrink and darken the post controls a little 2022-11-22 12:15:26 -06:00
Paul Frazee ab4f828865 Shrink the footer a bit 2022-11-22 12:02:45 -06:00
Paul Frazee c72e1b6635 Refactor: create src/lib to reflect actual sharing of that code 2022-11-22 12:02:31 -06:00
Paul Frazee 4e245f8471 Merge branch 'simplify' into main 2022-11-21 18:55:08 -06:00
Paul Frazee 652362b0c2 Track rotated auth tokens 2022-11-21 16:17:40 -06:00
Paul Frazee abd6ffdbf5 Add web linking and proper share controls 2022-11-21 16:07:26 -06:00
Paul Frazee 0dc1c904ed Adjust control alignment 2022-11-20 16:29:43 -06:00
Paul Frazee a8bdb4a288 Fix the pointy edges on the arrow icons 2022-11-20 16:24:44 -06:00
Paul Frazee 9ec2712728 Move search btn into the viewheader 2022-11-20 12:25:11 -06:00
Paul Frazee 64609575e7 Add build flags and disable tabs for now 2022-11-20 12:00:40 -06:00
Paul Frazee 09411967e8 Adjust post control sizing and alignment 2022-11-20 11:45:31 -06:00
Paul Frazee fbec25412b Remove downvotes from the UI 2022-11-20 11:32:13 -06:00
Paul Frazee ffe51591e8 Replace the FAB with a compose prompt at the top of the feed 2022-11-20 11:20:08 -06:00
Paul Frazee f11ef7ba0b Dont group notifications that are an hour apart 2022-11-18 15:38:20 -06:00
Paul Frazee 0439674aa9 Fix data loss on notifications-view update 2022-11-18 14:17:26 -06:00
Paul Frazee e609f8dadb Dedup posts in the home TL 2022-11-18 14:05:19 -06:00
Paul Frazee 6af2e1d162 Add support for web links 2022-11-18 13:59:17 -06:00
Paul Frazee 35e46a5b60 Fix rendering of mentions in composer 2022-11-18 11:55:05 -06:00
Paul Frazee 14ca7602e9 Add long press newtab to footer nav 2022-11-18 11:40:12 -06:00
Paul Frazee 7c719f3af8 Fix richtext link rendering 2022-11-18 11:37:25 -06:00
Paul Frazee 547965b528 Spacing and sizing fixes 2022-11-18 11:37:12 -06:00
Paul Frazee 85a425bf3e Dont autofocus composer to avoid a bug with keyboard avoiding views 2022-11-18 11:10:29 -06:00
Paul Frazee d9d9344fcc Small sizing and spacing tweaks 2022-11-18 11:10:19 -06:00
Paul Frazee 67fb6b23da Add min height to post text 2022-11-18 10:58:48 -06:00
Paul Frazee 2a4391af97 Fix avatar click target in posts 2022-11-18 10:48:18 -06:00
Paul Frazee fec3aa2e2f Fix post thread title 2022-11-17 16:26:00 -06:00
Paul Frazee 4fcc0accc7 Add padding to the bottom of the feed to ensure compose btn doesnt cover it 2022-11-17 16:07:38 -06:00
Paul Frazee 3da90128f0 Improve reliability of screen titles 2022-11-17 16:01:29 -06:00
Paul Frazee 038556cc58 Add new tab animation 2022-11-17 15:44:54 -06:00
Paul Frazee f42ff8e4cf Add live search to autocomplete and only highlight known handles 2022-11-17 14:35:12 -06:00
Paul Frazee d073049ed2 Fix loadLatest() on home feed 2022-11-17 13:17:08 -06:00
Paul Frazee b165d076f1 Fix: correctly set visible on screens 2022-11-17 13:15:04 -06:00
Paul Frazee c16e1b8fb1 Improve perf of post rendering 2022-11-17 13:02:53 -06:00
Paul Frazee a527c1086a Invalidate profiles cache on direct load 2022-11-17 13:01:57 -06:00
Paul Frazee 6be082e728 Clear session when auth fails 2022-11-17 12:33:59 -06:00
Paul Frazee f99cdba6dd Poll periodically for new posts 2022-11-17 12:33:19 -06:00
Paul Frazee 397ace5c11 Improve coffee 2022-11-17 11:29:35 -06:00
Paul Frazee 924c76f11b Add tabs explainer and fix 'black screen' during onboard 2022-11-17 11:21:04 -06:00
Paul Frazee d875933412 Lighten the post controls 2022-11-17 11:03:38 -06:00
Paul Frazee c5a81dcc71 Fix positioning with overflows in the post meta 2022-11-17 10:56:42 -06:00
Paul Frazee 28a9fe85d5 Include tab count and move btn to center 2022-11-17 10:37:30 -06:00
Paul Frazee 29d5cef912 Open in new tab on long press 2022-11-17 10:36:57 -06:00
Paul Frazee 0e935a50e7 Avoid overlap against phone header when tabs selector is open 2022-11-17 10:24:40 -06:00
Paul Frazee 61de9aaea6 Fix header spacing for when dark mode is active 2022-11-17 10:15:48 -06:00
Paul Frazee 83a533a0dc Show bold icons in footer based on state 2022-11-16 18:04:21 -06:00
Paul Frazee 2e7da95e5b Add a fancy 'drawer' animation to the tabs selector 2022-11-16 17:18:16 -06:00
Paul Frazee 93a7667c83 Add post deletion to highlighted post in threads 2022-11-16 16:18:15 -06:00
Paul Frazee 51f78cef9a Add post deletion 2022-11-16 16:16:43 -06:00
Paul Frazee bf7581e8e3 Clear notifications count optimistically 2022-11-16 14:36:16 -06:00
Paul Frazee aa7a5964f2 Fix composer positioning 2022-11-16 14:33:01 -06:00
Paul Frazee 30c0a5f4b1 Fix input positioning for small screens 2022-11-16 14:28:33 -06:00
Paul Frazee a3c3b1cd27 Fix sizing on smaller phones 2022-11-16 14:05:21 -06:00
Paul Frazee cc775dcdc0 Nicer loading state for profiles 2022-11-16 13:32:10 -06:00
Paul Frazee 5d9c21c2a5 Reduce jank in refreshes 2022-11-16 13:18:53 -06:00
Paul Frazee 9a19607f3f Add placeholder loading states 2022-11-16 13:05:36 -06:00
Paul Frazee 3d0eeb01f8 Improve reliability of modal close 2022-11-16 12:37:46 -06:00
Paul Frazee 310ec3a574 Fix up/down vote number changes 2022-11-16 11:02:36 -06:00
Paul Frazee 96d12df021 Add animations to post controls 2022-11-16 10:58:39 -06:00
Paul Frazee f382d6f3a5 Update prod service URL 2022-11-16 10:06:57 -06:00
Paul Frazee 6de99fd964 Better invite code error message 2022-11-15 15:13:55 -06:00
Paul Frazee bc76c7ffb8 Add a server instance selector and drop env vars 2022-11-15 15:09:50 -06:00
Paul Frazee 20ed8da853 Switch to using setVote() 2022-11-15 13:19:21 -06:00
Paul Frazee aaf10bfdbf Add current user profile to header and enlarge the header 2022-11-15 13:11:01 -06:00
Paul Frazee 36b9020f36 Add compose button to notifications, profile, and search 2022-11-15 13:00:00 -06:00
Paul Frazee 5ec8fcf350 Add missing dep 2022-11-15 12:54:15 -06:00
Paul Frazee 194c6dc0fd Improve connectivity-issue error message 2022-11-15 12:54:04 -06:00
Paul Frazee aadec58087 Better loading screens 2022-11-15 12:07:41 -06:00
Paul Frazee 1b1883aa30 Improve empty states 2022-11-15 10:54:43 -06:00
Paul Frazee 020a0bc882 Improve error messages 2022-11-15 10:46:12 -06:00
Paul Frazee f2bf75e85e Add profile info caching 2022-11-14 16:56:59 -06:00
Paul Frazee 957f42698e Disable storing nav state due to bugs 2022-11-14 16:56:40 -06:00
Paul Frazee fd436dcd9b Add more info to routing 2022-11-14 16:30:06 -06:00
Paul Frazee 9e32b64d57 Restore nav state hydration 2022-11-14 16:28:58 -06:00
Paul Frazee 7d39cb5f6b Improve not found page 2022-11-14 16:27:59 -06:00
Paul Frazee a8cd419b08 Use only alphabet in generated avatar 2022-11-14 15:58:21 -06:00
Paul Frazee c20d941a77 Update all state on profile change 2022-11-14 15:55:38 -06:00
Paul Frazee 93741ac50e Make 'back swiping' a little easier 2022-11-14 15:47:56 -06:00
Paul Frazee f83739fdb9 Enforce limits on create scene as well 2022-11-14 15:19:08 -06:00
Paul Frazee daf91112f5 Fix double-posting bug 2022-11-14 15:10:34 -06:00
Paul Frazee d406b3a5c2 Fix issue causing double-loads of notifications 2022-11-14 15:02:42 -06:00
Paul Frazee 09b8ae0fed Automatically add the domain to the handle during signin 2022-11-14 14:30:59 -06:00
Paul Frazee 683a456b5c Fix empty states for scene members and memberships 2022-11-14 14:24:23 -06:00
Paul Frazee 265af0d720 Fix: scroll all the way down on home feed 2022-11-14 14:18:42 -06:00
Paul Frazee 30f6636a95 Fix overflows in post meta info 2022-11-14 14:16:31 -06:00
Paul Frazee 03980afe98 Turn off autocorrect and auto-lowercase login handle 2022-11-14 14:01:01 -06:00
Paul Frazee a3f2c28c13 Add link behaviors to search screen suggestions 2022-11-14 13:52:23 -06:00
Paul Frazee 2850887c71 Dont suggest followed users and add empty state to suggestions 2022-11-14 13:48:57 -06:00
Paul Frazee 8a403407cb Dont include self in suggested follows 2022-11-14 13:42:53 -06:00
Paul Frazee 73f1f464d8 Always fallback from displayName to handle 2022-11-14 13:39:10 -06:00
Paul Frazee 16c06cd997 Turn 'include reason' on posts into a link 2022-11-14 13:36:09 -06:00
Paul Frazee 0f1a59641a Reposition to handle scene creation keyboard view 2022-11-14 13:32:04 -06:00
Paul Frazee bd62ab2f92 Change appid to xyz.blueskyweb.app 2022-11-14 13:13:08 -06:00
Paul Frazee 4727fb25ce Improvements to the feature explainer, including intro screen and screenshot of scenes 2022-11-14 13:12:29 -06:00
Paul Frazee 0947970514 Add staging env 2022-11-11 15:02:19 -06:00
Paul Frazee 04b081bbd7 Implement profile updates 2022-11-11 14:15:43 -06:00
Paul Frazee 3a6bb19cad Add UI to remove members from scenes 2022-11-11 13:28:23 -06:00
Paul Frazee 77650f328b Implement trending 2022-11-11 13:10:05 -06:00
Paul Frazee 424a08c4a0 Handle pending invites correctly 2022-11-11 12:49:53 -06:00
Paul Frazee 18d96ce0ce Disable scene discover btn for now 2022-11-11 10:17:23 -06:00
Paul Frazee 60f4d64af6 Only suggest users in invite suggestions 2022-11-11 10:17:14 -06:00
Paul Frazee 5664ecbd0c Fixes to onboarding 2022-11-10 17:19:45 -06:00
Paul Frazee 4fa74c0d38 Fixes to account creation 2022-11-10 17:05:26 -06:00
Paul Frazee 6b3780f6d1 Fix follows 2022-11-10 16:35:13 -06:00
Paul Frazee 7d90638188 Implement scene invitation and membership controls 2022-11-10 16:30:14 -06:00
Paul Frazee 28c2591e0b More informative empty state for scenes 2022-11-09 17:34:55 -06:00
Paul Frazee 2b58550d36 Add scene creator 2022-11-09 15:57:49 -06:00
Paul Frazee 22e619d0ea Add 'you are a member' line to scene headers and small other tweaks 2022-11-09 13:48:40 -06:00
Paul Frazee a32b067057 Add creator to scene profile header 2022-11-09 13:12:03 -06:00
Paul Frazee 482f848281 Implement scene member/memberships listings 2022-11-08 16:37:21 -06:00
Paul Frazee 6f97f8a84b Implement scenes listing in main menu 2022-11-08 15:56:22 -06:00
Paul Frazee 0168efd737 Finish the upvote/downvote implementation 2022-11-08 12:14:51 -06:00
Paul Frazee bb1d0ab0d9 Add search view; factor out SuggestedFollows component; add suggested follows to search 2022-11-07 16:24:06 -06:00
Paul Frazee 0fae45e8df Add onboarding (WIP) 2022-11-07 15:35:51 -06:00
Paul Frazee 34203fcbce Reuse service address 2022-11-07 11:45:26 -06:00
Paul Frazee e64fe9d36e Sizing and spacing fixes based on on-device testing 2022-11-05 16:12:06 -05:00
Paul Frazee 11c5000b5b Unify profile follow btn colors with the rest 2022-11-05 15:07:28 -05:00
Paul Frazee 1e5046c679 Set ios app icon 2022-11-05 14:55:41 -05:00
Paul Frazee 9344f7f20d Add splash screen to ios 2022-11-05 14:52:44 -05:00
Paul Frazee b724b0d3eb Rename to bsky.app 2022-11-05 13:56:22 -05:00
Paul Frazee 6703f0c068 Replace likes with votes on post UIs 2022-11-05 13:48:45 -05:00
Paul Frazee 88345d7cb5 More profile header tweaks 2022-11-05 13:02:21 -05:00
Paul Frazee 266cd69348 Tweak profile header 2022-11-05 12:43:21 -05:00
Paul Frazee 1ae5318af0 Switch to procedurally-generated banners 2022-11-05 12:33:59 -05:00
Paul Frazee 992b79384f Add actor types to the profiles and clean up the UI 2022-11-05 11:58:48 -05:00
Paul Frazee f9fa6229b2 Update to new textslice 2022-11-04 17:56:48 -05:00
Paul Frazee 2c5b988de0 Update to the latest APIs 2022-11-04 17:39:54 -05:00
Paul Frazee feac39e657 Rework the composer to a less buggy solution 2022-11-01 14:25:41 -05:00
Paul Frazee 1fa4419da1 Remove old tabs selector modal 2022-11-01 14:00:58 -05:00
Paul Frazee f49f8b6495 Add animation to the tabs selector 2022-11-01 13:46:07 -05:00
Paul Frazee c122f8a9d7 Replace notifications icon 2022-11-01 13:45:58 -05:00
Paul Frazee 91dd25f7b1 Replace footer-nav back and forward arrows with search and notifications 2022-11-01 11:53:30 -05:00
Paul Frazee 0d1cdb7a38 Add consistent view headers 2022-11-01 11:06:43 -05:00
Paul Frazee 9238504db9 Update scene items in mainmenu to use generated avatars 2022-11-01 10:06:24 -05:00
Paul Frazee 774a3a653e Improve animation jitter in main menu 2022-11-01 10:02:24 -05:00
Paul Frazee 497155b84c Fix typo 2022-10-31 17:24:58 -05:00
Paul Frazee b03cc5862b Switch to autogenerated avis for now 2022-10-31 17:23:47 -05:00
Paul Frazee b76a6109cf WIP scene UIs 2022-10-31 12:17:58 -05:00
Paul Frazee 97d8b7cf23 Fix some useEffect() cleanup issues 2022-10-26 14:48:15 -05:00
Paul Frazee 48158e05cb Update to latest APIs 2022-10-26 14:34:47 -05:00
Paul Frazee 20890227c9 Add contacts screen 2022-10-12 18:56:10 -05:00
Paul Frazee ed86125d87 Update api nsids 2022-10-12 15:18:46 -05:00
Paul Frazee 4b8795bfea Improve main menu (animation, aesthetics) 2022-10-11 15:16:46 -05:00
Paul Frazee 07a234e0f2 Home button scrolls to top when on home page 2022-10-11 09:37:01 -05:00
Paul Frazee bf42123576 Rearrange shell buttons to merge notifications into menu and bring back forward 2022-10-11 09:19:09 -05:00
Paul Frazee 37016ccf9f Remove the firehose view from home 2022-10-11 09:18:39 -05:00
Paul Frazee 47b8b93c2c Speed up shell nav button presses 2022-10-11 09:18:24 -05:00
Paul Frazee c5f744870f Rework footer controls 2022-10-10 21:13:25 -05:00
Paul Frazee 993a273d76 Rework profile header controls 2022-10-10 21:13:10 -05:00
Paul Frazee 6ee93cdbc4 Add firehose view to home screen 2022-10-04 14:22:20 -05:00
Paul Frazee 9a57f5de5e Update to new get*Feed xrpc methods 2022-10-04 12:55:25 -05:00
Paul Frazee 94f365f564 Update the view after a post is created 2022-10-04 11:33:32 -05:00
Paul Frazee 01515de17d Implement profile-update api 2022-10-04 11:10:24 -05:00
Paul Frazee f074d6017d Implement a couple missing bits 2022-10-04 10:53:08 -05:00
Paul Frazee 5b96be04b4 Fix to mention rendering 2022-10-04 10:26:33 -05:00
Paul Frazee de7951074a Choose mention candidates from follows 2022-10-04 10:18:35 -05:00
Paul Frazee 990b3c7084 Fixes to entity extraction 2022-10-04 10:15:35 -05:00
Paul Frazee 7de013f467 Implement mentions rendering 2022-10-03 16:02:03 -05:00
Paul Frazee ba417935f0 Fix to auth of mutation ops 2022-10-03 11:17:12 -05:00
Paul Frazee a77988a984 Implement notifications 2022-10-03 10:53:36 -05:00
Paul Frazee 5b8d0957b3 Remove debug time delays 2022-09-30 11:30:18 -05:00
Paul Frazee a913745b8f Fix thread view sizing 2022-09-29 15:17:31 -05:00
Paul Frazee 2f7e3da138 Clear all state on signout 2022-09-29 13:55:07 -05:00
Paul Frazee 13ce232455 Add settings page 2022-09-29 11:59:11 -05:00
Paul Frazee a67b4847ca Light icons 2022-09-29 10:40:05 -05:00
Paul Frazee 49beea6cc8 Add profile to tabs selector modal 2022-09-29 09:24:36 -05:00
Paul Frazee ee81540c64 More blue theming 2022-09-29 09:11:48 -05:00
Paul Frazee ccd3492e1e Beta banner 2022-09-29 09:05:47 -05:00
Paul Frazee 0a37c34704 Remove top bar in the shell 2022-09-29 09:05:40 -05:00
Paul Frazee 60c2805c01 Swap new tab and share buttons in tabs modal 2022-09-29 09:05:07 -05:00
Paul Frazee debfb16520 No visual feedback on FAB to reduce jank 2022-09-29 09:04:49 -05:00
Paul Frazee 76782b6ff1 Fix feed pagination on user profiles 2022-09-28 17:02:55 -05:00
Paul Frazee 1ccb0e8123 Add reply information to feed items 2022-09-28 15:36:25 -05:00
Paul Frazee d9cf32f0ac Improve thread rendering (show reply lines) 2022-09-28 15:03:16 -05:00
Paul Frazee 521e691138 Fix to session load 2022-09-28 15:03:02 -05:00
Paul Frazee be9d89e0cc Switch to one default avi 2022-09-28 14:00:40 -05:00
Paul Frazee b93b57c83e Update api 2022-09-28 13:59:57 -05:00
Paul Frazee 6bad17e353 Add account creation 2022-09-27 14:24:47 -05:00
Paul Frazee eaabfb8250 Remove old auth code 2022-09-27 10:13:12 -05:00
Paul Frazee 1001c5b4c4 Add logout and tweak signin screen 2022-09-27 08:59:15 -05:00
Paul Frazee 2441cbfde6 Implement signin flow 2022-09-26 21:03:07 -05:00
Paul Frazee b2b6df7a7e A few client fixes 2022-09-26 13:38:37 -05:00
Paul Frazee d954f6d905 Implement unfollow, unlike, unrepost 2022-09-23 09:47:21 -05:00
Paul Frazee 3269f048b3 Replace mock-api with real api 2022-09-22 19:28:25 -05:00
Paul Frazee 5c07a74c55 Add close animation to tabs selector 2022-09-09 16:45:37 -05:00
Paul Frazee 744a21ec57 Replace tabs selector with better solution, also fix some bugs with the modal state 2022-09-09 16:20:46 -05:00
Paul Frazee c55711a1d9 Reduce the frequency of accidental visual triggers of touchable items 2022-09-09 13:24:44 -05:00
Paul Frazee ddcc804518 Fix some jank in the navigation swipes 2022-09-09 13:11:30 -05:00
Paul Frazee 56f983fd4e Disable swipe gestures in view selector for now 2022-09-09 12:10:18 -05:00
Paul Frazee d85751caf0 Make view-selector swipes easier to trigger 2022-09-09 11:58:28 -05:00
Paul Frazee 79a5064072 Make nav swipes easier to trigger 2022-09-09 11:55:53 -05:00
Paul Frazee cb083f3836 Allow nav swipes to start from anywhere on the screen 2022-09-09 11:55:31 -05:00
Paul Frazee 3677f3be4b UI sizing fixes 2022-09-09 11:29:46 -05:00
Paul Frazee fc835be1e6 Rename mobile start-point index.js to avoid build issues 2022-09-09 11:29:22 -05:00
Paul Frazee 40fdd27698 Implement autocomplete UI in composer 2022-09-08 13:39:53 -05:00
Paul Frazee d46de5b819 Add EditProfile modal 2022-09-07 16:00:25 -05:00
Paul Frazee 9627e9981d Improve navigation gesture and fix caching issue 2022-09-07 14:43:00 -05:00
Paul Frazee 5852f17bed Refactor profile to use new ViewSelector element which is reusable and now supports swipe gestures 2022-09-06 22:34:31 -05:00
Paul Frazee 80c4566baf Add 'swipe to go back' gesture 2022-09-06 17:29:26 -05:00
Paul Frazee 8b286a2179 Rework profile page to include working view selector 2022-09-06 14:26:39 -05:00
Paul Frazee 9abeb86168 Rework profile header 2022-09-05 16:57:20 -05:00
Paul Frazee 0963e67325 Rewrite the post composer as a modal 2022-09-05 14:16:48 -05:00
Paul Frazee 8dba18b67c Add post dropdown menus 2022-09-02 15:43:10 -05:00
Paul Frazee 4e56f11d06 Move SharePost modal to new system 2022-09-02 12:17:33 -05:00
Paul Frazee 39f13f01bc Implement consistent Link component 2022-09-02 11:52:33 -05:00
Paul Frazee 2ed9ea85c6 Add more robust modals controller 2022-09-02 11:51:46 -05:00
Paul Frazee 61b5a0cbe9 Rename location-menu to location-navigator and add an actual location-menu 2022-09-02 09:55:52 -05:00
Paul Frazee c3831bd799 Add accounts menu to shell 2022-09-02 09:30:21 -05:00
Paul Frazee 53deb48e2d Add location 'menu' 2022-09-01 16:06:09 -05:00
Paul Frazee 2eac309f86 Fix bug in selection of screens to cache 2022-09-01 13:30:57 -05:00
Paul Frazee 558f8010eb Implement working screen-state management and remove extraneous loads 2022-09-01 12:00:08 -05:00
Paul Frazee 36e3697fd6 Fix screen-blanking bug 2022-09-01 10:58:29 -05:00
Paul Frazee 42f1c5d45d Update post thread aesthetics 2022-08-31 21:02:12 -05:00
Paul Frazee 00c4940352 Add avi and context menu to shell topbar 2022-08-31 20:43:36 -05:00
Paul Frazee 3075ded77f Add composer FAB to home page 2022-08-31 20:09:58 -05:00
Paul Frazee 94fd697148 Aesthetic improvements 2022-08-31 20:09:47 -05:00
Paul Frazee a3df278f7d Unify the color palette 2022-08-31 17:06:44 -05:00
Paul Frazee 135a0456a2 New navigation model (#1)
* Flatten all routing into a single stack

* Replace router with custom implementation

* Add shell header and titles

* Add tab selector

* Add back/forward history menus on longpress

* Fix: don't modify state during render

* Add refresh() to navigation and reroute navigations to the current location to refresh instead of add to history

* Cache screens during navigation to maintain scroll position and improve load-time for renders
2022-08-31 14:36:50 -05:00
415 changed files with 39528 additions and 22354 deletions
+85
View File
@@ -0,0 +1,85 @@
/** @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/app.app',
build:
'xcodebuild -workspace ios/app.xcworkspace -scheme app -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',
},
'ios.release': {
type: 'ios.app',
binaryPath: 'ios/build/Build/Products/Release-iphonesimulator/app.app',
build:
'xcodebuild -workspace ios/app.xcworkspace -scheme app -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 14',
},
},
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
View File
@@ -1 +0,0 @@
REACT_APP_AUTH_LOBBY = 'http://localhost:3001'
+8 -4
View File
@@ -2,14 +2,18 @@ module.exports = {
root: true,
extends: '@react-native-community',
parser: '@typescript-eslint/parser',
// plugins: ['@typescript-eslint'],
plugins: ['@typescript-eslint', 'detox'],
ignorePatterns: [
'**/__mocks__/*.ts',
'src/third-party',
'ios',
'android',
'coverage',
],
overrides: [
{
files: ['*.js', '*.mjs', '*.ts', '*.tsx'],
rules: {
'@typescript-eslint/no-shadow': 'off',
'no-shadow': 'off',
'no-undef': 'off',
semi: [2, 'never'],
},
},
+38
View File
@@ -0,0 +1,38 @@
name: Lint
on:
pull_request:
branches:
- main
jobs:
linting:
name: Run linters
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v3
- name: Yarn install
run: yarn
- name: Lint Reporter
uses: wearerequired/lint-action@v2.2.0
with:
eslint: true
prettier: true
- name: Typescript & Lint check
run: yarn lint
testing:
name: Run tests
runs-on: ubuntu-latest
steps:
- name: Install node 18
uses: actions/setup-node@v3
with:
node-version: 18
- name: Check out Git repository
uses: actions/checkout@v3
- name: Yarn install
run: yarn
- name: Run tests
run: |
yarn test --forceExit
+18
View File
@@ -59,3 +59,21 @@ buck-out/
# Ruby / CocoaPods
/ios/Pods/
/vendor/bundle/
# Testing
coverage/
junit.xml
artifacts
.expo/
dist/
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/
# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*
+5
View File
@@ -0,0 +1,5 @@
ios
android
src/third-party
src/app.json
public
+1 -1
View File
@@ -1 +1 @@
2.7.4
2.7.6
+2 -2
View File
@@ -1,6 +1,6 @@
source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby '2.7.4'
ruby File.read(File.join(__dir__, '.ruby-version')).strip
gem 'cocoapods', '~> 1.11', '>= 1.11.2'
gem 'cocoapods', '~> 1.11', '>= 1.11.3'
+16 -40
View File
@@ -1,28 +1,19 @@
# Social App
In-progress social app.
Uses:
- [React Native](https://reactnative.dev)
- [React Native for Web](https://necolas.github.io/react-native-web/)
- [React Navigation](https://reactnative.dev/docs/navigation#react-navigation)
- [MobX](https://mobx.js.org/README.html)
- [Async Storage](https://github.com/react-native-async-storage/async-storage)
## TODOs
- Handle the "unauthed" state better than changing route definitions
- Currently it's possible to get a 404 if the auth state changes
# Bluesky
## Build instructions
- Setup your environment [using the react native instructions](https://reactnative.dev/docs/environment-setup).
- 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:
- `cd ios ; pod install`
- Start the dev servers
- `yarn dev-pds`
- `yarn dev-wallet`
- `git clone git@github.com:bluesky-social/atproto.git`
- `cd atproto`
- `yarn`
- `cd packages/dev-env && yarn start`
- Run the dev app
- iOS: `yarn ios`
- Android: `yarn android`
@@ -37,34 +28,19 @@ Uses:
## Various notes
### Env vars
### Debugging
Set using the `.env` file or using bash.
- Note that since 0.70, debugging using the old debugger (which shows up using CMD+D) doesn't work anymore. Follow the instructions below to debug the code: https://reactnative.dev/docs/next/hermes#debugging-js-on-hermes-using-google-chromes-devtools
```
REACT_APP_AUTH_LOBBY = 'http://localhost:3001'
```
### Running E2E Tests
### Build behaviors
The `metro.config.js` file rewrites a couple of imports. This is partly to work around missing features in Metro, and partly to patch the bundle. Affected imports include:
- ucans
- one-webcrypto
### Cryptography
For native builds, we must provide a polyfill of `webcrypto`. We use a custom native module AppSecureRandom (based on [react-native-securerandom](https://github.com/robhogan/react-native-securerandom)) for the CRNG and [msrcrypto](https://github.com/microsoft/MSR-JavaScript-Crypto) for the cryptography.
**NOTE** Keys are not currently stored securely.
- Make sure you've setup your environment following above
- Make sure Metro and the dev server are running
- Run `yarn e2e`
- Find the artifacts in the `artifact` folder
### Polyfills
`./platform/polyfills.*.ts` adds polyfills to the environment. Currently this includes:
- webcrypto
- TextEncoder / TextDecoder
### Auth flow
The auth flow is based on a browser app which is specified by the `REACT_APP_AUTH_LOBBY` env var. The app redirects to that location with the UCAN request, and then waits for a redirect back. In the native platforms with proper support, it will do this using an in-app browser. In native without in-app browser, or in the Web platform, it will handle this with redirects. The ucan is extracted from the hash fragment of the "return url" which is provided either by the in-app browser in response or detected during initial setup in the case of redirects.
+57
View File
@@ -0,0 +1,57 @@
import React from 'react'
import {View, ScrollView, Modal, FlatList, TextInput} from 'react-native'
const BottomSheetModalContext = React.createContext(null)
const BottomSheetModalProvider = (props: any) => {
return <BottomSheetModalContext.Provider {...props} value={{}} />
}
class BottomSheet extends React.Component<{onClose?: () => void}> {
snapToIndex() {}
snapToPosition() {}
expand() {}
collapse() {}
close() {
this.props.onClose?.()
}
forceClose() {}
render() {
return <View>{this.props.children}</View>
}
}
const BottomSheetModal = (props: any) => <Modal {...props} />
const BottomSheetBackdrop = (props: any) => <View {...props} />
const BottomSheetHandle = (props: any) => <View {...props} />
const BottomSheetFooter = (props: any) => <View {...props} />
const BottomSheetScrollView = (props: any) => <ScrollView {...props} />
const BottomSheetFlatList = (props: any) => <FlatList {...props} />
const BottomSheetTextInput = (props: any) => <TextInput {...props} />
const useBottomSheet = jest.fn()
const useBottomSheetModal = jest.fn()
const useBottomSheetSpringConfigs = jest.fn()
const useBottomSheetTimingConfigs = jest.fn()
const useBottomSheetInternal = jest.fn()
const useBottomSheetDynamicSnapPoints = jest.fn()
export {useBottomSheet}
export {useBottomSheetModal}
export {useBottomSheetSpringConfigs}
export {useBottomSheetTimingConfigs}
export {useBottomSheetInternal}
export {useBottomSheetDynamicSnapPoints}
export {
BottomSheetModalProvider,
BottomSheetBackdrop,
BottomSheetHandle,
BottomSheetModal,
BottomSheetFooter,
BottomSheetScrollView,
BottomSheetFlatList,
BottomSheetTextInput,
}
export default BottomSheet
+6
View File
@@ -0,0 +1,6 @@
export default {
requestPermission: jest.fn(),
onForegroundEvent: jest.fn(),
setBadgeCount: jest.fn(),
displayNotification: jest.fn(),
}
@@ -0,0 +1,9 @@
export const CameraRoll = {
getPhotos: jest.fn().mockResolvedValue({
edges: [
{node: {image: {uri: 'path/to/image1.jpg'}}},
{node: {image: {uri: 'path/to/image2.jpg'}}},
{node: {image: {uri: 'path/to/image3.jpg'}}},
],
}),
}
@@ -0,0 +1,4 @@
export default {
configure: jest.fn().mockResolvedValue(0),
finish: jest.fn(),
}
+1
View File
@@ -0,0 +1 @@
export default {}
+9
View File
@@ -0,0 +1,9 @@
export const openPicker = jest
.fn()
.mockImplementation(() => Promise.resolve({uri: ''}))
export const openCamera = jest
.fn()
.mockImplementation(() => Promise.resolve({uri: ''}))
export const openCropper = jest
.fn()
.mockImplementation(() => Promise.resolve({uri: ''}))
+67
View File
@@ -0,0 +1,67 @@
// @flow
// https://github.com/FormidableLabs/react-native-svg-mock
import React from 'react'
const createComponent = function (name) {
return class extends React.Component {
// overwrite the displayName, since this is a class created dynamically
static displayName = name
render() {
return React.createElement(name, this.props, this.props.children)
}
}
}
// Mock all react-native-svg exports
// from https://github.com/magicismight/react-native-svg/blob/master/index.js
const Svg = createComponent('Svg')
const Circle = createComponent('Circle')
const Ellipse = createComponent('Ellipse')
const G = createComponent('G')
const Text = createComponent('Text')
const TextPath = createComponent('TextPath')
const TSpan = createComponent('TSpan')
const Path = createComponent('Path')
const Polygon = createComponent('Polygon')
const Polyline = createComponent('Polyline')
const Line = createComponent('Line')
const Rect = createComponent('Rect')
const Use = createComponent('Use')
const Image = createComponent('Image')
const Symbol = createComponent('Symbol')
const Defs = createComponent('Defs')
const LinearGradient = createComponent('LinearGradient')
const RadialGradient = createComponent('RadialGradient')
const Stop = createComponent('Stop')
const ClipPath = createComponent('ClipPath')
const Pattern = createComponent('Pattern')
const Mask = createComponent('Mask')
export {
Svg,
Circle,
Ellipse,
G,
Text,
TextPath,
TSpan,
Path,
Polygon,
Polyline,
Line,
Rect,
Use,
Image,
Symbol,
Defs,
LinearGradient,
RadialGradient,
Stop,
ClipPath,
Pattern,
Mask,
}
export default Svg
+10
View File
@@ -0,0 +1,10 @@
jest.mock('rn-fetch-blob', () => {
return {
__esModule: true,
default: {
fs: {
unlink: jest.fn(),
},
},
}
})
-16
View File
@@ -1,16 +0,0 @@
/**
* @format
*/
import 'react-native'
import React from 'react'
import App from '../src/App'
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer'
it('renders correctly', () => {
renderer.act(() => {
renderer.create(<App />)
})
})
+47
View File
@@ -0,0 +1,47 @@
export const exampleComHtml = `<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta name="description" content="An example website">
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
background-color: #fdfdff;
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>`
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+47
View File
@@ -0,0 +1,47 @@
import {bundleAsync} from '../../../src/lib/async/bundle'
describe('bundle', () => {
it('bundles multiple simultaneous calls into one execution', async () => {
let calls = 0
const fn = bundleAsync(async () => {
calls++
await new Promise(r => setTimeout(r, 1))
return 'hello'
})
const [res1, res2, res3] = await Promise.all([fn(), fn(), fn()])
expect(calls).toEqual(1)
expect(res1).toEqual('hello')
expect(res2).toEqual('hello')
expect(res3).toEqual('hello')
})
it('does not bundle non-simultaneous calls', async () => {
let calls = 0
const fn = bundleAsync(async () => {
calls++
await new Promise(r => setTimeout(r, 1))
return 'hello'
})
const res1 = await fn()
const res2 = await fn()
const res3 = await fn()
expect(calls).toEqual(3)
expect(res1).toEqual('hello')
expect(res2).toEqual('hello')
expect(res3).toEqual('hello')
})
it('is not affected by rejections', async () => {
let calls = 0
const fn = bundleAsync(async () => {
calls++
await new Promise(r => setTimeout(r, 1))
throw new Error()
})
const res1 = await fn().catch(() => 'reject')
const res2 = await fn().catch(() => 'reject')
const res3 = await fn().catch(() => 'reject')
expect(calls).toEqual(3)
expect(res1).toEqual('reject')
expect(res2).toEqual('reject')
expect(res3).toEqual('reject')
})
})
+19
View File
@@ -0,0 +1,19 @@
import {isNetworkError} from '../../src/lib/strings/errors'
describe('isNetworkError', () => {
const inputs = [
'TypeError: Network request failed',
'Uncaught TypeError: Cannot read property x of undefined',
'Uncaught RangeError',
'Error: Aborted',
]
const outputs = [true, false, false, true]
it('correctly distinguishes network errors', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const result = isNetworkError(input)
expect(result).toEqual(outputs[i])
}
})
})
+134
View File
@@ -0,0 +1,134 @@
import {extractHtmlMeta} from '../../src/lib/link-meta/html'
import {exampleComHtml} from './__mocks__/exampleComHtml'
import {youtubeHTML} from './__mocks__/youtubeHtml'
import {tiktokHtml} from './__mocks__/tiktokHtml'
import {youtubeChannelHtml} from './__mocks__/youtubeChannelHtml'
describe('extractHtmlMeta', () => {
const cases = [
['', {}],
['nothing', {}],
['<title>title</title>', {title: 'title'}],
['<title> aSd!@#AC </title>', {title: 'aSd!@#AC'}],
['<title>\n title\n </title>', {title: 'title'}],
['<meta name="title" content="meta title">', {title: 'meta title'}],
[
'<meta name="description" content="meta description">',
{description: 'meta description'},
],
['<meta property="og:title" content="og title">', {title: 'og title'}],
[
'<meta property="og:description" content="og description">',
{description: 'og description'},
],
[
'<meta property="og:image" content="https://ogimage.com/foo.png">',
{image: 'https://ogimage.com/foo.png'},
],
[
'<meta property="twitter:title" content="twitter title">',
{title: 'twitter title'},
],
[
'<meta property="twitter:description" content="twitter description">',
{description: 'twitter description'},
],
[
'<meta property="twitter:image" content="https://twitterimage.com/foo.png">',
{image: 'https://twitterimage.com/foo.png'},
],
['<meta\n name="title"\n content="meta title"\n>', {title: 'meta title'}],
]
it.each(cases)(
'given the html tag %p, returns %p',
// @ts-ignore not worth fixing -prf
(input, expectedResult) => {
const output = extractHtmlMeta({html: input as string, hostname: ''})
expect(output).toEqual(expectedResult)
},
)
it('extracts title and description from a generic HTML page', () => {
const input = exampleComHtml
const expectedOutput = {
title: 'Example Domain',
description: 'An example website',
}
const output = extractHtmlMeta({html: input, hostname: 'example.com'})
expect(output).toEqual(expectedOutput)
})
it('extracts title and description from a Tiktok HTML page', () => {
const input = tiktokHtml
const expectedOutput = {
title:
'Coca-Cola and Mentos! Super Reaction! #cocacola #mentos #reaction #bal... | TikTok',
description:
'5.5M Likes, 20.8K Comments. TikTok video from Power Vision Tests (@_powervision_): &quot;Coca-Cola and Mentos! Super Reaction! #cocacola #mentos #reaction #balloon #sciencemoment #scienceexperiment #experiment #test #amazing #pvexp&quot;. оригинальный звук - Power Vision Tests.',
}
const output = extractHtmlMeta({html: input, hostname: 'tiktok.com'})
expect(output).toEqual(expectedOutput)
})
it('extracts title and description from a generic youtube page', () => {
const input = youtubeHTML
const expectedOutput = {
title: 'HD Video (1080p) with Relaxing Music of Native American Shamans',
description:
'Stunning HD Video ( 1080p ) of Patagonian Nature with Relaxing Native American Shamanic Music. HD footage used from ',
image: 'https://i.ytimg.com/vi/x6UITRjhijI/sddefault.jpg',
}
const output = extractHtmlMeta({html: input, hostname: 'youtube.com'})
expect(output).toEqual(expectedOutput)
})
it('extracts avatar from a youtube channel', () => {
const input = youtubeChannelHtml
const expectedOutput = {
title: 'penguinz0',
description:
'Clips channel: https://www.youtube.com/channel/UC4EQHfzIbkL_Skit_iKt1aA\n\nTwitter: https://twitter.com/MoistCr1TiKaL\n\nInstagram: https://www.instagram.com/bigmoistcr1tikal/?hl=en\n\nTwitch: https://www.twitch.tv/moistcr1tikal\n\nSnapchat: Hugecharles\n\nTik Tok: Hugecharles\n\nI don&#39;t have any other public accounts.',
image:
'https://yt3.googleusercontent.com/ytc/AL5GRJWOhJOuUC6C2b7gP-5D2q6ypXbcOOckyAE1En4RUQ=s176-c-k-c0x00ffffff-no-rj',
}
const output = extractHtmlMeta({html: input, hostname: 'youtube.com'})
expect(output).toEqual(expectedOutput)
})
it('extracts username from the url a twitter profile page', () => {
const expectedOutput = {
title: '@bluesky on Twitter',
}
const output = extractHtmlMeta({
html: '',
hostname: 'twitter.com',
pathname: '/bluesky',
})
expect(output).toEqual(expectedOutput)
})
it('extracts username from the url a tweet', () => {
const expectedOutput = {
title: 'Tweet by @bluesky',
}
const output = extractHtmlMeta({
html: '',
hostname: 'twitter.com',
pathname: '/bluesky/status/1582437529969917953',
})
expect(output).toEqual(expectedOutput)
})
it("does not extract username from the url when it's not a tweet or profile page", () => {
const expectedOutput = {
title: 'Twitter',
}
const output = extractHtmlMeta({
html: '',
hostname: 'twitter.com',
pathname: '/i/articles/follows/-1675653703?time_window=24',
})
expect(output).toEqual(expectedOutput)
})
})
+121
View File
@@ -0,0 +1,121 @@
import {
downloadAndResize,
DownloadAndResizeOpts,
} from '../../src/lib/media/manip'
import ImageResizer from '@bam.tech/react-native-image-resizer'
import RNFetchBlob from 'rn-fetch-blob'
describe('downloadAndResize', () => {
const errorSpy = jest.spyOn(global.console, 'error')
const mockResizedImage = {
path: jest.fn().mockReturnValue('file://resized-image.jpg'),
size: 100,
width: 50,
height: 50,
mime: 'image/jpeg',
}
beforeEach(() => {
const mockedCreateResizedImage =
ImageResizer.createResizedImage as jest.Mock
mockedCreateResizedImage.mockResolvedValue(mockResizedImage)
})
afterEach(() => {
jest.clearAllMocks()
})
it('should return resized image for valid URI and options', async () => {
const mockedFetch = RNFetchBlob.fetch as jest.Mock
mockedFetch.mockResolvedValueOnce({
path: jest.fn().mockReturnValue('file://downloaded-image.jpg'),
flush: jest.fn(),
})
const opts: DownloadAndResizeOpts = {
uri: 'https://example.com/image.jpg',
width: 100,
height: 100,
maxSize: 500000,
mode: 'cover',
timeout: 10000,
}
const result = await downloadAndResize(opts)
expect(result).toEqual(mockResizedImage)
expect(RNFetchBlob.config).toHaveBeenCalledWith({
fileCache: true,
appendExt: 'jpeg',
})
expect(RNFetchBlob.fetch).toHaveBeenCalledWith(
'GET',
'https://example.com/image.jpg',
)
expect(ImageResizer.createResizedImage).toHaveBeenCalledWith(
'file://downloaded-image.jpg',
100,
100,
'JPEG',
100,
undefined,
undefined,
undefined,
{mode: 'cover'},
)
})
it('should return undefined for invalid URI', async () => {
const opts: DownloadAndResizeOpts = {
uri: 'invalid-uri',
width: 100,
height: 100,
maxSize: 500000,
mode: 'cover',
timeout: 10000,
}
const result = await downloadAndResize(opts)
expect(errorSpy).toHaveBeenCalled()
expect(result).toBeUndefined()
})
it('should return undefined for unsupported file type', async () => {
const mockedFetch = RNFetchBlob.fetch as jest.Mock
mockedFetch.mockResolvedValueOnce({
path: jest.fn().mockReturnValue('file://downloaded-image'),
flush: jest.fn(),
})
const opts: DownloadAndResizeOpts = {
uri: 'https://example.com/image',
width: 100,
height: 100,
maxSize: 500000,
mode: 'cover',
timeout: 10000,
}
const result = await downloadAndResize(opts)
expect(result).toEqual(mockResizedImage)
expect(RNFetchBlob.config).toHaveBeenCalledWith({
fileCache: true,
appendExt: 'jpeg',
})
expect(RNFetchBlob.fetch).toHaveBeenCalledWith(
'GET',
'https://example.com/image',
)
expect(ImageResizer.createResizedImage).toHaveBeenCalledWith(
'file://downloaded-image',
100,
100,
'JPEG',
100,
undefined,
undefined,
undefined,
{mode: 'cover'},
)
})
})
+118
View File
@@ -0,0 +1,118 @@
import {
LikelyType,
getLinkMeta,
getLikelyType,
} from '../../src/lib/link-meta/link-meta'
import {exampleComHtml} from './__mocks__/exampleComHtml'
import AtpAgent from '@atproto/api'
import {DEFAULT_SERVICE, RootStoreModel} from '../../src/state'
describe('getLinkMeta', () => {
let rootStore: RootStoreModel
beforeEach(() => {
rootStore = new RootStoreModel(new AtpAgent({service: DEFAULT_SERVICE}))
})
const inputs = [
'',
'httpbadurl',
'https://example.com',
'https://example.com/index.html',
'https://example.com/image.png',
'https://example.com/video.avi',
'https://example.com/audio.ogg',
'https://example.com/text.txt',
'https://example.com/javascript.js',
'https://bsky.app/',
'https://bsky.app/index.html',
]
const outputs = [
{
error: 'Invalid URL',
likelyType: LikelyType.Other,
url: '',
},
{
error: 'Invalid URL',
likelyType: LikelyType.Other,
url: 'httpbadurl',
},
{
likelyType: LikelyType.HTML,
url: 'https://example.com',
title: 'Example Domain',
description: 'An example website',
},
{
likelyType: LikelyType.HTML,
url: 'https://example.com/index.html',
title: 'Example Domain',
description: 'An example website',
},
{
likelyType: LikelyType.Image,
url: 'https://example.com/image.png',
},
{
likelyType: LikelyType.Video,
url: 'https://example.com/video.avi',
},
{
likelyType: LikelyType.Audio,
url: 'https://example.com/audio.ogg',
},
{
likelyType: LikelyType.Text,
url: 'https://example.com/text.txt',
},
{
likelyType: LikelyType.Other,
url: 'https://example.com/javascript.js',
},
{
likelyType: LikelyType.AtpData,
url: '/',
title: 'Bluesky',
description: 'A new kind of social network',
},
{
likelyType: LikelyType.AtpData,
url: '/index.html',
title: 'Not found',
},
{
likelyType: LikelyType.Other,
url: '',
title: '',
},
]
it('correctly handles a set of text inputs', async () => {
for (let i = 0; i < inputs.length; i++) {
global.fetch = jest.fn().mockImplementationOnce(() => {
return new Promise((resolve, _reject) => {
resolve({
ok: true,
status: 200,
text: () => exampleComHtml,
})
})
})
const input = inputs[i]
const output = await getLinkMeta(rootStore, input)
expect(output).toEqual(outputs[i])
}
})
})
describe('getLikelyType', () => {
it('correctly handles non-parsed url', async () => {
const output = await getLikelyType('https://example.com')
expect(output).toEqual(LikelyType.HTML)
})
it('handles non-string urls without crashing', async () => {
const output = await getLikelyType('123')
expect(output).toEqual(LikelyType.Other)
})
})
+24
View File
@@ -0,0 +1,24 @@
import {clamp} from '../../src/lib/numbers'
describe('clamp', () => {
const inputs: [number, number, number][] = [
[100, 0, 200],
[100, 0, 100],
[0, 0, 100],
[100, 0, -1],
[4, 1, 1],
[100, -100, 0],
[400, 100, -100],
[70, -1, 1],
[Infinity, Infinity, Infinity],
]
const outputs = [100, 100, 0, -1, 1, 0, -100, 1, Infinity]
it('correctly clamps any given number and range', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const result = clamp(...input)
expect(result).toEqual(outputs[i])
}
})
})
+516
View File
@@ -0,0 +1,516 @@
import {
getYoutubeVideoId,
makeRecordUri,
toNiceDomain,
toShortUrl,
toShareUrl,
} from '../../src/lib/strings/url-helpers'
import {pluralize, enforceLen} from '../../src/lib/strings/helpers'
import {ago} from '../../src/lib/strings/time'
import {
extractEntities,
detectLinkables,
} from '../../src/lib/strings/rich-text-detection'
import {makeValidHandle, createFullHandle} from '../../src/lib/strings/handles'
import {cleanError} from '../../src/lib/strings/errors'
describe('extractEntities', () => {
const knownHandles = new Set(['handle.com', 'full123.test-of-chars'])
const inputs = [
'no mention',
'@handle.com middle end',
'start @handle.com end',
'start middle @handle.com',
'@handle.com @handle.com @handle.com',
'@full123.test-of-chars',
'not@right',
'@handle.com!@#$chars',
'@handle.com\n@handle.com',
'parenthetical (@handle.com)',
'start https://middle.com end',
'start https://middle.com/foo/bar end',
'start https://middle.com/foo/bar?baz=bux end',
'start https://middle.com/foo/bar?baz=bux#hash end',
'https://start.com/foo/bar?baz=bux#hash middle end',
'start middle https://end.com/foo/bar?baz=bux#hash',
'https://newline1.com\nhttps://newline2.com',
'start middle.com end',
'start middle.com/foo/bar end',
'start middle.com/foo/bar?baz=bux end',
'start middle.com/foo/bar?baz=bux#hash end',
'start.com/foo/bar?baz=bux#hash middle end',
'start middle end.com/foo/bar?baz=bux#hash',
'newline1.com\nnewline2.com',
'not.. a..url ..here',
'e.g.',
'something-cool.jpg',
'website.com.jpg',
'e.g./foo',
'website.com.jpg/foo',
'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/',
'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/ ',
'https://foo.com https://bar.com/whatever https://baz.com',
'punctuation https://foo.com, https://bar.com/whatever; https://baz.com.',
'parenthentical (https://foo.com)',
'except for https://foo.com/thing_(cool)',
]
interface Output {
type: string
value: string
noScheme?: boolean
}
const outputs: Output[][] = [
[],
[{type: 'mention', value: 'handle.com'}],
[{type: 'mention', value: 'handle.com'}],
[{type: 'mention', value: 'handle.com'}],
[
{type: 'mention', value: 'handle.com'},
{type: 'mention', value: 'handle.com'},
{type: 'mention', value: 'handle.com'},
],
[
{
type: 'mention',
value: 'full123.test-of-chars',
},
],
[],
[{type: 'mention', value: 'handle.com'}],
[
{type: 'mention', value: 'handle.com'},
{type: 'mention', value: 'handle.com'},
],
[{type: 'mention', value: 'handle.com'}],
[{type: 'link', value: 'https://middle.com'}],
[{type: 'link', value: 'https://middle.com/foo/bar'}],
[{type: 'link', value: 'https://middle.com/foo/bar?baz=bux'}],
[{type: 'link', value: 'https://middle.com/foo/bar?baz=bux#hash'}],
[{type: 'link', value: 'https://start.com/foo/bar?baz=bux#hash'}],
[{type: 'link', value: 'https://end.com/foo/bar?baz=bux#hash'}],
[
{type: 'link', value: 'https://newline1.com'},
{type: 'link', value: 'https://newline2.com'},
],
[{type: 'link', value: 'middle.com', noScheme: true}],
[{type: 'link', value: 'middle.com/foo/bar', noScheme: true}],
[{type: 'link', value: 'middle.com/foo/bar?baz=bux', noScheme: true}],
[{type: 'link', value: 'middle.com/foo/bar?baz=bux#hash', noScheme: true}],
[{type: 'link', value: 'start.com/foo/bar?baz=bux#hash', noScheme: true}],
[{type: 'link', value: 'end.com/foo/bar?baz=bux#hash', noScheme: true}],
[
{type: 'link', value: 'newline1.com', noScheme: true},
{type: 'link', value: 'newline2.com', noScheme: true},
],
[],
[],
[],
[],
[],
[],
[
{
type: 'link',
value:
'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/',
},
],
[
{
type: 'link',
value:
'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/',
},
],
[
{type: 'link', value: 'https://foo.com'},
{type: 'link', value: 'https://bar.com/whatever'},
{type: 'link', value: 'https://baz.com'},
],
[
{type: 'link', value: 'https://foo.com'},
{type: 'link', value: 'https://bar.com/whatever'},
{type: 'link', value: 'https://baz.com'},
],
[{type: 'link', value: 'https://foo.com'}],
[{type: 'link', value: 'https://foo.com/thing_(cool)'}],
]
it('correctly handles a set of text inputs', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const result = extractEntities(input, knownHandles)
if (!outputs[i].length) {
expect(result).toBeFalsy()
} else if (outputs[i].length && !result) {
expect(result).toBeTruthy()
} else if (result) {
expect(result.length).toBe(outputs[i].length)
for (let j = 0; j < outputs[i].length; j++) {
expect(result[j].type).toEqual(outputs[i][j].type)
if (outputs[i][j].noScheme) {
expect(result[j].value).toEqual(`https://${outputs[i][j].value}`)
} else {
expect(result[j].value).toEqual(outputs[i][j].value)
}
if (outputs[i]?.[j].type === 'mention') {
expect(
input.slice(result[j].index.start, result[j].index.end),
).toBe(`@${result[j].value}`)
} else {
if (!outputs[i]?.[j].noScheme) {
expect(
input.slice(result[j].index.start, result[j].index.end),
).toBe(result[j].value)
} else {
expect(
input.slice(result[j].index.start, result[j].index.end),
).toBe(result[j].value.slice('https://'.length))
}
}
}
}
}
})
})
describe('detectLinkables', () => {
const inputs = [
'no linkable',
'@start middle end',
'start @middle end',
'start middle @end',
'@start @middle @end',
'@full123.test-of-chars',
'not@right',
'@bad!@#$chars',
'@newline1\n@newline2',
'parenthetical (@handle)',
'start https://middle.com end',
'start https://middle.com/foo/bar end',
'start https://middle.com/foo/bar?baz=bux end',
'start https://middle.com/foo/bar?baz=bux#hash end',
'https://start.com/foo/bar?baz=bux#hash middle end',
'start middle https://end.com/foo/bar?baz=bux#hash',
'https://newline1.com\nhttps://newline2.com',
'start middle.com end',
'start middle.com/foo/bar end',
'start middle.com/foo/bar?baz=bux end',
'start middle.com/foo/bar?baz=bux#hash end',
'start.com/foo/bar?baz=bux#hash middle end',
'start middle end.com/foo/bar?baz=bux#hash',
'newline1.com\nnewline2.com',
'not.. a..url ..here',
'e.g.',
'e.g. real.com fake.notreal',
'something-cool.jpg',
'website.com.jpg',
'e.g./foo',
'website.com.jpg/foo',
'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/',
'Classic article https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/ ',
'https://foo.com https://bar.com/whatever https://baz.com',
'punctuation https://foo.com, https://bar.com/whatever; https://baz.com.',
'parenthentical (https://foo.com)',
'except for https://foo.com/thing_(cool)',
]
const outputs = [
['no linkable'],
[{link: '@start'}, ' middle end'],
['start ', {link: '@middle'}, ' end'],
['start middle ', {link: '@end'}],
[{link: '@start'}, ' ', {link: '@middle'}, ' ', {link: '@end'}],
[{link: '@full123.test-of-chars'}],
['not@right'],
[{link: '@bad'}, '!@#$chars'],
[{link: '@newline1'}, '\n', {link: '@newline2'}],
['parenthetical (', {link: '@handle'}, ')'],
['start ', {link: 'https://middle.com'}, ' end'],
['start ', {link: 'https://middle.com/foo/bar'}, ' end'],
['start ', {link: 'https://middle.com/foo/bar?baz=bux'}, ' end'],
['start ', {link: 'https://middle.com/foo/bar?baz=bux#hash'}, ' end'],
[{link: 'https://start.com/foo/bar?baz=bux#hash'}, ' middle end'],
['start middle ', {link: 'https://end.com/foo/bar?baz=bux#hash'}],
[{link: 'https://newline1.com'}, '\n', {link: 'https://newline2.com'}],
['start ', {link: 'middle.com'}, ' end'],
['start ', {link: 'middle.com/foo/bar'}, ' end'],
['start ', {link: 'middle.com/foo/bar?baz=bux'}, ' end'],
['start ', {link: 'middle.com/foo/bar?baz=bux#hash'}, ' end'],
[{link: 'start.com/foo/bar?baz=bux#hash'}, ' middle end'],
['start middle ', {link: 'end.com/foo/bar?baz=bux#hash'}],
[{link: 'newline1.com'}, '\n', {link: 'newline2.com'}],
['not.. a..url ..here'],
['e.g.'],
['e.g. ', {link: 'real.com'}, ' fake.notreal'],
['something-cool.jpg'],
['website.com.jpg'],
['e.g./foo'],
['website.com.jpg/foo'],
[
'Classic article ',
{
link: 'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/',
},
],
[
'Classic article ',
{
link: 'https://socket3.wordpress.com/2018/02/03/designing-windows-95s-user-interface/',
},
' ',
],
[
{link: 'https://foo.com'},
' ',
{link: 'https://bar.com/whatever'},
' ',
{link: 'https://baz.com'},
],
[
'punctuation ',
{link: 'https://foo.com'},
', ',
{link: 'https://bar.com/whatever'},
'; ',
{link: 'https://baz.com'},
'.',
],
['parenthentical (', {link: 'https://foo.com'}, ')'],
['except for ', {link: 'https://foo.com/thing_(cool)'}],
]
it('correctly handles a set of text inputs', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const output = detectLinkables(input)
expect(output).toEqual(outputs[i])
}
})
})
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'],
]
const outputs = ['at://alice.test/app.bsky.feed.post/3jk7x4irgv52r']
it('correctly builds a record URI', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const result = makeRecordUri(...input)
expect(result).toEqual(outputs[i])
}
})
})
describe('ago', () => {
const inputs = [
1671461038,
'04 Dec 1995 00:12:00 GMT',
new Date(),
new Date().setMinutes(new Date().getMinutes() - 10),
new Date().setHours(new Date().getHours() - 1),
new Date().setDate(new Date().getDate() - 1),
new Date().setMonth(new Date().getMonth() - 1),
]
const outputs = [
new Date(1671461038).toLocaleDateString(),
new Date('04 Dec 1995 00:12:00 GMT').toLocaleDateString(),
'0s',
'10m',
'1h',
'1d',
'1mo',
]
it('correctly calculates how much time passed, in a string', () => {
for (let i = 0; i < inputs.length; i++) {
const result = ago(inputs[i])
expect(result).toEqual(outputs[i])
}
})
})
describe('makeValidHandle', () => {
const inputs = [
'test-handle-123',
'test!"#$%&/()=?_',
'this-handle-should-be-too-big',
]
const outputs = ['test-handle-123', 'test', 'this-handle-should-b']
it('correctly parses and corrects handles', () => {
for (let i = 0; i < inputs.length; i++) {
const result = makeValidHandle(inputs[i])
expect(result).toEqual(outputs[i])
}
})
})
describe('createFullHandle', () => {
const inputs: [string, string][] = [
['test-handle-123', 'test'],
['.test.handle', 'test.test.'],
['test.handle.', '.test.test'],
]
const outputs = [
'test-handle-123.test',
'.test.handle.test.test.',
'test.handle.test.test',
]
it('correctly parses and corrects handles', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const result = createFullHandle(...input)
expect(result).toEqual(outputs[i])
}
})
})
describe('enforceLen', () => {
const inputs: [string, number][] = [
['Hello World!', 5],
['Hello World!', 20],
['', 5],
]
const outputs = ['Hello', 'Hello World!', '']
it('correctly enforces defined length on a given string', () => {
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i]
const result = enforceLen(...input)
expect(result).toEqual(outputs[i])
}
})
})
describe('cleanError', () => {
const inputs = [
'TypeError: Network request failed',
'Error: Aborted',
'Error: TypeError "x" is not a function',
'Error: SyntaxError unexpected token "export"',
'Some other error',
]
const outputs = [
'Unable to connect. Please check your internet connection and try again.',
'Unable to connect. Please check your internet connection and try again.',
'TypeError "x" is not a function',
'SyntaxError unexpected token "export"',
'Some other error',
]
it('removes extra content from error message', () => {
for (let i = 0; i < inputs.length; i++) {
const result = cleanError(inputs[i])
expect(result).toEqual(outputs[i])
}
})
})
describe('toNiceDomain', () => {
const inputs = [
'https://example.com/index.html',
'https://bsky.app',
'https://bsky.social',
'#123123123',
]
const outputs = ['example.com', 'bsky.app', 'Bluesky Social', '#123123123']
it("displays the url's host in a easily readable manner", () => {
for (let i = 0; i < inputs.length; i++) {
const result = toNiceDomain(inputs[i])
expect(result).toEqual(outputs[i])
}
})
})
describe('toShortUrl', () => {
const inputs = [
'https://bsky.app',
'https://bsky.app/3jk7x4irgv52r',
'https://bsky.app/3jk7x4irgv52r2313y182h9',
]
const outputs = [
'bsky.app',
'bsky.app/3jk7x4irgv52r',
'bsky.app/3jk7x4irgv52r2313y...',
]
it('shortens the url', () => {
for (let i = 0; i < inputs.length; i++) {
const result = toShortUrl(inputs[i])
expect(result).toEqual(outputs[i])
}
})
})
describe('toShareUrl', () => {
const inputs = ['https://bsky.app', '/3jk7x4irgv52r', 'item/test/123']
const outputs = [
'https://bsky.app',
'https://bsky.app/3jk7x4irgv52r',
'https://bsky.app/item/test/123',
]
it('appends https, when not present', () => {
for (let i = 0; i < inputs.length; i++) {
const result = toShareUrl(inputs[i])
expect(result).toEqual(outputs[i])
}
})
})
describe('getYoutubeVideoId', () => {
it(' should return undefined for invalid youtube links', () => {
expect(getYoutubeVideoId('')).toBeUndefined()
expect(getYoutubeVideoId('https://www.google.com')).toBeUndefined()
expect(getYoutubeVideoId('https://www.youtube.com')).toBeUndefined()
expect(
getYoutubeVideoId('https://www.youtube.com/channelName'),
).toBeUndefined()
expect(
getYoutubeVideoId('https://www.youtube.com/channel/channelName'),
).toBeUndefined()
})
it('getYoutubeVideoId should return video id for valid youtube links', () => {
expect(getYoutubeVideoId('https://www.youtube.com/watch?v=videoId')).toBe(
'videoId',
)
expect(
getYoutubeVideoId(
'https://www.youtube.com/watch?v=videoId&feature=share',
),
).toBe('videoId')
expect(getYoutubeVideoId('https://youtu.be/videoId')).toBe('videoId')
})
})
@@ -0,0 +1,84 @@
import {
getMentionAt,
insertMentionAt,
} from '../../../src/lib/strings/mention-manip'
describe('getMentionAt', () => {
type Case = [string, number, string | undefined]
const cases: Case[] = [
['hello @alice goodbye', 0, undefined],
['hello @alice goodbye', 1, undefined],
['hello @alice goodbye', 2, undefined],
['hello @alice goodbye', 3, undefined],
['hello @alice goodbye', 4, undefined],
['hello @alice goodbye', 5, undefined],
['hello @alice goodbye', 6, 'alice'],
['hello @alice goodbye', 7, 'alice'],
['hello @alice goodbye', 8, 'alice'],
['hello @alice goodbye', 9, 'alice'],
['hello @alice goodbye', 10, 'alice'],
['hello @alice goodbye', 11, 'alice'],
['hello @alice goodbye', 12, 'alice'],
['hello @alice goodbye', 13, undefined],
['hello @alice goodbye', 14, undefined],
['@alice', 0, 'alice'],
['@alice hello', 0, 'alice'],
['@alice hello', 1, 'alice'],
['@alice hello', 2, 'alice'],
['@alice hello', 3, 'alice'],
['@alice hello', 4, 'alice'],
['@alice hello', 5, 'alice'],
['@alice hello', 6, 'alice'],
['@alice hello', 7, undefined],
['alice@alice', 0, undefined],
['alice@alice', 6, undefined],
]
it.each(cases)(
'given input string %p and cursor position %p, returns %p',
(str, cursorPos, expected) => {
const output = getMentionAt(str, cursorPos)
expect(output?.value).toEqual(expected)
},
)
})
describe('insertMentionAt', () => {
type Case = [string, number, string]
const cases: Case[] = [
['hello @alice goodbye', 0, 'hello @alice goodbye'],
['hello @alice goodbye', 1, 'hello @alice goodbye'],
['hello @alice goodbye', 2, 'hello @alice goodbye'],
['hello @alice goodbye', 3, 'hello @alice goodbye'],
['hello @alice goodbye', 4, 'hello @alice goodbye'],
['hello @alice goodbye', 5, 'hello @alice goodbye'],
['hello @alice goodbye', 6, 'hello @alice.com goodbye'],
['hello @alice goodbye', 7, 'hello @alice.com goodbye'],
['hello @alice goodbye', 8, 'hello @alice.com goodbye'],
['hello @alice goodbye', 9, 'hello @alice.com goodbye'],
['hello @alice goodbye', 10, 'hello @alice.com goodbye'],
['hello @alice goodbye', 11, 'hello @alice.com goodbye'],
['hello @alice goodbye', 12, 'hello @alice.com goodbye'],
['hello @alice goodbye', 13, 'hello @alice goodbye'],
['hello @alice goodbye', 14, 'hello @alice goodbye'],
['@alice', 0, '@alice.com '],
['@alice hello', 0, '@alice.com hello'],
['@alice hello', 1, '@alice.com hello'],
['@alice hello', 2, '@alice.com hello'],
['@alice hello', 3, '@alice.com hello'],
['@alice hello', 4, '@alice.com hello'],
['@alice hello', 5, '@alice.com hello'],
['@alice hello', 6, '@alice.com hello'],
['@alice hello', 7, '@alice hello'],
['alice@alice', 0, 'alice@alice'],
['alice@alice', 6, 'alice@alice'],
]
it.each(cases)(
'given input string %p and cursor position %p, returns %p',
(str, cursorPos, expected) => {
const output = insertMentionAt(str, cursorPos, 'alice.com')
expect(output).toEqual(expected)
},
)
})
+123
View File
@@ -0,0 +1,123 @@
import {AppBskyFeedPost} from '@atproto/api'
type Entity = AppBskyFeedPost.Entity
import {RichText} from '../../../src/lib/strings/rich-text'
import {removeExcessNewlines} from '../../../src/lib/strings/rich-text-sanitize'
describe('removeExcessNewlines', () => {
it('removes more than two consecutive new lines', () => {
const input = new RichText(
'test\n\n\n\n\ntest\n\n\n\n\n\n\ntest\n\n\n\n\n\n\ntest\n\n\n\n\n\n\ntest',
)
const output = removeExcessNewlines(input)
expect(output.text).toEqual('test\n\ntest\n\ntest\n\ntest\n\ntest')
})
it('removes more than two consecutive new lines with spaces', () => {
const input = new RichText(
'test\n\n\n\n\ntest\n \n \n \n \n\n\ntest\n\n\n\n\n\n\ntest\n\n\n\n\n \n\ntest',
)
const output = removeExcessNewlines(input)
expect(output.text).toEqual('test\n\ntest\n\ntest\n\ntest\n\ntest')
})
it('returns original string if there are no consecutive new lines', () => {
const input = new RichText('test\n\ntest\n\ntest\n\ntest\n\ntest')
const output = removeExcessNewlines(input)
expect(output.text).toEqual(input.text)
})
it('returns original string if there are no new lines', () => {
const input = new RichText('test test test test test')
const output = removeExcessNewlines(input)
expect(output.text).toEqual(input.text)
})
it('returns empty string if input is empty', () => {
const input = new RichText('')
const output = removeExcessNewlines(input)
expect(output.text).toEqual('')
})
it('works with different types of new line characters', () => {
const input = new RichText(
'test\r\ntest\n\rtest\rtest\n\n\n\ntest\n\r \n \n \n \n\n\ntest',
)
const output = removeExcessNewlines(input)
expect(output.text).toEqual('test\r\ntest\n\rtest\rtest\n\ntest\n\ntest')
})
it('removes more than two consecutive new lines with zero width space', () => {
const input = new RichText(
'test\n\n\n\n\ntest\n\u200B\u200B\n\n\n\ntest\n \u200B\u200B \n\n\n\ntest\n\n\n\n\n\n\ntest',
)
const output = removeExcessNewlines(input)
expect(output.text).toEqual('test\n\ntest\n\ntest\n\ntest\n\ntest')
})
it('removes more than two consecutive new lines with zero width non-joiner', () => {
const input = new RichText(
'test\n\n\n\n\ntest\n\u200C\u200C\n\n\n\ntest\n \u200C\u200C \n\n\n\ntest\n\n\n\n\n\n\ntest',
)
const output = removeExcessNewlines(input)
expect(output.text).toEqual('test\n\ntest\n\ntest\n\ntest\n\ntest')
})
it('removes more than two consecutive new lines with zero width joiner', () => {
const input = new RichText(
'test\n\n\n\n\ntest\n\u200D\u200D\n\n\n\ntest\n \u200D\u200D \n\n\n\ntest\n\n\n\n\n\n\ntest',
)
const output = removeExcessNewlines(input)
expect(output.text).toEqual('test\n\ntest\n\ntest\n\ntest\n\ntest')
})
it('removes more than two consecutive new lines with soft hyphen', () => {
const input = new RichText(
'test\n\n\n\n\ntest\n\u00AD\u00AD\n\n\n\ntest\n \u00AD\u00AD \n\n\n\ntest\n\n\n\n\n\n\ntest',
)
const output = removeExcessNewlines(input)
expect(output.text).toEqual('test\n\ntest\n\ntest\n\ntest\n\ntest')
})
it('removes more than two consecutive new lines with word joiner', () => {
const input = new RichText(
'test\n\n\n\n\ntest\n\u2060\u2060\n\n\n\ntest\n \u2060\u2060 \n\n\n\ntest\n\n\n\n\n\n\ntest',
)
const output = removeExcessNewlines(input)
expect(output.text).toEqual('test\n\ntest\n\ntest\n\ntest\n\ntest')
})
})
describe('removeExcessNewlines w/entities', () => {
it('preserves entities as expected', () => {
const input = new RichText(
'test\n\n\n\n\ntest\n\n\n\n\n\n\ntest\n\n\n\n\n\n\ntest\n\n\n\n\n\n\ntest',
[
{index: {start: 0, end: 13}, type: '', value: ''},
{index: {start: 13, end: 24}, type: '', value: ''},
{index: {start: 9, end: 15}, type: '', value: ''},
{index: {start: 4, end: 9}, type: '', value: ''},
],
)
const output = removeExcessNewlines(input)
expect(entToStr(input.text, input.entities?.[0])).toEqual(
'test\n\n\n\n\ntest',
)
expect(entToStr(input.text, input.entities?.[1])).toEqual(
'\n\n\n\n\n\n\ntest',
)
expect(entToStr(input.text, input.entities?.[2])).toEqual('test\n\n')
expect(entToStr(input.text, input.entities?.[3])).toEqual('\n\n\n\n\n')
expect(output.text).toEqual('test\n\ntest\n\ntest\n\ntest\n\ntest')
expect(entToStr(output.text, output.entities?.[0])).toEqual('test\n\ntest')
expect(entToStr(output.text, output.entities?.[1])).toEqual('test')
expect(entToStr(output.text, output.entities?.[2])).toEqual('test')
expect(output.entities?.[3]).toEqual(undefined)
})
})
function entToStr(str: string, ent?: Entity) {
if (!ent) {
return ''
}
return str.slice(ent.index.start, ent.index.end)
}
+123
View File
@@ -0,0 +1,123 @@
import {RichText} from '../../../src/lib/strings/rich-text'
describe('richText.insert', () => {
const input = new RichText('hello world', [
{index: {start: 2, end: 7}, type: '', value: ''},
])
it('correctly adjusts entities (scenario A - before)', () => {
const output = input.clone().insert(0, 'test')
expect(output.text).toEqual('testhello world')
expect(output.entities?.[0].index.start).toEqual(6)
expect(output.entities?.[0].index.end).toEqual(11)
expect(
output.text.slice(
output.entities?.[0].index.start,
output.entities?.[0].index.end,
),
).toEqual('llo w')
})
it('correctly adjusts entities (scenario B - inner)', () => {
const output = input.clone().insert(4, 'test')
expect(output.text).toEqual('helltesto world')
expect(output.entities?.[0].index.start).toEqual(2)
expect(output.entities?.[0].index.end).toEqual(11)
expect(
output.text.slice(
output.entities?.[0].index.start,
output.entities?.[0].index.end,
),
).toEqual('lltesto w')
})
it('correctly adjusts entities (scenario C - after)', () => {
const output = input.clone().insert(8, 'test')
expect(output.text).toEqual('hello wotestrld')
expect(output.entities?.[0].index.start).toEqual(2)
expect(output.entities?.[0].index.end).toEqual(7)
expect(
output.text.slice(
output.entities?.[0].index.start,
output.entities?.[0].index.end,
),
).toEqual('llo w')
})
})
describe('richText.delete', () => {
const input = new RichText('hello world', [
{index: {start: 2, end: 7}, type: '', value: ''},
])
it('correctly adjusts entities (scenario A - entirely outer)', () => {
const output = input.clone().delete(0, 9)
expect(output.text).toEqual('ld')
expect(output.entities?.length).toEqual(0)
})
it('correctly adjusts entities (scenario B - entirely after)', () => {
const output = input.clone().delete(7, 11)
expect(output.text).toEqual('hello w')
expect(output.entities?.[0].index.start).toEqual(2)
expect(output.entities?.[0].index.end).toEqual(7)
expect(
output.text.slice(
output.entities?.[0].index.start,
output.entities?.[0].index.end,
),
).toEqual('llo w')
})
it('correctly adjusts entities (scenario C - partially after)', () => {
const output = input.clone().delete(4, 11)
expect(output.text).toEqual('hell')
expect(output.entities?.[0].index.start).toEqual(2)
expect(output.entities?.[0].index.end).toEqual(4)
expect(
output.text.slice(
output.entities?.[0].index.start,
output.entities?.[0].index.end,
),
).toEqual('ll')
})
it('correctly adjusts entities (scenario D - entirely inner)', () => {
const output = input.clone().delete(3, 5)
expect(output.text).toEqual('hel world')
expect(output.entities?.[0].index.start).toEqual(2)
expect(output.entities?.[0].index.end).toEqual(5)
expect(
output.text.slice(
output.entities?.[0].index.start,
output.entities?.[0].index.end,
),
).toEqual('l w')
})
it('correctly adjusts entities (scenario E - partially before)', () => {
const output = input.clone().delete(1, 5)
expect(output.text).toEqual('h world')
expect(output.entities?.[0].index.start).toEqual(1)
expect(output.entities?.[0].index.end).toEqual(3)
expect(
output.text.slice(
output.entities?.[0].index.start,
output.entities?.[0].index.end,
),
).toEqual(' w')
})
it('correctly adjusts entities (scenario F - entirely before)', () => {
const output = input.clone().delete(0, 2)
expect(output.text).toEqual('llo world')
expect(output.entities?.[0].index.start).toEqual(0)
expect(output.entities?.[0].index.end).toEqual(5)
expect(
output.text.slice(
output.entities?.[0].index.start,
output.entities?.[0].index.end,
),
).toEqual('llo w')
})
})
+157
View File
@@ -0,0 +1,157 @@
import {RootStoreModel} from './../../../src/state/models/root-store'
import {NavigationModel} from './../../../src/state/models/navigation'
import * as flags from '../../../src/lib/build-flags'
import AtpAgent from '@atproto/api'
import {DEFAULT_SERVICE} from '../../../src/state'
describe('NavigationModel', () => {
let model: NavigationModel
let rootStore: RootStoreModel
beforeEach(() => {
rootStore = new RootStoreModel(new AtpAgent({service: DEFAULT_SERVICE}))
model = new NavigationModel(rootStore)
model.setTitle('0-0', 'title')
})
afterAll(() => {
jest.clearAllMocks()
})
it('should clear() to the correct base state', async () => {
await model.clear()
expect(model.tabCount).toBe(3)
expect(model.tab).toEqual({
fixedTabPurpose: 0,
history: [
{
id: expect.anything(),
ts: expect.anything(),
url: '/',
},
],
id: expect.anything(),
index: 0,
isNewTab: false,
})
})
it('should call the navigate method', async () => {
const navigateSpy = jest.spyOn(model.tab, 'navigate')
await model.navigate('testurl', 'teststring')
expect(navigateSpy).toHaveBeenCalledWith('testurl', 'teststring')
})
it('should call the refresh method', async () => {
const refreshSpy = jest.spyOn(model.tab, 'refresh')
await model.refresh()
expect(refreshSpy).toHaveBeenCalled()
})
it('should call the isCurrentScreen method', () => {
expect(model.isCurrentScreen('11', 0)).toEqual(false)
})
it('should call the tab getter', () => {
expect(model.tab).toEqual({
fixedTabPurpose: 0,
history: [
{
id: expect.anything(),
ts: expect.anything(),
url: '/',
},
],
id: expect.anything(),
index: 0,
isNewTab: false,
})
})
it('should call the tabCount getter', () => {
expect(model.tabCount).toBe(3)
})
describe('tabs not enabled', () => {
jest.mock('../../../src/lib/build-flags', () => ({
TABS_ENABLED: false,
}))
afterAll(() => {
jest.clearAllMocks()
})
it('should not create new tabs', () => {
// @ts-expect-error
flags.TABS_ENABLED = false
model.newTab('testurl')
expect(model.tab.isNewTab).toBe(false)
expect(model.tabIndex).toBe(0)
})
it('should not change the active tab', () => {
// @ts-expect-error
flags.TABS_ENABLED = false
model.setActiveTab(3)
expect(model.tabIndex).toBe(0)
})
it('should note close tabs', () => {
// @ts-expect-error
flags.TABS_ENABLED = false
model.closeTab(0)
expect(model.tabCount).toBe(3)
})
})
// TODO restore when tabs get re-enabled
// describe('tabs enabled', () => {
// jest.mock('../../../src/build-flags', () => ({
// TABS_ENABLED: true,
// }))
// afterAll(() => {
// jest.clearAllMocks()
// })
// it('should create new tabs', () => {
// // @ts-expect-error
// flags.TABS_ENABLED = true
// model.newTab('testurl', 'title')
// expect(model.tab.isNewTab).toBe(true)
// expect(model.tabIndex).toBe(2)
// })
// it('should change the current tab', () => {
// // @ts-expect-error
// flags.TABS_ENABLED = true
// model.setActiveTab(0)
// expect(model.tabIndex).toBe(0)
// })
// it('should close tabs', () => {
// // @ts-expect-error
// flags.TABS_ENABLED = true
// model.closeTab(0)
// expect(model.tabs).toEqual([
// {
// fixedTabPurpose: 1,
// history: [
// {
// id: expect.anything(),
// ts: expect.anything(),
// url: '/notifications',
// },
// ],
// id: expect.anything(),
// index: 0,
// isNewTab: false,
// },
// ])
// expect(model.tabIndex).toBe(0)
// })
// })
})
-55
View File
@@ -1,55 +0,0 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
lib_deps = []
create_aar_targets(glob(["libs/*.aar"]))
create_jar_targets(glob(["libs/*.jar"]))
android_library(
name = "all-libs",
exported_deps = lib_deps,
)
android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)
android_build_config(
name = "build_config",
package = "xyz.blueskyweb.pubsq",
)
android_resource(
name = "res",
package = "xyz.blueskyweb.pubsq",
res = "src/main/res",
)
android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)
+131 -215
View File
@@ -1,128 +1,107 @@
apply plugin: "com.android.application"
apply plugin: "com.facebook.react"
import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
def expoDebuggableVariants = ['debug']
// Override `debuggableVariants` for expo-updates debugging
if (System.getenv('EX_UPDATES_NATIVE_DEBUG') == "1") {
react {
expoDebuggableVariants = []
}
}
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation. If none specified and
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
* // default. Can be overridden with ENTRY_FILE environment variable.
* entryFile: "index.android.js",
*
* // https://reactnative.dev/docs/performance#enable-the-ram-format
* bundleCommand: "ram-bundle",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
* This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need.
*/
react {
entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
debuggableVariants = expoDebuggableVariants
project.ext.react = [
enableHermes: false, // clean and rebuild if changing
]
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..'
// root = file("../")
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
// reactNativeDir = file("../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
// codegenDir = file("../node_modules/react-native-codegen")
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
// cliFile = file("../node_modules/react-native/cli.js")
apply from: "../../node_modules/react-native/react.gradle"
/* Variants */
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
// debuggableVariants = ["liteDebug", "prodDebug"]
/* Bundling */
// A list containing the node command and its flags. Default is just 'node'.
// nodeExecutableAndArgs = ["node"]
//
// The command to run when bundling. By default is 'bundle'
// bundleCommand = "ram-bundle"
//
// The path to the CLI configuration file. Default is empty.
// bundleConfig = file(../rn-cli.config.js)
//
// The name of the generated asset file containing your JS bundle
// bundleAssetName = "MyApplication.android.bundle"
//
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
// entryFile = file("../js/MyApplication.android.js")
//
// A list of extra flags to pass to the 'bundle' commands.
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
// extraPackagerArgs = []
/* Hermes Commands */
// The hermes compiler command to run. By default it is 'hermesc'
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]
}
// Override `hermesEnabled` by `expo.jsEngine`
ext {
hermesEnabled = (findProperty('expo.jsEngine') ?: "hermes") == "hermes"
}
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
* Set this to true to create four separate APKs instead of one,
* one for each native architecture. This is useful if you don't
* use App Bundles (https://developer.android.com/guide/app-bundle/)
* and want to have separate APKs to upload to the Play Store.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
*/
def enableProguardInReleaseBuilds = false
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
/**
* The preferred build flavor of JavaScriptCore.
* The preferred build flavor of JavaScriptCore (JSC)
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Whether to enable the Hermes VM.
*
* This should be set on project.ext.react and that value will be read here. If it is not set
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced.
*/
def enableHermes = project.ext.react.get("enableHermes", false);
/**
* Architectures to build native code for.
* Private function to get the list of Native Architectures you want to build.
* This reads the value from reactNativeArchitectures in your gradle.properties
* file and works together with the --active-arch-only flag of react-native run-android.
*/
def reactNativeArchitectures() {
def value = project.getProperties().get("reactNativeArchitectures")
@@ -134,84 +113,13 @@ android {
compileSdkVersion rootProject.ext.compileSdkVersion
namespace 'xyz.blueskyweb.app'
defaultConfig {
applicationId "xyz.blueskyweb.pubsq"
applicationId 'xyz.blueskyweb.app'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) {
// We configure the NDK build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
ndkBuild {
arguments "APP_PLATFORM=android-21",
"APP_STL=c++_shared",
"NDK_TOOLCHAIN_VERSION=clang",
"GENERATED_SRC_DIR=$buildDir/generated/source",
"PROJECT_BUILD_DIR=$buildDir",
"REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
"REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build"
cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
cppFlags "-std=c++17"
// Make sure this target name is the same you specify inside the
// src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
targets "app_appmodules"
// Fix for windows limit on number of character in file paths and in command lines
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
arguments "NDK_APP_SHORT_COMMANDS=true"
}
}
}
if (!enableSeparateBuildPerCPUArchitecture) {
ndk {
abiFilters (*reactNativeArchitectures())
}
}
}
}
if (isNewArchitectureEnabled()) {
// We configure the NDK build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
ndkBuild {
path "$projectDir/src/main/jni/Android.mk"
}
}
def reactAndroidProjectDir = project(':ReactAndroid').projectDir
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
into("$buildDir/react-ndk/exported")
}
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
into("$buildDir/react-ndk/exported")
}
afterEvaluate {
// If you wish to add a custom TurboModule or component locally,
// you should uncomment this line.
// preBuild.dependsOn("generateCodegenArtifactsFromSchema")
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
// Due to a bug inside AGP, we have to explicitly set a dependency
// between configureNdkBuild* tasks and the preBuild tasks.
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
configureNdkBuildRelease.dependsOn(preReleaseBuild)
configureNdkBuildDebug.dependsOn(preDebugBuild)
reactNativeArchitectures().each { architecture ->
tasks.findByName("configureNdkBuildDebug[${architecture}]")?.configure {
dependsOn("preDebugBuild")
}
tasks.findByName("configureNdkBuildRelease[${architecture}]")?.configure {
dependsOn("preReleaseBuild")
}
}
}
versionName "1.0.0"
}
splits {
@@ -260,61 +168,69 @@ android {
}
}
// Apply static values from `gradle.properties` to the `android.packagingOptions`
// Accepts values in comma delimited lists, example:
// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini
["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop ->
// Split option: 'foo,bar' -> ['foo', 'bar']
def options = (findProperty("android.packagingOptions.$prop") ?: "").split(",");
// Trim all elements in place.
for (i in 0..<options.size()) options[i] = options[i].trim();
// `[] - ""` is essentially `[""].filter(Boolean)` removing all empty strings.
options -= ""
if (options.length > 0) {
println "android.packagingOptions.$prop += $options ($options.length)"
// Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'
options.each {
android.packagingOptions[prop] += it
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
def frescoVersion = rootProject.ext.frescoVersion
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
// If your app supports Android versions before Ice Cream Sandwich (API level 14)
if (isGifEnabled || isWebpEnabled) {
implementation("com.facebook.fresco:fresco:${frescoVersion}")
implementation("com.facebook.fresco:imagepipeline-okhttp3:${frescoVersion}")
}
if (isGifEnabled) {
// For animated gif support
implementation("com.facebook.fresco:animated-gif:${frescoVersion}")
}
if (isWebpEnabled) {
// For webp support
implementation("com.facebook.fresco:webpsupport:${frescoVersion}")
if (isWebpAnimatedEnabled) {
// Animated webp support
implementation("com.facebook.fresco:animated-webp:${frescoVersion}")
}
}
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
implementation jscFlavor
}
}
if (isNewArchitectureEnabled()) {
// If new architecture is enabled, we let you build RN from source
// Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
// This will be applied to all the imported transtitive dependency.
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute(module("com.facebook.react:react-native"))
.using(project(":ReactAndroid")).because("On New Architecture we're building React Native from source")
}
}
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.implementation
into 'libs'
}
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
def isNewArchitectureEnabled() {
// To opt-in for the New Architecture, you can either:
// - Set `newArchEnabled` to true inside the `gradle.properties` file
// - Invoke gradle with `-newArchEnabled=true`
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
applyNativeModulesAppBuildGradle(project)
-19
View File
@@ -1,19 +0,0 @@
"""Helper definitions to glob .aar and .jar targets"""
def create_aar_targets(aarfiles):
for aarfile in aarfiles:
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
lib_deps.append(":" + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
def create_jar_targets(jarfiles):
for jarfile in jarfiles:
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
lib_deps.append(":" + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)
+4
View File
@@ -8,3 +8,7 @@
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# react-native-reanimated
-keep class com.swmansion.reanimated.** { *; }
-keep class com.facebook.react.turbomodule.** { *; }
+1 -7
View File
@@ -1,13 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
</application>
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
</manifest>
@@ -4,7 +4,7 @@
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.app;
package xyz.blueskyweb.app;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
@@ -17,7 +17,6 @@ import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceEventListener;
import com.facebook.react.ReactInstanceManager;
@@ -25,13 +24,16 @@ import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
/**
* Class responsible of loading Flipper inside your React Native application. This is the debug
* flavor of it. Here you can add your own plugins and customize the Flipper setup.
*/
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new ReactFlipperPlugin());
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
+35 -44
View File
@@ -1,44 +1,35 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xyz.blueskyweb.pubsq">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- deep linking via web links -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- debug host: https://pubsq.pfrazee.com -->
<data android:scheme="https" />
<data android:host="pubsq.pfrazee.com" />
</intent-filter>
<!-- deep linking via custom links -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- debug scheme: pubsq://app -->
<data android:scheme="pubsq" />
<data android:host="app" />
</intent-filter>
</activity>
</application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="xyz.blueskyweb.app">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<queries>
<intent>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"/>
</intent>
</queries>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="48.0.0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@arrygoo/bluesky"/> <!-- TODO -->
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="xyz.blueskyweb.app"/>
<data android:scheme="exp+bluesky"/>
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false"/>
</application>
</manifest>
@@ -0,0 +1,68 @@
package xyz.blueskyweb.app;
import android.os.Build;
import android.os.Bundle;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactActivityDelegate;
import expo.modules.ReactActivityDelegateWrapper;
public class MainActivity extends ReactActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen.
setTheme(R.style.AppTheme);
super.onCreate(null);
}
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "main";
}
/**
* Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
* DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
* (aka React 18) with two boolean flags.
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, new DefaultReactActivityDelegate(
this,
getMainComponentName(),
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
));
}
/**
* Align the back button behavior with Android S
* where moving root activities to background instead of finishing activities.
* @see <a href="https://developer.android.com/reference/android/app/Activity#onBackPressed()">onBackPressed</a>
*/
@Override
public void invokeDefaultOnBackPressed() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
if (!moveTaskToBack(false)) {
// For non-root activities, use the default implementation to finish them.
super.invokeDefaultOnBackPressed();
}
return;
}
// Use the default back button implementation on Android S
// because it's doing more than {@link Activity#moveTaskToBack} in fact.
super.invokeDefaultOnBackPressed();
}
}
@@ -0,0 +1,76 @@
package xyz.blueskyweb.app;
import android.app.Application;
import android.content.res.Configuration;
import androidx.annotation.NonNull;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import expo.modules.ApplicationLifecycleDispatcher;
import expo.modules.ReactNativeHostWrapper;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHostWrapper(this, new DefaultReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@Override
protected boolean isNewArchEnabled() {
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}
@Override
protected Boolean isHermesEnabled() {
return BuildConfig.IS_HERMES_ENABLED;
}
});
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
DefaultNewArchitectureEntryPoint.load();
}
ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
ApplicationLifecycleDispatcher.onApplicationCreate(this);
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);
}
}
@@ -1,28 +0,0 @@
package xyz.blueskyweb.pubsq;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
import java.security.SecureRandom;
import android.util.Base64;
public class AppSecureRandomModule extends ReactContextBaseJavaModule {
public AppSecureRandomModule(ReactApplicationContext context) {
super(context);
}
@ReactMethod
public void generateSecureRandomAsBase64(int length, Promise promise) {
SecureRandom secureRandom = new SecureRandom();
byte[] buffer = new byte[length];
secureRandom.nextBytes(buffer);
promise.resolve(Base64.encodeToString(buffer, Base64.NO_WRAP));
}
@Override
public String getName() {
return "AppSecureRandomModule";
}
}
@@ -1,26 +0,0 @@
package xyz.blueskyweb.pubsq;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AppSecureRandomPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new AppSecureRandomModule(reactContext));
return modules;
}
}
@@ -1,46 +0,0 @@
package xyz.blueskyweb.pubsq;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import android.os.Bundle;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "xyz.blueskyweb.pubsq";
}
/**
* Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
* you can specify the rendered you wish to use (Fabric or the older renderer).
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new MainActivityDelegate(this, getMainComponentName());
}
public static class MainActivityDelegate extends ReactActivityDelegate {
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
super(activity, mainComponentName);
}
@Override
protected ReactRootView createRootView() {
ReactRootView reactRootView = new ReactRootView(getContext());
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
return reactRootView;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
}
}
}
@@ -1,92 +0,0 @@
package xyz.blueskyweb.pubsq;
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.soloader.SoLoader;
import xyz.blueskyweb.pubsq.newarchitecture.MainApplicationReactNativeHost;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new AppSecureRandomPackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
private final ReactNativeHost mNewArchitectureNativeHost =
new MainApplicationReactNativeHost(this);
@Override
public ReactNativeHost getReactNativeHost() {
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
return mNewArchitectureNativeHost;
} else {
return mReactNativeHost;
}
}
@Override
public void onCreate() {
super.onCreate();
// If you opted-in for the New Architecture, we enable the TurboModule system
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.app.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
@@ -1,116 +0,0 @@
package xyz.blueskyweb.pubsq.newarchitecture;
import android.app.Application;
import androidx.annotation.NonNull;
import com.facebook.react.PackageList;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
import com.facebook.react.bridge.JSIModulePackage;
import com.facebook.react.bridge.JSIModuleProvider;
import com.facebook.react.bridge.JSIModuleSpec;
import com.facebook.react.bridge.JSIModuleType;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.react.fabric.CoreComponentsRegistry;
import com.facebook.react.fabric.EmptyReactNativeConfig;
import com.facebook.react.fabric.FabricJSIModuleProvider;
import com.facebook.react.uimanager.ViewManagerRegistry;
import xyz.blueskyweb.pubsq.BuildConfig;
import xyz.blueskyweb.pubsq.newarchitecture.components.MainComponentsRegistry;
import xyz.blueskyweb.pubsq.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
* TurboModule delegates and the Fabric Renderer.
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
public class MainApplicationReactNativeHost extends ReactNativeHost {
public MainApplicationReactNativeHost(Application application) {
super(application);
}
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
// TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
// packages.add(new TurboReactPackage() { ... });
// If you have custom Fabric Components, their ViewManagers should also be loaded here
// inside a ReactPackage.
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
@NonNull
@Override
protected ReactPackageTurboModuleManagerDelegate.Builder
getReactPackageTurboModuleManagerDelegateBuilder() {
// Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
// for the new architecture and to use TurboModules correctly.
return new MainApplicationTurboModuleManagerDelegate.Builder();
}
@Override
protected JSIModulePackage getJSIModulePackage() {
return new JSIModulePackage() {
@Override
public List<JSIModuleSpec> getJSIModules(
final ReactApplicationContext reactApplicationContext,
final JavaScriptContextHolder jsContext) {
final List<JSIModuleSpec> specs = new ArrayList<>();
// Here we provide a new JSIModuleSpec that will be responsible of providing the
// custom Fabric Components.
specs.add(
new JSIModuleSpec() {
@Override
public JSIModuleType getJSIModuleType() {
return JSIModuleType.UIManager;
}
@Override
public JSIModuleProvider<UIManager> getJSIModuleProvider() {
final ComponentFactory componentFactory = new ComponentFactory();
CoreComponentsRegistry.register(componentFactory);
// Here we register a Components Registry.
// The one that is generated with the template contains no components
// and just provides you the one from React Native core.
MainComponentsRegistry.register(componentFactory);
final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
ViewManagerRegistry viewManagerRegistry =
new ViewManagerRegistry(
reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
return new FabricJSIModuleProvider(
reactApplicationContext,
componentFactory,
new EmptyReactNativeConfig(),
viewManagerRegistry);
}
});
return specs;
}
};
}
}
@@ -1,36 +0,0 @@
package xyz.blueskyweb.pubsq.newarchitecture.components;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.soloader.SoLoader;
/**
* Class responsible to load the custom Fabric Components. This class has native methods and needs a
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
* folder for you).
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
@DoNotStrip
public class MainComponentsRegistry {
static {
SoLoader.loadLibrary("fabricjni");
}
@DoNotStrip private final HybridData mHybridData;
@DoNotStrip
private native HybridData initHybrid(ComponentFactory componentFactory);
@DoNotStrip
private MainComponentsRegistry(ComponentFactory componentFactory) {
mHybridData = initHybrid(componentFactory);
}
@DoNotStrip
public static MainComponentsRegistry register(ComponentFactory componentFactory) {
return new MainComponentsRegistry(componentFactory);
}
}
@@ -1,48 +0,0 @@
package xyz.blueskyweb.pubsq.newarchitecture.modules;
import com.facebook.jni.HybridData;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.soloader.SoLoader;
import java.util.List;
/**
* Class responsible to load the TurboModules. This class has native methods and needs a
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
* folder for you).
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
public class MainApplicationTurboModuleManagerDelegate
extends ReactPackageTurboModuleManagerDelegate {
private static volatile boolean sIsSoLibraryLoaded;
protected MainApplicationTurboModuleManagerDelegate(
ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {
super(reactApplicationContext, packages);
}
protected native HybridData initHybrid();
native boolean canCreateTurboModule(String moduleName);
public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
protected MainApplicationTurboModuleManagerDelegate build(
ReactApplicationContext context, List<ReactPackage> packages) {
return new MainApplicationTurboModuleManagerDelegate(context, packages);
}
}
@Override
protected synchronized void maybeLoadOtherSoLibraries() {
if (!sIsSoLibraryLoaded) {
// If you change the name of your application .so file in the Android.mk file,
// make sure you update the name here as well.
SoLoader.loadLibrary("app_appmodules");
sIsSoLibraryLoaded = true;
}
}
}
-49
View File
@@ -1,49 +0,0 @@
THIS_DIR := $(call my-dir)
include $(REACT_ANDROID_DIR)/Android-prebuilt.mk
# If you wish to add a custom TurboModule or Fabric component in your app you
# will have to include the following autogenerated makefile.
# include $(GENERATED_SRC_DIR)/codegen/jni/Android.mk
include $(CLEAR_VARS)
LOCAL_PATH := $(THIS_DIR)
# You can customize the name of your application .so file here.
LOCAL_MODULE := app_appmodules
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/*.cpp)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
# If you wish to add a custom TurboModule or Fabric component in your app you
# will have to uncomment those lines to include the generated source
# files from the codegen (placed in $(GENERATED_SRC_DIR)/codegen/jni)
#
# LOCAL_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
# LOCAL_SRC_FILES += $(wildcard $(GENERATED_SRC_DIR)/codegen/jni/*.cpp)
# LOCAL_EXPORT_C_INCLUDES += $(GENERATED_SRC_DIR)/codegen/jni
# Here you should add any native library you wish to depend on.
LOCAL_SHARED_LIBRARIES := \
libfabricjni \
libfbjni \
libfolly_futures \
libfolly_json \
libglog \
libjsi \
libreact_codegen_rncore \
libreact_debug \
libreact_nativemodule_core \
libreact_render_componentregistry \
libreact_render_core \
libreact_render_debug \
libreact_render_graphics \
librrc_view \
libruntimeexecutor \
libturbomodulejsijni \
libyoga
LOCAL_CFLAGS := -DLOG_TAG=\"ReactNative\" -fexceptions -frtti -std=c++17 -Wall
include $(BUILD_SHARED_LIBRARY)
@@ -1,24 +0,0 @@
#include "MainApplicationModuleProvider.h"
#include <rncore.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string moduleName,
const JavaTurboModule::InitParams &params) {
// Here you can provide your own module provider for TurboModules coming from
// either your application or from external libraries. The approach to follow
// is similar to the following (for a library called `samplelibrary`:
//
// auto module = samplelibrary_ModuleProvider(moduleName, params);
// if (module != nullptr) {
// return module;
// }
// return rncore_ModuleProvider(moduleName, params);
return rncore_ModuleProvider(moduleName, params);
}
} // namespace react
} // namespace facebook
@@ -1,16 +0,0 @@
#pragma once
#include <memory>
#include <string>
#include <ReactCommon/JavaTurboModule.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string moduleName,
const JavaTurboModule::InitParams &params);
} // namespace react
} // namespace facebook
@@ -1,45 +0,0 @@
#include "MainApplicationTurboModuleManagerDelegate.h"
#include "MainApplicationModuleProvider.h"
namespace facebook {
namespace react {
jni::local_ref<MainApplicationTurboModuleManagerDelegate::jhybriddata>
MainApplicationTurboModuleManagerDelegate::initHybrid(
jni::alias_ref<jhybridobject>) {
return makeCxxInstance();
}
void MainApplicationTurboModuleManagerDelegate::registerNatives() {
registerHybrid({
makeNativeMethod(
"initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid),
makeNativeMethod(
"canCreateTurboModule",
MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),
});
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string name,
const std::shared_ptr<CallInvoker> jsInvoker) {
// Not implemented yet: provide pure-C++ NativeModules here.
return nullptr;
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string name,
const JavaTurboModule::InitParams &params) {
return MainApplicationModuleProvider(name, params);
}
bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(
std::string name) {
return getTurboModule(name, nullptr) != nullptr ||
getTurboModule(name, {.moduleName = name}) != nullptr;
}
} // namespace react
} // namespace facebook
@@ -1,38 +0,0 @@
#include <memory>
#include <string>
#include <ReactCommon/TurboModuleManagerDelegate.h>
#include <fbjni/fbjni.h>
namespace facebook {
namespace react {
class MainApplicationTurboModuleManagerDelegate
: public jni::HybridClass<
MainApplicationTurboModuleManagerDelegate,
TurboModuleManagerDelegate> {
public:
// Adapt it to the package you used for your Java class.
static constexpr auto kJavaDescriptor =
"Lcom/app/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>);
static void registerNatives();
std::shared_ptr<TurboModule> getTurboModule(
const std::string name,
const std::shared_ptr<CallInvoker> jsInvoker) override;
std::shared_ptr<TurboModule> getTurboModule(
const std::string name,
const JavaTurboModule::InitParams &params) override;
/**
* Test-only method. Allows user to verify whether a TurboModule can be
* created by instances of this class.
*/
bool canCreateTurboModule(std::string name);
};
} // namespace react
} // namespace facebook
@@ -1,61 +0,0 @@
#include "MainComponentsRegistry.h"
#include <CoreComponentsRegistry.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/components/rncore/ComponentDescriptors.h>
namespace facebook {
namespace react {
MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
std::shared_ptr<ComponentDescriptorProviderRegistry const>
MainComponentsRegistry::sharedProviderRegistry() {
auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
// Custom Fabric Components go here. You can register custom
// components coming from your App or from 3rd party libraries here.
//
// providerRegistry->add(concreteComponentDescriptorProvider<
// AocViewerComponentDescriptor>());
return providerRegistry;
}
jni::local_ref<MainComponentsRegistry::jhybriddata>
MainComponentsRegistry::initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate) {
auto instance = makeCxxInstance(delegate);
auto buildRegistryFunction =
[](EventDispatcher::Weak const &eventDispatcher,
ContextContainer::Shared const &contextContainer)
-> ComponentDescriptorRegistry::Shared {
auto registry = MainComponentsRegistry::sharedProviderRegistry()
->createComponentDescriptorRegistry(
{eventDispatcher, contextContainer});
auto mutableRegistry =
std::const_pointer_cast<ComponentDescriptorRegistry>(registry);
mutableRegistry->setFallbackComponentDescriptor(
std::make_shared<UnimplementedNativeViewComponentDescriptor>(
ComponentDescriptorParameters{
eventDispatcher, contextContainer, nullptr}));
return registry;
};
delegate->buildRegistryFunction = buildRegistryFunction;
return instance;
}
void MainComponentsRegistry::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
});
}
} // namespace react
} // namespace facebook
@@ -1,32 +0,0 @@
#pragma once
#include <ComponentFactory.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
namespace facebook {
namespace react {
class MainComponentsRegistry
: public facebook::jni::HybridClass<MainComponentsRegistry> {
public:
// Adapt it to the package you used for your Java class.
constexpr static auto kJavaDescriptor =
"Lcom/app/newarchitecture/components/MainComponentsRegistry;";
static void registerNatives();
MainComponentsRegistry(ComponentFactory *delegate);
private:
static std::shared_ptr<ComponentDescriptorProviderRegistry const>
sharedProviderRegistry();
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate);
};
} // namespace react
} // namespace facebook
-11
View File
@@ -1,11 +0,0 @@
#include <fbjni/fbjni.h>
#include "MainApplicationTurboModuleManagerDelegate.h"
#include "MainComponentsRegistry.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] {
facebook::react::MainApplicationTurboModuleManagerDelegate::
registerNatives();
facebook::react::MainComponentsRegistry::registerNatives();
});
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

+1 -1
View File
@@ -1,3 +1,3 @@
<resources>
<string name="app_name">pubsq</string>
<string name="app_name">bsky</string>
</resources>
@@ -0,0 +1,18 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package xyz.blueskyweb.app;
import android.content.Context;
import com.facebook.react.ReactInstanceManager;
/**
* Class responsible of loading Flipper inside your React Native application. This is the release
* flavor of it so it's empty as we don't want to load Flipper.
*/
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
// Do nothing as we don't want to initialize Flipper on Release.
}
}
+16 -27
View File
@@ -1,32 +1,26 @@
import org.apache.tools.ant.taskdefs.condition.Os
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "31.0.0"
minSdkVersion = 21
compileSdkVersion = 31
targetSdkVersion = 31
if (System.properties['os.arch'] == "aarch64") {
// For M1 Users we need to use the NDK 24 which added support for aarch64
ndkVersion = "24.0.8215888"
} else {
// Otherwise we default to the side-by-side NDK version from AGP.
ndkVersion = "21.4.7075529"
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '33.0.0'
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21')
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '33')
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '33')
if (findProperty('android.kotlinVersion')) {
kotlinVersion = findProperty('android.kotlinVersion')
}
frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0'
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
ndkVersion = "23.1.7779620"
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath('com.android.tools.build:gradle:7.2.1')
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("de.undercouch:gradle-download-task:4.1.2")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath('com.android.tools.build:gradle:7.3.1')
classpath('com.facebook.react:react-native-gradle-plugin')
}
}
@@ -34,20 +28,15 @@ allprojects {
repositories {
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
mavenCentral {
// We don't want to fetch react-native from Maven Central as there are
// older versions over there.
content {
excludeGroup "com.facebook.react"
}
url(new File(['node', '--print', "require.resolve('jsc-android/package.json')"].execute(null, rootDir).text.trim(), '../dist'))
}
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }
}
}
+13
View File
@@ -21,6 +21,7 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
@@ -38,3 +39,15 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
newArchEnabled=false
# The hosted JavaScript engine
# Supported values: expo.jsEngine = "hermes" | "jsc"
expo.jsEngine=hermes
# Enable GIF support in React Native images (~200 B increase)
expo.gif.enabled=true
# Enable webp support in React Native images (~85 KB increase)
expo.webp.enabled=true
# Enable animated webp support (~3.4 MB increase)
# Disabled by default because iOS doesn't support animated webp
expo.webp.animated=false
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+6
View File
@@ -205,6 +205,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+8 -6
View File
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
+9 -8
View File
@@ -1,9 +1,10 @@
rootProject.name = 'app'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
includeBuild('../node_modules/react-native-gradle-plugin')
rootProject.name = 'bluesky'
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
include(":ReactAndroid")
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
}
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
useExpoModules()
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
applyNativeModulesSettingsGradle(settings)
include ':app'
includeBuild(new File(["node", "--print", "require.resolve('react-native-gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile())
+29
View File
@@ -0,0 +1,29 @@
{
"expo": {
"name": "bluesky",
"slug": "bluesky",
"version": "1.7.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": false,
"bundleIdentifier": "xyz.blueskyweb.app"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "xyz.blueskyweb.app"
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

+32 -17
View File
@@ -1,19 +1,34 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module:react-native-dotenv',
{
// envName: 'APP_ENV',
moduleName: '@env',
path: '.env',
blocklist: null,
allowlist: null,
safe: false,
allowUndefined: true,
verbose: false,
},
module.exports = function (api) {
api.cache(true)
return {
presets: ['babel-preset-expo'],
plugins: [
[
'module:react-native-dotenv',
{
envName: 'APP_ENV',
moduleName: '@env',
path: '.env',
blocklist: null,
allowlist: null,
safe: false,
allowUndefined: true,
verbose: false,
},
],
[
'module-resolver',
{
alias: {
// This needs to be mirrored in tsconfig.json
lib: './src/lib',
platform: './src/platform',
state: './src/state',
view: './src/view',
},
},
],
'react-native-reanimated/plugin', // NOTE: this plugin MUST be last
],
'react-native-reanimated/plugin', // NOTE: this plugin MUST be last
],
}
}
+12
View File
@@ -0,0 +1,12 @@
/** @type {import('@jest/types').Config.InitialOptions} */
module.exports = {
rootDir: '..',
testMatch: ['<rootDir>/e2e/**/*.test.js'],
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,
}
+70
View File
@@ -0,0 +1,70 @@
/* eslint-env detox/detox */
describe('Happy paths', () => {
async function grantAccessToUserWithValidCredentials(
username,
{takeScreenshots} = {takeScreenshots: false},
) {
await element(by.id('signInButton')).tap()
if (takeScreenshots) {
await device.takeScreenshot('1- opened sign-in screen')
}
await element(by.id('loginSelectServiceButton')).tap()
if (takeScreenshots) {
await device.takeScreenshot('2- opened service selector')
}
await element(by.id('localDevServerButton')).tap()
if (takeScreenshots) {
await device.takeScreenshot('3- selected local dev server')
}
await element(by.id('loginUsernameInput')).typeText(username)
await element(by.id('loginPasswordInput')).typeText('hunter2')
if (takeScreenshots) {
await device.takeScreenshot('4- entered username and password')
}
await element(by.id('loginNextButton')).tap()
}
beforeEach(async () => {
await device.uninstallApp()
await device.installApp()
await device.launchApp({permissions: {notifications: 'YES'}})
})
it('As Alice, I can login', async () => {
await expect(element(by.id('signInButton'))).toBeVisible()
await grantAccessToUserWithValidCredentials('alice', {
takeScreenshots: true,
})
await device.takeScreenshot('5- opened home screen')
})
it('As Alice, I can login, and post a text', async () => {
await grantAccessToUserWithValidCredentials('alice')
await element(by.id('composeFAB')).tap()
await device.takeScreenshot('1- opened composer')
await element(by.id('composerTextInput')).typeText(
'Greetings earthlings, I come in peace... and to run some tests.',
)
await device.takeScreenshot('2- entered text')
await element(by.id('composerPublishButton')).tap()
await device.takeScreenshot('3- opened general section')
await expect(element(by.id('composeFAB'))).toBeVisible()
})
it('I can create a new account', async () => {
await element(by.id('createAccountButton')).tap()
await device.takeScreenshot('1- opened create account screen')
await element(by.id('registerSelectServiceButton')).tap()
await device.takeScreenshot('2- opened service selector')
await element(by.id('localDevServerButton')).tap()
await device.takeScreenshot('3- selected local dev server')
await element(by.id('registerEmailInput')).typeText('example@test.com')
await element(by.id('registerPasswordInput')).typeText('hunter2')
await element(by.id('registerHandleInput')).typeText('e2e-test')
await element(by.id('registerIs13Input')).tap()
await device.takeScreenshot('4- entered account details')
await element(by.id('createAccountButton')).tap()
await expect(element(by.id('welcomeBanner'))).toBeVisible()
})
})
+14
View File
@@ -0,0 +1,14 @@
import 'react-native-gesture-handler' // must be first
import {LogBox} from 'react-native'
LogBox.ignoreLogs(['Require cycle:']) // suppress require-cycle warnings, it's fine
import 'platform/polyfills'
import {registerRootComponent} from 'expo'
import App from './src/App'
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App)
-9
View File
@@ -1,9 +0,0 @@
/**
* @format
*/
import {AppRegistry} from 'react-native'
import App from './src/App'
import {name as appName} from './src/app.json'
AppRegistry.registerComponent(appName, () => App)
+4
View File
@@ -0,0 +1,4 @@
import 'platform/polyfills'
import {registerRootComponent} from 'expo'
import App from './src/App'
registerRootComponent(App)
+10
View File
@@ -0,0 +1,10 @@
# This `.xcode.env` file is versioned and is used to source the environment
# used when running script phases inside Xcode.
# To customize your local environment, you can create an `.xcode.env.local`
# file that is not versioned.
# NODE_BINARY variable contains the PATH to the node executable.
#
# Customize the NODE_BINARY variable here.
# For example, to use nvm with brew, add the following line
# . "$(brew --prefix nvm)/nvm.sh" --no-use
export NODE_BINARY=$(command -v node)
+1
View File
@@ -0,0 +1 @@
export NODE_BINARY="/Users/paulfrazee/.nvm/versions/node/v18.8.0/bin/node"
-5
View File
@@ -1,5 +0,0 @@
#import <React/RCTBridgeModule.h>
@interface AppSecureRandomModule : NSObject <RCTBridgeModule>
@end
-27
View File
@@ -1,27 +0,0 @@
#import "AppSecureRandomModule.h"
@implementation AppSecureRandomModule
RCT_EXPORT_MODULE();
+ (BOOL)requiresMainQueueSetup
{
return NO;
}
RCT_REMAP_METHOD(generateSecureRandomAsBase64,
withLength:(int)length
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSMutableData* bytes = [NSMutableData dataWithLength:length];
int result = SecRandomCopyBytes(kSecRandomDefault,length, [bytes mutableBytes]);
if (result == errSecSuccess) {
resolve([bytes base64EncodedStringWithOptions:0]);
} else {
NSError *error = [NSError errorWithDomain:@"RNSecureRandom" code:result userInfo: nil];
reject(@"randombytes_error", @"Error generating random bytes", error);
}
}
@end
+72 -29
View File
@@ -1,48 +1,91 @@
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
require File.join(File.dirname(`node --print "require.resolve('@react-native-community/cli-platform-ios/package.json')"`), "native_modules")
platform :ios, '11.0'
install! 'cocoapods', :deterministic_uuids => false
require 'json'
podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
target 'app' do
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
ENV['RCT_NEW_ARCH_ENABLED'] = podfile_properties['newArchEnabled'] == 'true' ? '1' : '0'
platform :ios, podfile_properties['ios.deploymentTarget'] || '13.0'
install! 'cocoapods',
:deterministic_uuids => false
prepare_react_native_project!
# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
# because `react-native-flipper` depends on (FlipperKit,...), which will be excluded. To fix this,
# you can also exclude `react-native-flipper` in `react-native.config.js`
#
# ```js
# module.exports = {
# dependencies: {
# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
# }
# }
# ```
flipper_config = FlipperConfiguration.disabled
if ENV['NO_FLIPPER'] == "1" || ENV['CI'] then
# Explicitly disabled through environment variables
flipper_config = FlipperConfiguration.disabled
elsif podfile_properties.key?('ios.flipper') then
# Configure Flipper in Podfile.properties.json
if podfile_properties['ios.flipper'] == 'true' then
flipper_config = FlipperConfiguration.enabled(["Debug", "Release"])
elsif ppodfile_properties['ios.flipper'] != 'false' then
flipper_config = FlipperConfiguration.enabled(["Debug", "Release"], { 'Flipper' => podfile_properties['ios.flipper'] })
end
end
target 'bluesky' do
use_expo_modules!
config = use_native_modules!
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
# Flags change depending on the env values.
flags = get_default_flags()
use_react_native!(
:path => config[:reactNativePath],
# to enable hermes on iOS, change `false` to `true` and then install pods
:hermes_enabled => flags[:hermes_enabled],
:hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
:fabric_enabled => flags[:fabric_enabled],
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
:app_path => "#{Pod::Config.instance.installation_root}/..",
# Note that if you have use_frameworks! enabled, Flipper will not work if enabled
:flipper_configuration => flipper_config
)
target 'appTests' do
inherit! :complete
# Pods for testing
end
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable the next line.
#use_flipper!()
post_install do |installer|
react_native_post_install(installer)
react_native_post_install(
installer,
config[:reactNativePath],
# Set `mac_catalyst_enabled` to `true` in order to apply patches
# necessary for Mac Catalyst builds
:mac_catalyst_enabled => false
)
__apply_Xcode_12_5_M1_post_install_workaround(installer)
# iOS fix
installer.pods_project.build_configurations.each do |config|
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
end
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES'
# This is necessary for Xcode 14, because it signs resource bundles by default
# when building for devices.
installer.target_installation_results.pod_target_installation_results
.each do |pod_name, target_installation_result|
target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
resource_bundle_target.build_configurations.each do |config|
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
end
end
end
end
end
post_integrate do |installer|
begin
expo_patch_react_imports!(installer)
rescue => e
Pod::UI.warn e
end
end
end
+733 -328
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
{
"expo.jsEngine": "hermes"
}
-680
View File
@@ -1,680 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
00E356F31AD99517003FC87E /* appTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* appTests.m */; };
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
5CEAE7B7A55582F96F1D5952 /* libPods-app.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB672808307A6013805A3FE /* libPods-app.a */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
E4BD704B285AD57E00A8FED9 /* AppSecureRandomModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E4BD704A285AD57E00A8FED9 /* AppSecureRandomModule.m */; };
E4BD704C285AD57E00A8FED9 /* AppSecureRandomModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E4BD704A285AD57E00A8FED9 /* AppSecureRandomModule.m */; };
FEB90D21557517F9279AECA4 /* libPods-app-appTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BAD3BC60FA05CF2D4F6F9BA2 /* libPods-app-appTests.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = app;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
00E356EE1AD99517003FC87E /* appTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = appTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* appTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = appTests.m; sourceTree = "<group>"; };
03F7088487057F17D25D2F4B /* Pods-app-appTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-appTests.release.xcconfig"; path = "Target Support Files/Pods-app-appTests/Pods-app-appTests.release.xcconfig"; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = app.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = app/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = app/AppDelegate.mm; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = app/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = app/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = app/main.m; sourceTree = "<group>"; };
19C43486502F2DE23E091FE3 /* Pods-app-appTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-appTests.debug.xcconfig"; path = "Target Support Files/Pods-app-appTests/Pods-app-appTests.debug.xcconfig"; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = app/LaunchScreen.storyboard; sourceTree = "<group>"; };
970005155A83960D1D13380F /* Pods-app.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app.release.xcconfig"; path = "Target Support Files/Pods-app/Pods-app.release.xcconfig"; sourceTree = "<group>"; };
BAD3BC60FA05CF2D4F6F9BA2 /* libPods-app-appTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-app-appTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
E4437C9E28581FA7006DA9E7 /* app.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = app.entitlements; path = app/app.entitlements; sourceTree = "<group>"; };
E4BD7049285AD54000A8FED9 /* AppSecureRandomModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppSecureRandomModule.h; sourceTree = "<group>"; };
E4BD704A285AD57E00A8FED9 /* AppSecureRandomModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppSecureRandomModule.m; sourceTree = "<group>"; };
ED22CAA45207BC18E75DB44B /* Pods-app.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app.debug.xcconfig"; path = "Target Support Files/Pods-app/Pods-app.debug.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
FCB672808307A6013805A3FE /* libPods-app.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-app.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
00E356EB1AD99517003FC87E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
FEB90D21557517F9279AECA4 /* libPods-app-appTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5CEAE7B7A55582F96F1D5952 /* libPods-app.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
00E356EF1AD99517003FC87E /* appTests */ = {
isa = PBXGroup;
children = (
00E356F21AD99517003FC87E /* appTests.m */,
00E356F01AD99517003FC87E /* Supporting Files */,
);
path = appTests;
sourceTree = "<group>";
};
00E356F01AD99517003FC87E /* Supporting Files */ = {
isa = PBXGroup;
children = (
00E356F11AD99517003FC87E /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
13B07FAE1A68108700A75B9A /* app */ = {
isa = PBXGroup;
children = (
E4437C9E28581FA7006DA9E7 /* app.entitlements */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
13B07FB61A68108700A75B9A /* Info.plist */,
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
13B07FB71A68108700A75B9A /* main.m */,
E4BD7049285AD54000A8FED9 /* AppSecureRandomModule.h */,
E4BD704A285AD57E00A8FED9 /* AppSecureRandomModule.m */,
);
name = app;
sourceTree = "<group>";
};
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
FCB672808307A6013805A3FE /* libPods-app.a */,
BAD3BC60FA05CF2D4F6F9BA2 /* libPods-app-appTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
);
name = Libraries;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
13B07FAE1A68108700A75B9A /* app */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* appTests */,
83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */,
BBD78D7AC51CEA395F1C20DB /* Pods */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
usesTabs = 0;
};
83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* app.app */,
00E356EE1AD99517003FC87E /* appTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup;
children = (
ED22CAA45207BC18E75DB44B /* Pods-app.debug.xcconfig */,
970005155A83960D1D13380F /* Pods-app.release.xcconfig */,
19C43486502F2DE23E091FE3 /* Pods-app-appTests.debug.xcconfig */,
03F7088487057F17D25D2F4B /* Pods-app-appTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
00E356ED1AD99517003FC87E /* appTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "appTests" */;
buildPhases = (
F309585457BFF312EF73FD95 /* [CP] Check Pods Manifest.lock */,
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
2772CBCCE24036517E86445D /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
00E356F51AD99517003FC87E /* PBXTargetDependency */,
);
name = appTests;
productName = appTests;
productReference = 00E356EE1AD99517003FC87E /* appTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
13B07F861A680F5B00A75B9A /* app */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "app" */;
buildPhases = (
4D45C29570A58E7A8A8D177D /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
9CEFF2A5EA3D60C120442CA6 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = app;
productName = app;
productReference = 13B07F961A680F5B00A75B9A /* app.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1340;
TargetAttributes = {
00E356ED1AD99517003FC87E = {
CreatedOnToolsVersion = 6.2;
TestTargetID = 13B07F861A680F5B00A75B9A;
};
13B07F861A680F5B00A75B9A = {
LastSwiftMigration = 1120;
};
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */;
compatibilityVersion = "Xcode 12.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* app */,
00E356ED1AD99517003FC87E /* appTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
00E356EC1AD99517003FC87E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8E1A680F5B00A75B9A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Bundle React Native code and images";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
2772CBCCE24036517E86445D /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-app-appTests/Pods-app-appTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
4D45C29570A58E7A8A8D177D /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-app-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9CEFF2A5EA3D60C120442CA6 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-app/Pods-app-resources.sh\"\n";
showEnvVarsInLog = 0;
};
F309585457BFF312EF73FD95 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-app-appTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
FD10A7F022414F080027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Start Packager";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
00E356EA1AD99517003FC87E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
00E356F31AD99517003FC87E /* appTests.m in Sources */,
E4BD704C285AD57E00A8FED9 /* AppSecureRandomModule.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F871A680F5B00A75B9A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
E4BD704B285AD57E00A8FED9 /* AppSecureRandomModule.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 13B07F861A680F5B00A75B9A /* app */;
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 19C43486502F2DE23E091FE3 /* Pods-app-appTests.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = appTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
"$(inherited)",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/app.app/app";
};
name = Debug;
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 03F7088487057F17D25D2F4B /* Pods-app-appTests.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = appTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
"$(inherited)",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/app.app/app";
};
name = Release;
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = ED22CAA45207BC18E75DB44B /* Pods-app.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = app/app.entitlements;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = A6GRZHF6BV;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
INFOPLIST_FILE = app/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = xyz.blueskyweb.pubsq;
PRODUCT_NAME = app;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 970005155A83960D1D13380F /* Pods-app.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = app/app.entitlements;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = A6GRZHF6BV;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
INFOPLIST_FILE = app/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = xyz.blueskyweb.pubsq;
PRODUCT_NAME = app;
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
83CBBA201A601CBA00E9B192 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = (
"\"$(SDKROOT)/usr/lib/swift\"",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",
);
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
SDKROOT = iphoneos;
};
name = Debug;
};
83CBBA211A601CBA00E9B192 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = (
"\"$(SDKROOT)/usr/lib/swift\"",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",
);
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "appTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
00E356F61AD99517003FC87E /* Debug */,
00E356F71AD99517003FC87E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "app" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13B07F941A680F5B00A75B9A /* Debug */,
13B07F951A680F5B00A75B9A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "app" */ = {
isa = XCConfigurationList;
buildConfigurations = (
83CBBA201A601CBA00E9B192 /* Debug */,
83CBBA211A601CBA00E9B192 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
}
-8
View File
@@ -1,8 +0,0 @@
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
@property (nonatomic, strong) UIWindow *window;
@end
-126
View File
@@ -1,126 +0,0 @@
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTAppSetupUtils.h>
// universal links
#import <React/RCTLinkingManager.h>
#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"xyz.blueskyweb.pubsq", nil);
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}
#pragma mark RCTTurboModuleManagerDelegate
- (Class)getModuleClassFromName:(const char *)name
{
return RCTCoreModulesClassProvider(name);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
#endif
// universal links
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application
continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
}
@end
@@ -1,53 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
-68
View File
@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>PubSQ</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>xyz.blueskyweb.pubsq</string>
<key>CFBundleURLSchemes</key>
<array>
<string>pubsqapp</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

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