From ad7d49ef8f6f579a4bf265c99c4d27075b8c437f Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 12 Dec 2025 20:32:06 +0200 Subject: [PATCH] [Contacts] Contacts matching flow (#9486) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add expo-contacts * add expo-sms * update copy * add basic settings screen * state machine, flow screen * phone input screen * otp screen * tweak spacing * resend code logic * add layoutanimationconfig * check availablility in settings screen * get contacts * matches screen * search, temp setup for matches UI * add a bunch of number parsing logic with libphonenumber * cast to looser type * rename sync to find FCF (Find Contacts Flow) * update geolocation hook * nicer design for settings screen * add completed state * up border contrast * update expo deps * add pending spinner * add country whitelist * add empty state screen * drop add more functionality * upload -> import * fix typo * fix permission string * copy updates * rm envelope icon * update sms copy * add inviteinfo component * woke is back * [Contacts] NUXes (#9515) * add a bunch of number parsing logic with libphonenumber * add banner nux * add announcement nux * native only nux * rm shitty animation * move isNative check * [Contacts] Onboarding step (#9489) * add a bunch of number parsing logic with libphonenumber * restructure onboarding to better support dynamic screens * integrate existing flow into onboarding * add intro step * lift state up to allow going back freely * gate onboarding by geo if unsupported country * add done button to standalone flow * [Contacts] Add `contact-match` notification type to feed (#9519) * add a bunch of number parsing logic with libphonenumber * add contact-joined notif type * update string, api package * Update NotificationFeedItem.tsx * Update NotificationFeedItem.tsx * Delete SyncContactsFlow.web.tsx * fix follow back btn for this case * [Contacts] API integration (#9487) * api integration for flow * copy tweak * tweaks after running it * wire up status page * rename toast * use api lib * rm temp code * maybe fix otp error * clear code on error/resend * add 1s delay to verify success * update package versions * Delete SyncContactsFlow.web.tsx * try and fix yarn.lock lint * even woker * fix uppercase friends * surfdude feedback Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> * rm log * allow resend on invalid code * Update GetContacts.tsx * overwrite country code if possible * fix Apple's Best Feature * devenv latest * disable bounces * interactive keyboard dismiss * copy changes * national format * allow resending immediately * move success state down a bit * Update FindContactsSettings.tsx * [Contacts] More onboarding changes (#9491) * integrate existing flow into onboarding * refreshed onboarding styles, rm stepper * center content on web * Add back dismiss button for internal onboarding * Import sort --------- Co-authored-by: Eric Bailey * add matches query to shadow * add clockwise arrow * update status design, fix dismiss, fix queries * add metrics * add more comments * Update metrics.ts * refetch both queries on PTR * fix shadow state in matches page * reduce empty space at bottom * show contact info on matches * filter out contacts without numbers at an earlier stage * Error handling ✨ * get notifs working * filter out businesses * rm log * remove TODO from learn more links * try and exclude from web bundle --------- Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> Co-authored-by: Eric Bailey --- app.config.js | 7 + ...otateClockwise_stroke2_corner0_rounded.svg | 1 + .../icons/contacts_filled_corner2_rounded.svg | 1 + .../contacts_stroke2_corner2_rounded.svg | 1 + ...gnifyingGlassX_stroke2_corner0_rounded.svg | 1 + ...ngGlassX_stroke2_corner0_rounded_large.svg | 1 + .../personX_stroke2_corner0_rounded_large.svg | 1 + assets/images/find_friends_illustration.webp | Bin 0 -> 171196 bytes .../find_friends_illustration_small.webp | Bin 0 -> 40962 bytes bskyweb/cmd/bskyweb/server.go | 1 - docs/build.md | 2 + package.json | 71 +- ...15.0.7.patch => expo-haptics+15.0.8.patch} | 0 ....patch.md => expo-haptics+15.0.8.patch.md} | 0 ....patch => expo-media-library+18.2.1.patch} | 0 ...4.patch => expo-modules-core+3.0.28.patch} | 0 ...h.md => expo-modules-core+3.0.28.patch.md} | 0 ...patch => expo-notifications+0.32.14.patch} | 0 ...md => expo-notifications+0.32.14.patch.md} | 0 ....0.12.patch => expo-updates+29.0.15.patch} | 21 - ...patch.md => expo-updates+29.0.15.patch.md} | 0 src/Navigation.tsx | 27 +- .../InternationalPhoneCodeSelect.tsx | 7 +- src/components/Layout/Header/index.tsx | 5 +- .../VideoEmbedInner/VideoFallback.tsx | 2 +- src/components/ProfileCard.tsx | 10 +- src/components/ProgressGuide/FollowDialog.tsx | 2 +- src/components/RichTextTag.tsx | 2 +- src/components/SearchError.tsx | 9 +- .../contacts/FindContactsBannerNUX.tsx | 107 ++ src/components/contacts/FindContactsFlow.tsx | 56 + .../contacts/FindContactsFlow.web.tsx | 3 + .../contacts/components/HeroImage.tsx | 33 + .../contacts/components/InviteInfo.tsx | 85 ++ .../contacts/components/OTPInput.tsx | 143 +++ src/components/contacts/contacts.ts | 100 ++ src/components/contacts/country-allowlist.ts | 37 + src/components/contacts/phone-number.ts | 162 +++ .../contacts/screens/GetContacts.tsx | 290 ++++++ .../contacts/screens/PhoneInput.tsx | 326 ++++++ .../contacts/screens/VerifyNumber.tsx | 386 +++++++ .../contacts/screens/ViewMatches.tsx | 683 ++++++++++++ src/components/contacts/state.ts | 198 ++++ src/components/dialogs/GifSelect.tsx | 2 +- .../dialogs/SearchablePeopleList.tsx | 2 +- .../dialogs/nuxs/FindContactsAnnouncement.tsx | 116 +++ src/components/dialogs/nuxs/index.tsx | 42 +- src/components/forms/SearchInput.tsx | 2 +- src/components/forms/TextField.tsx | 22 +- ...teCounterClockwise.tsx => ArrowRotate.tsx} | 6 + src/components/icons/Contacts.tsx | 9 + src/components/icons/MagnifyingGlass.tsx | 14 + src/components/icons/MagnifyingGlass2.tsx | 5 - src/components/icons/Person.tsx | 5 + .../intents/VerifyEmailIntentDialog.tsx | 2 +- .../moderation/ReportDialog/index.tsx | 2 +- src/lib/international-telephone-codes.ts | 120 ++- src/lib/routes/types.ts | 2 + src/lib/statsig/gates.ts | 1 + src/logger/metrics.ts | 89 ++ src/routes.ts | 2 + src/screens/FindContactsFlowScreen.tsx | 77 ++ src/screens/Messages/ChatList.tsx | 2 +- src/screens/Messages/Inbox.tsx | 2 +- src/screens/Onboarding/Layout.tsx | 202 ++-- .../Onboarding/StepFindContacts/index.tsx | 60 ++ .../Onboarding/StepFindContacts/index.web.tsx | 3 + .../StepFindContactsIntro/index.tsx | 88 ++ .../StepFindContactsIntro/index.web.tsx | 3 + src/screens/Onboarding/StepFinished/index.tsx | 114 +- .../Onboarding/StepInterests/index.tsx | 29 +- src/screens/Onboarding/StepProfile/index.tsx | 46 +- .../StepSuggestedAccounts/index.tsx | 37 +- .../StepSuggestedStarterpacks/index.tsx | 30 +- src/screens/Onboarding/index.tsx | 119 +-- src/screens/Onboarding/state.ts | 180 +++- .../PostThread/components/ThreadError.tsx | 2 +- .../Search/components/ModuleHeader.tsx | 2 +- src/screens/Settings/FindContactsSettings.tsx | 562 ++++++++++ src/screens/Settings/Settings.tsx | 14 + src/screens/Settings/components/OTAInfo.tsx | 2 +- src/state/cache/profile-shadow.ts | 2 + src/state/queries/find-contacts.ts | 128 +++ src/state/queries/notifications/feed.ts | 5 +- src/state/queries/notifications/types.ts | 1 + src/state/queries/notifications/util.ts | 3 +- src/state/queries/nuxs/definitions.ts | 12 + .../notifications/NotificationFeedItem.tsx | 34 +- src/view/com/profile/ProfileFollows.tsx | 2 + src/view/com/profile/ProfileMenu.tsx | 2 +- src/view/com/util/error/ErrorScreen.tsx | 2 +- src/view/screens/Storybook/Admonitions.tsx | 2 +- src/view/screens/Storybook/Menus.tsx | 2 +- src/view/shell/Drawer.tsx | 2 +- src/view/shell/bottom-bar/BottomBar.tsx | 2 +- src/view/shell/bottom-bar/BottomBarWeb.tsx | 2 +- src/view/shell/desktop/LeftNav.tsx | 2 +- yarn.lock | 982 +++++++++--------- 98 files changed, 4905 insertions(+), 1078 deletions(-) create mode 100644 assets/icons/arrowRotateClockwise_stroke2_corner0_rounded.svg create mode 100644 assets/icons/contacts_filled_corner2_rounded.svg create mode 100644 assets/icons/contacts_stroke2_corner2_rounded.svg create mode 100644 assets/icons/magnifyingGlassX_stroke2_corner0_rounded.svg create mode 100644 assets/icons/magnifyingGlassX_stroke2_corner0_rounded_large.svg create mode 100644 assets/icons/personX_stroke2_corner0_rounded_large.svg create mode 100644 assets/images/find_friends_illustration.webp create mode 100644 assets/images/find_friends_illustration_small.webp rename patches/{expo-haptics+15.0.7.patch => expo-haptics+15.0.8.patch} (100%) rename patches/{expo-haptics+15.0.7.patch.md => expo-haptics+15.0.8.patch.md} (100%) rename patches/{expo-media-library+18.2.0.patch => expo-media-library+18.2.1.patch} (100%) rename patches/{expo-modules-core+3.0.24.patch => expo-modules-core+3.0.28.patch} (100%) rename patches/{expo-modules-core+3.0.24.patch.md => expo-modules-core+3.0.28.patch.md} (100%) rename patches/{expo-notifications+0.32.12.patch => expo-notifications+0.32.14.patch} (100%) rename patches/{expo-notifications+0.32.12.patch.md => expo-notifications+0.32.14.patch.md} (100%) rename patches/{expo-updates+29.0.12.patch => expo-updates+29.0.15.patch} (51%) rename patches/{expo-updates+29.0.12.patch.md => expo-updates+29.0.15.patch.md} (100%) create mode 100644 src/components/contacts/FindContactsBannerNUX.tsx create mode 100644 src/components/contacts/FindContactsFlow.tsx create mode 100644 src/components/contacts/FindContactsFlow.web.tsx create mode 100644 src/components/contacts/components/HeroImage.tsx create mode 100644 src/components/contacts/components/InviteInfo.tsx create mode 100644 src/components/contacts/components/OTPInput.tsx create mode 100644 src/components/contacts/contacts.ts create mode 100644 src/components/contacts/country-allowlist.ts create mode 100644 src/components/contacts/phone-number.ts create mode 100644 src/components/contacts/screens/GetContacts.tsx create mode 100644 src/components/contacts/screens/PhoneInput.tsx create mode 100644 src/components/contacts/screens/VerifyNumber.tsx create mode 100644 src/components/contacts/screens/ViewMatches.tsx create mode 100644 src/components/contacts/state.ts create mode 100644 src/components/dialogs/nuxs/FindContactsAnnouncement.tsx rename src/components/icons/{ArrowRotateCounterClockwise.tsx => ArrowRotate.tsx} (52%) create mode 100644 src/components/icons/Contacts.tsx delete mode 100644 src/components/icons/MagnifyingGlass2.tsx create mode 100644 src/screens/FindContactsFlowScreen.tsx create mode 100644 src/screens/Onboarding/StepFindContacts/index.tsx create mode 100644 src/screens/Onboarding/StepFindContacts/index.web.tsx create mode 100644 src/screens/Onboarding/StepFindContactsIntro/index.tsx create mode 100644 src/screens/Onboarding/StepFindContactsIntro/index.web.tsx create mode 100644 src/screens/Settings/FindContactsSettings.tsx create mode 100644 src/state/queries/find-contacts.ts diff --git a/app.config.js b/app.config.js index 54c6edc8c..ca417206b 100644 --- a/app.config.js +++ b/app.config.js @@ -389,6 +389,13 @@ module.exports = function (_config) { ], ['expo-screen-orientation', {initialOrientation: 'PORTRAIT_UP'}], ['expo-location'], + [ + 'expo-contacts', + { + contactsPermission: + 'I agree to allow Bluesky to use my contacts for friend discovery until I opt out.', + }, + ], ].filter(Boolean), extra: { eas: { diff --git a/assets/icons/arrowRotateClockwise_stroke2_corner0_rounded.svg b/assets/icons/arrowRotateClockwise_stroke2_corner0_rounded.svg new file mode 100644 index 000000000..6cb05284d --- /dev/null +++ b/assets/icons/arrowRotateClockwise_stroke2_corner0_rounded.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/contacts_filled_corner2_rounded.svg b/assets/icons/contacts_filled_corner2_rounded.svg new file mode 100644 index 000000000..4f116ca10 --- /dev/null +++ b/assets/icons/contacts_filled_corner2_rounded.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/contacts_stroke2_corner2_rounded.svg b/assets/icons/contacts_stroke2_corner2_rounded.svg new file mode 100644 index 000000000..d7ba9a150 --- /dev/null +++ b/assets/icons/contacts_stroke2_corner2_rounded.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/magnifyingGlassX_stroke2_corner0_rounded.svg b/assets/icons/magnifyingGlassX_stroke2_corner0_rounded.svg new file mode 100644 index 000000000..a21615b5f --- /dev/null +++ b/assets/icons/magnifyingGlassX_stroke2_corner0_rounded.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/magnifyingGlassX_stroke2_corner0_rounded_large.svg b/assets/icons/magnifyingGlassX_stroke2_corner0_rounded_large.svg new file mode 100644 index 000000000..e39b48326 --- /dev/null +++ b/assets/icons/magnifyingGlassX_stroke2_corner0_rounded_large.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/personX_stroke2_corner0_rounded_large.svg b/assets/icons/personX_stroke2_corner0_rounded_large.svg new file mode 100644 index 000000000..d77d3763b --- /dev/null +++ b/assets/icons/personX_stroke2_corner0_rounded_large.svg @@ -0,0 +1 @@ + diff --git a/assets/images/find_friends_illustration.webp b/assets/images/find_friends_illustration.webp new file mode 100644 index 0000000000000000000000000000000000000000..9074282ea6239219cc8cc83a300b4eeb13f6e7b7 GIT binary patch literal 171196 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 z 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⋘NliPBGEF_zDki+cRi44Y zJFm7z^}n6M3xlAO6Oy}sY*8yr{_`TNS$uW-1A%Ow^jnN;8&ALayVsPN)!0U-I8|1< zqsT6?St06>SMd&3$rzQGNb~L!wRhYfALKlCgtDfcO$90vJwkKEIPR%=cx%IVA4$IDxK>mzb zlY$Oj>U?FVU-Ka9YWMY3oBv*waPw&4+p~VPtN7I4b$gGLOh2<_iE!)8hh9fmdiGT) zM?QHwgI81{<&3wgC9~qV?OPvrxNcG`)sbmn;Jtcw%2C&ca<|^CikS9H`v>=|8`V4a zz87JXRo=cwEyjAK$BFhAMg0td$`wu_tAAK&$-donw(X!z7+=5Kk~JOvIu9-$e=)&( zx@Oa>=~H(ZJ-2gOQruuV|Au`qo2Wd)O^5g;Dy!B#n|Xo1?1l1)+HLV47j66U)@{4{ z%$z6b*&$P}+}q(jYu3E4D-7js+o?V2FsYcb?91ZWmC*}AJlvyYqNe>f=w|=%L1OFk zsh3x*7yllcT0Y79)t{%!pBQbruqWf$savOJSKYIHfBDPQ{pVN|pFiGKcl*|*^uC>D zmzD}o51%5e^yDhnU+tBDjw}mbv-I85A4xa3WBV;XG=$9Po!Mb-wecduTK*S>oY|fd zU!vFfw508*GTNpTd`b6%Uk_h!Hlsv$_JOti?jbQBd-p!CNmD30_Uxz?_tB8fOJ;kS zTTEAOG}Q68?$LC(*13UK&phs+-rhAkUOv~kd~fPK_PT9$3p!-d{QYh$)cAWV%GAKe zpgZZTWZ;u|pAYd)6xrIMA$m#FJ=L+n_#PkU`ZD=&j&*|bs<!< zM%eMs4(1N~<&QC(U2{e#8fo)*UL`!oVP8>L_REC;PQbbHd|^tfvIyHtxN@ zP43A*iT_Cp`MJ1X-k3W{VfGHcLqCQH6`fuFE2__g~jOn9DOCwmL8ItY@re)}An+Qf-)?@m>%2{zFg?qb~pVf_W*U#;lhwjhy zxUlW0YT_{`qxI$Umujc1b2!_$sq?}q+qL)R9{9v?`pn%Y%-{DHy_pyOc2dcSGa^g9 z3=729zcV&&-Bvsy{CV5$TWbF-W*rxJ;GNUY9Ie_D?DK5OEANe5NO$SI$G@2U3)K0_IYpX z)|Iz~rrN|k=GS(4EZKG~@95zybCyf& z!NRuoI<}m%SBx8*1(!^?`Tjkt=v8L6Qgey$cXE-(R|Y6)e=}6&Ip;7{Ca!gf?y8pb z$z0Bky~*E?p7n3uxNBbTrVHkqvlcTgx)k#NPOXTHZ~mmYM|SnAe^`3;=N!>#$(BX$ z6+DgSDhLS$##v>&pRjZ&=@3*DCyaE>�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 literal 0 HcmV?d00001 diff --git a/assets/images/find_friends_illustration_small.webp b/assets/images/find_friends_illustration_small.webp new file mode 100644 index 0000000000000000000000000000000000000000..af7cd083f2344d874d8430981b341f5ef7ce6ddb GIT binary patch literal 40962 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ⓈXZ5?s ze(bcu;*T3MjZDIn&Rz;Gl})Pp%fNX|!T;>j1q*Zdbo5KsALqBKTPh~P{nx%RW6A$V zpLG@s-1c!4Zf6hAPq1jXto+?`j`I1NuaD-Z-0jhsz^RZcR{Nl?ttFxJ@-Lokw;!Z0 z47)x1n4W`_Usq^xfl1=pu9>@k+T~uWwu|=tvta&tzvOiVY*YH{xz|$j z+?Em8wYU1t{Fzts?s@D{zkK|S<}7df0={;${Y@tiGO8?pw<$UNbJh2wQMK2$eo2gb zt@h$}`@ZeBzHa|`Z|}?>?pmv?gAScg&XrR*Zawe74uMyt%m!i#-|s!GN!;<%NA8j3 z?YEw<98WF2yy^1v{)?+5EUd&*H#{$vd;Ews>CUUrSkdLYM=fucTOBbz6F8-hHS20? zUf+?6!Q6sbHmRa1NkMlf4hy&|{HxbFIXtWhFwL%J!$ZWg(axVnoHsr@eA z+rIo>ez$PC<_ zUJP@|#LK+%nz>6?b{`9A5)MCXUtxZz>O(~Ed9IKxTDo6-=6t@j#JJctEZeZ{e(+Yb?dpgb*F9Z{M}l(-v?hdRaM^?Z_Mj;V&3H5 zuf`Vop;Hp~gkM_zq;ukaE$Ib)XLK7Hk}@|sDKrQ+`dmD2X4Nl!{*XfLd$sD4O3}zX z3$~YGncHnyIX!MY+EcUMZ&qW?qi;3ax~8sMX7;~$hVqP=)9YMs7wR^}o|vJ#Pt>$Z z+UY9mv6^_936_mpeB3@C_HWRRF5=wvBW3ETndJ+)H+pohnW4Yh>d&!6hN!DoYI@3^ zcGbk&^?mF;z2W*v!6>DDvBEw|0`5P~o$uJTJ)~U5m$SAs_m#)lf-@J`vu8+FD)jy@ z2)@W%#HzD($ENyaf&c6mei3=hmvY?Y`5OL2wvMwp70K`ZJV~@zCAOgN^A{H*r?%HF z7ujrV79F{LDfjrT$8M|7PY8ap=>6;cZpNG3mTCIWyxq2U`ss3GmDys`O6RZ6-g*Bqxa zN*~HpVM%J4run4z>tvxv>omXroqBWe!6uQn3Cr|-zsK7=TajbAVg8$kPdmex`bz)2 zxja-RewM6xiN%R&r)F-S@$KhIi(kod)7kXJL&U#@A1b!r8!08)EF_(vH%Ig1$AY_S zo4Tv-RZm}QAaal0jd{iG1^X4w>YB$ERcw!8Za5`VdLvK4Z`1z3jn$K{gteae9qpI0 zB*5$0(-mcM(wUVm%Ok9nzWY=i^boDAfBs^Q@5BVYm0v3IWe?hKFo=CLDbMRh>}FEpd2uA>+k?JRgR|Q7NIC@)vDBSzNuiL?@w3OzLR&3|Z#7FADK) z{comC)=mrb2<7ri{l0R=6l=q~d%0iQ8QE9Q4BN7uy=?ssnNKrY1&fwl-1F7{bJCu| z^3??&p1fS5UTNR&w(wb$OZa5}`=65ys$Vv!C5p_}(HFTtoqv_NjPj$&s$YtnIlRO_ z&NGp}Y=1dhrX)n-v(wA#|5CoFZfrPlZByX?k`I5mc^c-vsGmC3e~Qcv)r}Xwv)`C# z?Ed3uN{lS?(UWUS6x+P!-mg5RQP#8jt;G)c;+x;=%=VP3-;mv1vZ-Z7U1(Cor3I-s zGjD&Z-!}i>w5sfVymsI7 zM7E{)(5`a=;Y%)dG#f_k@i|o0zT0@ui={JlCV%+zIaPV7KwXQRYWVG)d)3#m8~tgY z_;lZy{tnS!0wo7Cb5-yCJ-)>zLOyNXUnYS=ud+97)qcBX?x_o9FXet29|;cWw6Ycc zcp|yzshdW_J?)Hx%g&1|l4ug(td106ZMnALalH>?*A>z0a@Cu5c@};AV&o>i()FYYo)XXVnYluB))L*5 zO_yfy@N3;WY<}X9IMcaJYx1`(k32H-uIdOI|N`_b2DK??r9A#!p3y zPkVGO+!H_d`oT>LKeylX`1&y*WMADQo_n{9P8~XvkSkpLdd4-a6Xz%I_+Q2%B+%N~ zyY$lJwEb=iEIjh{6N7wB7VeV@{$saaxFhPn*WGD zuPL-SUU2`-&9-p*+LY9PKddw=8nJc}9A8In@0Ez~!(Yx`bSkYS>C^^jr) zOKN^?^$m6}$yPDltuiX560-ji7Yntwc?k=q>SvyGlUXQb6xga-qI8WlJ*J+^S}54` z#RbKV(@izqLhYrKecR_uXK(oVRnkZE+^_nLnPIUSi}d-f`tDa((H0C|*?r{B<^w{< z1Se)r_sQ;*5XtHWzb#lJVdOnOQpTLq=l{Wo*>ZVyyE2;c)DL+GPG@v<+^l^h z@!gyI7BlaLM(i)pTV^O77VnrgcgH0&u6b#RN001ZBpcnU?!xZEFtb~?fGy>QLb|8o zdLg_1ePwFr8uo5J@$IH;W%q)0lQJ)yN%*TZA*o;I&*Uv>CwBfi{A(A}tR+QfbM*W! z3iNEcvD$1B$E4e{6|*i`&VO0o^iTQ>&*`t5E1fe1IeQOHVrbm8%+EzK&+ui2r0gx5 zBUO%-0X%q6DRy%&b%#ME7(c(>|I%o z&~1Ec&06K>N$j5K#`fvihQBS>>MxYX=$U_<<921mbT@6+BhC^|2{W0#tDZb#*PUK= zTQBp;^lw~pcSN=q&2Vt@&NBG(2Aa+}jU1-PAdk zxmNaFi{|3q?yXyP#n0w>T>oR{!?mY-s>;6$YW%-b&&hRqi`hkkOXZQ*7AM>~61BQu zWslTe{nxX1EN0JMaPv-z(#KnwQ&P=;-hIvY_Ru@K>8~y~7rG_On%Rmwn9sTBH9duk zt5sI*@XwWpcg62pKcmiLg~Gx{YdyhPiRGmn-s>9Lz3vB3e>(m3>*qdA39Q%JIoF?8 z?lW#XylGeJ_ntY$_g4mg*8Sx)yKjP-?6;U(m%NRwHpFdTvA1~B-bn&E@~gP|Mc%zX zeZ(R|W8dpu{fr;GLIuvm&+il3Va>fko#BaK-w)F-vx}};JE|^L*!*X)&Bgh=P6Z!h zd0Sui*%))EskA#E+bQxV;_N-0bPFv-`^Cp^bhG3$?XTMxU+^nAcS-=)WP9<)OIfoI zbbWps^jIJv-0DNqo)3$HYEm+l%`~00?ul|6*A_1OvG>v8ZSQCMxG=rFe<8!%Xy=;0 z7mL15n(3aN($&J&CT?`Y#f;s{$zsjrcRv_{mhazuVVA`ESs6lew>d@p{QT+Xu1G`a za872eqCn`M>4S6waO<2hum~UUuX2%eoyg9XacldmD5K$$ET?_;O@_ zj!4_5oSQ4fA1oEII&|C0i%pREwa-(divNOFPMgfK`jb3ARpI=?eZ|4aoEhf}Ew~P( z&k?eJCUI|%*;Kh59`D>{WKR=2-~DHb=Y;Kl%?sa55We>5i0ayU_AQ}$&hISBZY46_ z^G)xQO7Sa9Vg6}*<4pH={%=37p8GoGy>E8p$y#3PNeb0b(toA*XIq%OY4*Ey{+mz# zbc2-VnjS^QJFFIbbovP<&)da6isWj;xbF?|B>DE#nMkj(V>n#lZz?P z;ptV$+eQpVMKS^tRplqI`f+!*UE}-bd=Khh?5Snn$YWf${AI`;YqJ!;4KFk{9?N?3 zP>*Fr0-sOWsdar#Qg7w(;uj-}F3qQ0g{0mpVWO|r(i`b%OJ8gb%{ zcP|eL)VF{5wl3>W;Y-fC`uvB}3uLb(_ z%Rin@b?BOLmsjJ*hO4^C_CAMuuDZ`vykO)IASnAKpzy$Dk>s>RRgU`?IM&vr`sv37 z{PE!3ar`Fdc9)}-k|B)iy6R*E%lB^a+pNzxCoCbi>sj~76b+dGhqC!^uY6~VE}32N z`Fz;wHy%5jCu@HB`PnS2Ff+SzLi?;vmEZr^D{sEczaZgLylut?FTL?)mw_<(<^@1@Y$F ztY+}f{_D)a7(M@6#?4UK3xD^no}f@9x+&@wXX0AR6GypAvRP;C*5kU%G(lPE=flmv zlrG#9GZkr*ef4+Ft+mI!TCem!iCRL7_>z+JhG?llj+r6;%zYf*JeYp?Tm5Bf0rJz_jbIyulmVNKd}z2 zrIj+b5--d?+PB4=BdhG?!($I;YS`=X{0#h~b>(#8tGsQ?wU|FzeV)0&CATDq&2913 zzY`WK3ZB$?5Lg)C<+f@1L>7_ti}+jXJ~7uxnr_x+omOS;H6vGyCwIg3DD7zq)^>YW zl_l1jX_nVSYl&XTd$zzcnP)l6uYCP8iXt2ih5N4@Z(EnSKmM*+9vkd$0z~Gk9b@3kX=SN+W;aeeq@O?K&~F3RP+QHcr1= z{_MJ^=!LU)4wrvU4P-uF>SH)5yXjt;le0|i?ai#>e9k7}F$UYs{G<|OYY^ySK{lsvSv-Puc$NKexyMqTkOKUnZjll*FAPRz9!&csS`(n z{Nx3dtga6C*K9US$c#8q^_0W?1ycZXO0I{(CvD@eYB3foy3U4d+Y`R!7PH=Gfj#Q0 zgx7s3QF<2SVQj7)>SaFdd5_TP=e@>;G8t!2MSr^a-sMEW=As{ua%TMA`cQ(an8hRQ z^VM^@tuM>;H3VMeGGGUuv9e3C8hIX#Xl&#rs#5m{ZiWmQq`I#`~z4+qE<&X021a_JJ z*T}mWp0Pi4Q~lZNjS;JBRtYd~nYV1&*8JC+T&`DxvRYqlymV-W>&JOZr%qgQMK1Fq z)9!@UG}BE+NxKg2&c8objNc$Gqf;XFW$?zc+PQ^%n`V6ysM)<>>zaAn_G=_->Hdp+ zVt4*U)-|~o?NKEL+10)0wa%UhYYR4&YtF9B-Kvwto0-3KuFw(j1zMBsQ=2M6{dD!j zQx8mNS)X-!NA1ztkXwO;EGt{}{W@+q=dN8l@sQB0uX_*fjCgVN?OU^Y{tFjELXSFW zUylxEi#N;FVK+Rn$70D-neS(>ob}(bB8IC7KBj zfJJJOQ6jU76@GVdiFK=}zH;5b5OnOitVhg2Z<$+uyvqV!8Em`7D0R;86HlC)DjOSb zv%^G#yODWUi-Wt|YI#`M@>Xkq{jJj!U}|Ol)j853c}i2WWB;y4%Yts&&tm+1D!n~y zqS|T!!ONzn^ZxE=`6I+8z38|obN#Nf>~qQNZTKIx?CUyk|4XCKEf<(Q^b%$+dtXZ_P-llQGn@!w{$@Y_SX z$jJc?vUftS-jlW!y*HD|prv!Etg+^*=whQ?W#Ot~Gwmjy__xvW$)S*QT378R->LuA z+ou>F@i_BnQN!PapG&vh{x7+XduxN@MX5@~-KzwBZtcAn+||LnP4V#~2crjJtum>8 zkyjay*ZXJqJMh?Z&oUA!ZrQeWZNcOF7wld%>{}7gVLC@JPXD{&&tS!^myX;|Z7^Oo zwO)@Sf?M^lj?DE3{5!wPZ}EHM6XJB3XYR_rRX(%zteg(-NPqHE|4-oBf(|Y{$zP?? zCl&qd`~S5t>7ILh{^GA`+nKA1TojM7nm_+>eWA4Yu>j>cTX@pdW}3}0{avxyqgq(u z{QX5oGDW+d$VISD_jS64 z^Gbb;M$5A3CHu?x@0J~SEN8B=!=bFsic59I>jmc)2N(n^$1d2%wd9U;mPP&px#q;H zjRpz@|Gpl&xor(Ux6;0+X-QARfBbm$Xh^})nc`@PhzE5}jt9EQy<2LJ) z?CMuPU*sN2m0N8U|MgV!+S}G`+cV#-Jnz-OdWygJVbrAiJ@1ORPK5;gHd^{LMEVB;B$>{B&wW_z_bS`7U%pIial2p3+ZSB3Jb9PQm7Po}zP%}`J9f`L{eS0P z-rye{5p${@O^`WmUNa+a{ZrUk71wMAXQ?U9^8{|IvYq_$%Ikc8sO&P6zAyuO zz8y9KQES<4ZVJ3%*j8|lBgG-?dcC%=-L5r>PwuTf^_HdJ%p}H7B|5gho8(dpi{m@w zRUCs%ET?`m+t_O>Vbt^P`?LRUtPk%Vy1C+8nU1K0cIB(te*J;4?B?ISks*H+b3A@aq_v#x5UuI1{J5hy(1fMOLoG?JyNqDrG88?&(Rm^-4e6rHj7HD zu~hP&G{MC;d3@aqrT;9*)%vfx?%U+Yi+(>nAXc<*>Ur*mkB;3cS1NlIb4NDn!jgh%TvW{`8r;JHy$*qZN*?v}qXMDd^?taCLiM3H(f7;6U6uSbcO_~)*TwS6qs^G(nG!~M7W<`f^iB>%3n z;`oE6rjSTW@pa)VH-s))8j<-90Jo2M8fAT>a_s8=s=dz#HH94w`juvg6i|bBkJ(9W-vH#?;rC~F_D;!W< z`~11KtY`D5)oUHu*FAhCzANy3veA~5?oFTg*ZO_?VpgzZ%^Wu_&d96tC8oys&6P4= zc87oJn?6nM-OsLhCm!klwB^sGXz^2jGEcyYD)Y*6lJvU;0l_%-a6R1{p1g`UHMlee&}s_`0tc;RB7n@>Kmb3 z{dzg#mmINj{&iCIo@eI$!0(bJ?~X1t6SH3Y^6rrz7ynu>tGLzkZ??3=yo}{FM<%Xa zu_U4BU*0^?)~$Q3MGGdVr}Sx`U#(uR`?HogyQOu}=Bt;zcSodW&bZf8@_$p*s=%L) za{`Zkc~Y|Wu0(O3b^9Im-ub21CkQ((db;$%ejmq!`%S}+)y%A3dFV*XL6NG(O_pD; zUiw*e^h9BPHS>%Wj#XjRK`(sHJ+`>Ke#-;dc}I_U*0o(IG38^p)+W9^+u+J(zC*IN zTHncBUc7j^(u_UtoFC0}EYenKzS=&&fvY0Do%8Ff`5)KUhK%3|yQWv_uDESi|Nq!^j+o0QnN+@L`R+LM`0=Od7tcm?UZ3uu zs_^UN3&!^*A(laD5+)PU;#Mlo%5E`7Li!6*XCZD);dl4>Di% zf9i3&V)*#0M1E7op|^tCzm84r$ZNlQ&wdBz)`-bc=c@Be7HGe!ZoPTMF+M;`LFA{n zq(F7-GvBiW{nyd_)rf7n$pRpj$3jbB|h4;N+19?4Fc^5F0a&F_h3wo@6mF^ZIj zFShXT5*Lj$k)8Hw{Tn656R3OwNmoytPpX#wm}yc@*GUNP%!JM+fLJ75oXEW?3W=Y#1_A9 z#nOM#XVa9q7wnod<=d3<5P|%oF@EcpKh3XInQ{42o!*uTV}lt5yI1pF%A2vF)ns!ucMnGx!o_2v4b zJ=$kO?p|z4EpfA*@iO~s>SOj*lJooIwPP&ppR{DwTONokpOUXwt=`6USu}j{rP+s) z*t7ed?rvQ^?@3_h_HeeK2OJATS(g2}%D{Y|Pog(BtF&kD@rk;dH}mGdwy%}{cx zP6iQKg`SUnKh9jdc5Ldj*(S-a3}>J9 zDOozJScy&B;G*O<&yB}!m}qYbe=qiSyXo}Vg5lrn>R(Rh@v^g*nJ;$p)!B7#rIuSO zJ)8DFQf2$sB{v$rR?DkzULfl;+bC69F023YC-viQA>BXMlsyRg>9t>xA$P~t{eBM| zH8Yjx!{(1M8&cL9;sV@Y*^3nAjVbiR}e$@j@A{owbc(~UFv9>emddPahtHS zOrjBemv=6XeK`4){7Y`1m}~D9%=4ca{pkC!T(dDZquEe+ueYvw@HOeg?*9S|vVAkN zww+#X``ofi?0;lFK;=T)ikkoj%@8Zk;OkI z{7GrFxgy5&d|B_br>8G2J-MAFYvNB2h5oYkfCa1K4OV_!-L6M18u}Y7@;^vl z(MveSs%Vk#nZq04XW_EUSZC@ZIV0u%`=&D+3cerOZ@bQWe`h4C6ia5*x}ezOGuS?* z&5~Gh^WUu}3?C0%rTovvsLPx!C1-zqod45eD}#=B zoaAn?tXB+?8xGF-ed<;4P3y3Z-hdJl^X(TkwRvn&REO&ogYq$~PPSzw1=_ zEbdfTi0{(<%T$g9Jf6ipUgfgJ4u(k`r&Uk5 z?fy7%UV_W_Wos-KFJL)%_r)1o>Au6qlJfW*#rB=`Sas^L*Q)n^pHI)_T`RNy%z;Zm z`iAv$4mEok*_2%Ij=FVV&MLPBJ4LsPX0R1yB_~8p;a#Bj)!*xkjNh{?IV1KxwO=%M zEpxxIbMwpc;BQx?liwf6nr(9OCex;vCxWe;N){z^2=Z|kI>byqa%owh7h zZbqZ!Ts`isxA|(`?y3--dqc-9kzw})GhV5nb#a>0e7+S(3o$A0-6LyeVGjr0yO6Q2)UwXv3?WGp2+Yisu?M*_~co_Q-XOUe}!Gv+4p&xqjZt-Fqo( z>m|_%e#v|_D}pEeT|TpAhm-Gz^kaPU-d$^*&+=$O&z0qDr?2x)Tef=NjLGlrrtM|k z6d`-vyg_lP!VRVqECQZ0FN+$lm!8nk=b1Bo#}n1w+-25_`~ySPBOa&hYn`!B!drAebUSd5Lv1{j@b$4=C)Nk)}Z+4mX z+Gn5R$F+v*PUlY7TE1H7rP>2`PmcM$ZMvmbKN`-ll3cd`z#+Rw{#+Bb9yfS@Z;E!; zjO4aM^;;S;t5;ZVxvEm?pgzl?;DoJ;uARr$yA{7upPm246Z3MCf=I@fy@vBQJY68( zt^Q$q?t%2bMQ<#>DBb(IG2!ZJVcYbbOJ};MmC1dsKX&kx*72{x1>S9yALeL_s_eSx zm2>p1-R_x^wsY02UtU)EVS6g7rbzDx_n|n}kXxBqF8#4{k~${LtF%4g_~()H%Pl{- zCo2R*g=rR)pXA!~NX)g!J?g2cS%A;Pn{!;IZq0bE_2|Rg@RrRo46JQ8(gau^M)5Vg zdt|M&H=x}1(Y}?Bj_g@3o|bF0LQ^G2*zM_>KU@DA=K4v;$+voi+}Qu^`GuS=lZUrX z9yN*G+t&ZOl()~OOCam7mEqlZ^UmA)PUjLNCamH=U%c$jH>tzB-W=Os#!|p$Vs83b z`1zC5A8&uJ>@hyEH(M^-+hTvJ{;3O5vmF|n-nBXVOg;3|`qI^D&hMQ9m(`uqs&}8d zqFn35scp}L8J<2{_vp6D)_$YPj`h-?s~2~bH2qsM%g*MT*5USsfGq~+KSl1?V#giY zt-Jl8>dQ$t9{=k36SnS+z2$^d_e95F{lys<*4_=jG&|ohB5i&4+kG2~E^g#nmm#+2 zYnZCA%I2Ju&t;*yD|hohlTzB0{o(7G)xj3rc?o+L_I^Hc(CFJ+Nx7J(|1Dm8ewW{R zZQ2v29bVq@KOb-Ee)A#QvP`L_Qgoh!;=E#$RP|3cP5&IYKkcgt+gE$(^BpCBru00# zIYVvFhE;fh)tAu$=N_O|4kd4BKn-z=yFPoge5_|q>5?jm{ ztIYN@7hdap?MYHdvM%}j%jEsc8=;ehKCeE%^a0OJtDEV%rJ-RZ(au4y;`{2V(}Xg0 z@3ECXn(4!McGrg{>%~V|3XiQ^ur7*EqRZtdtADnoT}4s;ldX4osyE%4to^RZcqduP9YCJ}ZF2X8fSytZ(?>a@lB=-sLJ!>;{%cws`)|8={j_g{&KknazB z7I^zl?}=AjO2P>YBCEI7<-LDC_uuY#``KSqCx2W#{lLS%`(a-+n%3|;$JyQb!DIS* zYrSHcT;t8{0p$;mFW4KlJoTFUT^Z5qZ1x6QJPd=}A7%f&{q}yW+#RjtNydLwKb&b` zsrdU{Dt3asAJ3m3|1T7?88Lk^^iC^U;1|bgp_2Ch?#0QlAl-ul*f0_&{cZGc^$Ou2xDAe#hXug!_lqD12Eq$?5IHQF}PeEyi z$^!O{%TBXKH29TRDz0Tpu-^RDv=e&x=c)|sK-=j|?4n{hk*imh28rzcn*O5flyz4yj~uTG0}p0)qK#9_*qHg!Tf6IZ2zhv=@oUlttl znZxRqYkD~|;U)i9&db4XEjAzCvqn|i^=ACUt4+*N4}WJ}`Ct9^P41h$a*^e;K3PQW z_g@#Y&FpvF7X2%%f`?k4e>4&}qt%@x_@6QOHRqLe_l#6qr@k&s4|cGM{e0lq^Su0q z{FYtj=7;#^ub95|?5(FS;(knFINm$&O+dQu?ON-V{oSu-Pu)6i<^t)!1sovmk2q_4n;fGn79Xr#QBTw3hAVO0y2UcC=cQ z->mFBi|dmW)A<_R{Sr08nRi#7-D`4w@dH7lyRTA8Ch&8yxw7kT^e8x8pLNgh_mX>$ zzPCQp+!DMdWX_Md)<%_8Lb+-68kbYV+4KBvYdPxVJSq(1s+BFfvU|d-H|urUHk=mg zKY#p3$+5Tw*_cCj&*yHhDZb(8bgB6EruEuVLOb7O`m1f-?5#@~M@?kUY(|O&*f}e0-IK)c<{#ew-t9kEqtQV5&zj|C`K6O?2R>@7*PYK-a3Et_w9~oA z$&N|At)?>*XXmxfchRY5)!2B)b#octBL97V*o0oaE_MI=bb1Z%AC9Zt-#r}LzSdoE zoA%=a>n5FzlinEG%|CiI$B)%VdydVwR1GKDx0BA>-s1kX^>s%v$7^9nm*54g6OWxb z@xjZ`T$g$G&0OtC-Jg~1(k2PczrpxMzVw5L^v>pmziLJ9PK)7nWeVWte96S5ZT0Kf zyU(?EIXw!!TrBH;94lbHVCR}(J-Pq>xzj%H+|1W~oqBxBon@;7RN~ec${23{CNXoH zZNK70Ms{>Ee1zJGkvc=VG3Z;#~UWZTaJr;_Tr$FGw< z#}zi~)Cwh3c*g3UeYddT-)yy$ToIGHMgN8A%&ecIcdQ?fbwanG;zwjvk)g6xzU zvzQf2Ht)&)z%%7cYeDw3r4Q$~G;;la_Q^@|nZMV{y6(>|GZ-S*%)LIjr!k`9|57G_ z8m+YWV_Q~ApL-^r^KW+4(ykq1e+n$8yN7rrHhv7=q1G9;z{%A_Krb!rq^D-_gd0gG zD^G3-OI^9HEMI!<1vjfz=kLgD5o3JdB^C3*#6{?MvEGk2Eca(!sI-sxaLxWt*CD4v zbEdE7|KmFCprB*l8>jEAB@2D8i^u+tTYQJ{sb?Jjt73=aGfdai>^9qXL_6}w$vaUe z-@V%RML=Kidf4hiOK0^c$@Z<1mV6>LdA06^texGqrXMVXt7f=Y{#qhivh_8CV%@~= zT%7t}3T7XRU&x;0YR6ab>x$j6HMe+b0>WJ^O*Ap`;Z~Dv6Vly`=OmR6{XjStraG9pt$Hn{3Ywum%kbfq& zBw>wA{TG+nu^SyH=cG(xkaoNG)4D9B2R}TGpIUOJzHXvt zeQkG5_?FAJ?QhidYH`_vYwtB?7$*hpRlI)r+_v=2zjbfE$Xr(u{57Y)-?6nzxZ;LH z^RWjOfiHb^vu|7!YfU_(GE3};!BoqY#;pzE#eO$7Wj)}nTq|&5^Y_{Q?VC?TlpTC2 z@Ix_eCx69^>FJMFiYHB2_fCAa)xQTK_F3E<2Ug<(dln^^>{LNBPyQX( zTN;!^+{_++u(@8hx?L>uPFieVeZ;@(1?SnOMm^sibp56G&V3W7Ui!}PW?M3Y#H!z4 zPm29vc8&7wsp@#MDSX?lwMWXYiB8Iy`*=RXD!%GXtNy-}x|gqR!~f~a{UfWRy}5q# z{yE=2ad{4xhJv<}W|p1&Q>Ux<7c?-wowMQcx$o(Y=l+|-FmCy^Et6$}L+SlL3}3r9 znS`%garr|;Arn(}Ne?g6LEVg)tgVaV^fP`h_^#x`TeX;Dw|&&+%XwS+?>I^p{a=*! z^Wla%`DcOmG9U4JEf;Y%@KbZI?5}vG)Fb%OuOuhFJpT~yXSE$apG^F8X6k-RzwcT+ z4|`YJ6zmOKb=lfN!t5(EU#ne?O7Xj7M#*dW6D*f5Ns6&H{TifYEGsGEaPVB%)~FjN zcg1d>`d7f~cFhCphvFiQGD*@VOnTq;DLvw32EU0|$V5i~3G|4n0d5&4KUETxx^ALLlp8pkwy-ywOGSnhYR`?ub&oe~oh z8sN?zByv`KOWBrM|LE(vn_j29pW?V+MeV1iuL<<6Zxd84u96US)zoam}=^~c*e z))v~--C;ZubuLY^F`UUX?XSxE*)EQ$`xXQ31@y}(y-7d`^&FqywMwf=N}7f_TA_tX7lLBoCz*LArT#iHqMp3 zzv%IY@P~&cFMacBm7wvbjV{r=yi3a@^9eLCgt|Ndg@>3_MaKLkmO*e|&!*nHKH%XGi_L;lTy zzCT4a-p-d^xO>aJGB!B@x5qB8dlnw8nNr|(vn=F85bvESMo)4JeU4m|c&<9Dl|g!% z(u@S2=zE7u)>YjoWX+4;_rA1$lUeLS#oH-4Zc$CTKJ{#y#HOBY5jOVO)qSk>GWWDe zQ#U>R^^iyQ-JYwZ0w?*ugnYS`^3=u3_+Q7AOYDm{WRyjx-T7#xV_WaDcYf0et4CKH z-oD*%mgn{CKo1sqi<7^bYaI&Zem=U{{h8zFh2R4P%Uzl~lJ`!Faev|9;Q2INBrG;} z!&c!iZl~DR*PSH`&T}=Lo4UaF)VePr9?lFIZS^H*EVjQ6nPOMMc**|)b8g<8`qMEF zawBim_{2@SseJt7ZJqL&a>)X19-r;hi=$Rp1U-pmFPgK=SLx|fpIK+5ZH({SE>p1P zUdFm{HS5&Xm;S_*Nb`MIds4e1YSv^4cE9J%v(EP~QE*h6YQD|qg^}z#mfb5({h61! zs>W|(=V6PDtBxNio~E7uljGqdNtqUvUB6;y{dQf(ZgOiO)5Q3{OMUhTiaeTpQ~Q*( zZoSws=D2gO-xu~~rG!^AL<&A;*m(Pk@jfp17`@Ns!Poh+iyeMXi#q#y!z>HtD@=>R z?x{PjpS+Dx{FI2i-czQ9o2{j9H;cLT)tg0aj+9?&mn$Q-ueQ}S%P@Pn)Su;=i`p-* zbe$%ye&TG?**C`bdu{F50}4}5>(wmHxXj7U^X+RY+ph&oQ%}o%efsCh(Y4iVGa1=k z8K!fZi7;2270!Ge+-*C->0YSW<~*^_?~bwk?Q_53`~Jyx^~(3}ZSuJ!as|&{E_8En z`I)!o^Uae2$-DeKjd?j;8I-?DvCPvBILTBUnAkUqfr0VuvpbhmUhzcn9lUix&V~KI z$c){*w^gDwcAt(}%%i@&u>bO%5^nF){0bWy)5Fh1e)kgCS0%n6uk?JGkZIG##MZ#R zP!UVB7}vX%d0w9+7`M;)m2R0nUtT3(mfsid0QrZmWwz^h`nnm{^k1@K5?d0pQTy$s zYqoKA%q8Cra@y<Uu9GQ>N6bv_FdYAQxsm-$ZQ>41D@mE@H3vF3`7fDZ`+-UKL1@jz zdsq9G2F=_eEU~BY_E!1ifDJ2Ov^4Bn@Aytg-81P)BMY1MKiw+=oL?69S1)&t2tB?$ z)m!_`@)a8CtVMozy8$ZmNG$Y4+jb~P`aD;~T<%JRPcU=N1wn#2K;u6IjWgWJ-uq@^2)dO>0 zPWDc%@{!!6_ipy}ABPr}O27Qulf}=lRM`0N$GID>e?R*7>c-epJCAsU?R?o`?Xh9K z+%~s_1@B)qI`au{G>`o&WtwvA-p%!F*O-^xkeRl9V@D;E<|o}KPxYsfN&j2_eRb}L zkrH*--H?BS$wSof)cPgt$x9B&{P;DzGaW~L%UCY zuzhW!_~uU`hsx5nt1Du1zdcq=DBOPfL!Mu);^EB!GlNZ+e%)v{L2sh$f8}M}se5Z@ zoBs~+{+oI5m~w+Z1C!wHh3_u?>us%&D;1vJkvqNgg6HR_FBn(d5NiI^ySTt+xzfcq z&%XJlNX)-hUEiX5^r^4B8I#Oq_5LGn6H@w$V-D|BYE9la%`E!wLk*w#g61YZ*WFrr z<9ALFd9~y}yEwy-=4V$9eACrmbT4OJ^UuzI-%2ZO-vt@onOy#9eQo&c-wT$VI=j$) zXO@}h_uxx66(r8pYcoB6$Fb{3)fz3H$ctx^ADEQo=@&%%w{ce;j(UC2Ax2`uzWvNA z1Ua*}o87!qy_`v-^3Pdu&j}ZQs?Ch=UAITL>xwL1)r?0TbDEhvyQa@&{ql3d4nBitUPY}!%e%A;t^a-dzk5#B4=>&Dsu^L?tqh-v zS#M36vUIC@Z0Yj!IsZ?0J>g@s2$NqvQTt8oH*d=pA$6&pS(l7noO*hq^X1PMd3h2k z29N#(ePh`9dfodYQ;*xPzRRUGzln2AM_#t7*7bKAf*JG=-}@aKuU-+6&aN`WerI&< z@$aHcvv1TSv3MB@9^JY4PF(F1BjqzQn19^SO6$~UD!$=lkgxfmw9-j-_X9hp<=L9L zE)TZFUT`;eIU4XQWqsC08KX@f4SUX8c{?;d=l(5pqT$)zRTmdHSRR;QywboybKRes zr@NwN3GTW3Wqr5jk3V65-l&#v^=$QBxb)t&nKSRbU8wVR&i`!^mrIJKtnDc! zAofl1{tAaTz5P{=(>TPBe2A*zV4Y>?!<@=pR->U(?WR-sj9Kw!aT#}{fxJ6ryYu`E)nDB*D0_EI+d0vHy6%OTo_~DDA6{$UJNKsN<^!%~5f$q>-rix=ig~%l z`spm4my34J{%w2sa7RP=vt0gXLIR0?`rOx#W^S^oJDq!SPuap159U>WFPu5^4rit@ z(~Abb7iWt%M`-QyEx*Fxdq3dVk!zbD`}T1OMn1n6*z@~rv!L1v1ILf-bK?!`XFUF` zeg3uIjdEuTXWq$^Z*fPexfwqxia30ATF3A7ulujtG3GjUFnWFb5t^wbf3LQ{j>FDDh_R`-h{f@&ga?MxraOAN+cI-H_#73a~eNE*xpJ~^JJi+v4C36f&~aM6imd5olax<3D-45nJYx>(+E=LEZE@Ra zndw$Jf4|&}Eq;tI4H*k%+IHG(Vf=jHy%ww4!}3m%B(&2?^m16ClC2&?|OJZ zo2y{=gf1`rqn|!6E<7|jN%?V2uR=k{eyQE(6K8)A-s;0Kd#UrQk%M(+y|rnh>|_cJA^%17~KBs#~v*!$(*-iJS<>n2TIQN8B=f)(vc z6be`8YaMB?%KI?EB5SSI)xcOOmkB{v7-u-7syh`iigxXBJ9GMDvH6ysTKyucwqy0` zE_^#;*Le$k;Qe7&-<)Ru;MR+)zxXFC`f^OfB)oIJRC~74GSei3lQaK_-h1e&*VA;n5`ft5VH#>RVPQ{hNPj{f`P8 zVZV#tZS{RGzSd$|T>R>mkmI}*1_m?3@<|up-ES!S$af)6#wPsK{?ip7vTmGfyt&6c zbN^Yz&sN0(&)H2a?0?Mo{ApcY!qM$2dUKag_^9?q^vs{gpTbL?{mQ=H?s3uM;jh4p zdB=n&%$WPlU(I;2)Y|^Zfw#X+Kd~`l@vX|~62GsSZgF)<4ph?bnKMtXS)AH^*kpd&%A_9H}Wu^V$m**-L#?&G_JG@a^Q{ zt3uT^SuIghPG2q9<;QbF^TsYmPo+m8+oQT(KejTBW_QO@BW*gci?0H5zpjXm*0I{Qnvm_a6qL6!|}tPkBcat z$^W6JuVBJ%|J8R!iu!raYybI5ug4!OZZ&01|IX~Zv?O5CG{qkc{{~YmO(tqqzSN?u0FD=z>{M@w4lyzmg)x4SsOETN#)s+`t;tDCck@0t3+=2pWfMF{3pNRo%#Owd(z*Z_#~Z4;xjklJ#W@=h+%f? zz9h*#9c$Sxb8_=|d57p^GQWDiK}$`St-7bd`{@+vXI}r$+S=Cc?VDA6C~)c)g@PSv z>7_!GpB=qAt&U-j$xV0ZpZYOvx6SvQ;A_m*Jjg9R$vyw;hE!cs>BCH=E-}a7U9CI6 z{mkb{FXXoRr7Gs>fAv>R6SzPB?Y4AZ@2;J0`i!a9VcR`EZN16bYN>CF5|4{&FZH=2aD4gO z*ei;Xhi*(w<>?5Tc!p6&-^q^0mRoJ<`d8DpOkAJVzq zeA26LRXZLEGOs9dKFPGfT<)FQHI8Gy-=FJQ_dKrR1#3OyirMwx48Jz#7W; zbcT*{X07#=KQXHdJ_Wyxyu50I=N}Y66<>BFL zK^2u|YUN2Tlh3~XAH&DODP^Sj-#uZnL*d>8-3jGaIj%)5)9jHvH@V5})8z__kjOyc z%}ZuU?U{Ixvv6T@26OwA@ZXbbEUIy<{&lVVkbjW!3v| z$qx_t8w_plE-Ve7Fts|@CahrLv!)ZrOIUlqMP-ELwVM8X!MeqeTd{P-%fuIRr?~b1 zynIec%r?YxQPs{BI}W~>)4zPq(fG~(pB4UCxGZyKBj)!#&;T7A7z-=9qMC~@)V!%YJEzz=vLRNUsHTG%sskmR>CuBVMU{u zuis=?4dyX3oLJwt_R}6W7r`mJPRaj!6Zycl;<2Am+7F4~+45EM+t+P!zNyM`ck_{s z2hTnltIqcqd~&gpq2q`6(WfDPhFcp-x7=oyS$fy}-RH)c?x)tSf4f41W4nmlTTYE8 zm&Gfl8uDvuimbU8mtN#p5Ga|ie0lHQm2+Ru-^JgXEFf3^HU){Y zO|P?Btoc=TlVwSb=9D>%i>L797i}s}bN;yN{CVd|-M>WLgj1%M9r)Yz!06*!$rVx3 z6HU&%;JJ2b-h)|h`1UG>1k4o3`Lcb_29u+48*NN)-95_tV{-VHoA>{jNp*ix_I3=6Z=h9IOdtO_BQ=Fe|FOP$a9A!xw^kBE4TEs zl)B?wR@$nX_K^9?Q5Laa&*j%|85}ucyyjb_y2GTnrzs0_4~ACFe}67!@9Vq=B0Q|U z&EJkP%G@tmKmF~ly^}7Uzn?4PH%(^#SHHG-s;{T)-s8_cOW&MxeVy=^CI`{Fy@#1H5@nYv uaL8rNHa^RoknC~V?)#V1AH24{eDdn^(~o60x%IaQ8@CDWzx^I`5dr{^R{V7U literal 0 HcmV?d00001 diff --git a/bskyweb/cmd/bskyweb/server.go b/bskyweb/cmd/bskyweb/server.go index 790f211ee..5b8139626 100644 --- a/bskyweb/cmd/bskyweb/server.go +++ b/bskyweb/cmd/bskyweb/server.go @@ -308,7 +308,6 @@ func serve(cctx *cli.Context) error { e.GET("/settings/notifications/reposts-on-reposts", server.WebGeneric) e.GET("/settings/notifications/activity", server.WebGeneric) e.GET("/settings/notifications/miscellaneous", server.WebGeneric) - e.GET("/settings/app-icon", server.WebGeneric) e.GET("/sys/debug", server.WebGeneric) e.GET("/sys/debug-mod", server.WebGeneric) e.GET("/sys/log", server.WebGeneric) diff --git a/docs/build.md b/docs/build.md index fe95bb989..bcae2ece0 100644 --- a/docs/build.md +++ b/docs/build.md @@ -111,6 +111,8 @@ This is NOT required for app development but if you also want to develop the Blu - Start the docker daemon (on MacOS this entails starting the Docker Desktop app) - Launch a Postgres database on port 5432 - `cd packages/dev-env && pnpm start` + +Run the account with the AppView proxy DID passed in as an environment variable: `EXPO_PUBLIC_BLUESKY_PROXY_DID=did:plc:dw4kbjf5mn7nhenabiqpkyh3 yarn start` Then, when logging in or creating an account, point it to the localhost port of the devserver. diff --git a/package.json b/package.json index e26f1645b..d8f3dee7f 100644 --- a/package.json +++ b/package.json @@ -72,10 +72,10 @@ "icons:optimize": "svgo -f ./assets/icons" }, "dependencies": { - "@atproto/api": "^0.18.6", + "@atproto/api": "^0.18.8", "@bitdrift/react-native": "^0.6.8", "@braintree/sanitize-url": "^6.0.2", - "@bsky.app/alf": "^0.1.5", + "@bsky.app/alf": "^0.1.6", "@bsky.app/react-native-mmkv": "2.12.5", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", "@emoji-mart/react": "^1.1.1", @@ -132,43 +132,46 @@ "emoji-mart": "^5.5.2", "emoji-regex": "^10.4.0", "eventemitter3": "^5.0.1", - "expo": "^54.0.22", - "expo-application": "~7.0.7", - "expo-blur": "~15.0.7", - "expo-build-properties": "~1.0.9", - "expo-camera": "~17.0.9", - "expo-clipboard": "~8.0.7", - "expo-dev-client": "~6.0.16", - "expo-device": "~8.0.9", - "expo-file-system": "~19.0.17", - "expo-font": "~14.0.9", - "expo-haptics": "~15.0.7", - "expo-image": "~3.0.10", + "expo": "^54.0.27", + "expo-application": "~7.0.8", + "expo-blur": "~15.0.8", + "expo-build-properties": "~1.0.10", + "expo-camera": "~17.0.10", + "expo-clipboard": "~8.0.8", + "expo-contacts": "^15.0.10", + "expo-dev-client": "~6.0.20", + "expo-device": "~8.0.10", + "expo-file-system": "~19.0.20", + "expo-font": "~14.0.10", + "expo-haptics": "~15.0.8", + "expo-image": "~3.0.11", "expo-image-crop-tool": "^0.4.0", - "expo-image-manipulator": "~14.0.7", - "expo-image-picker": "~17.0.8", - "expo-intent-launcher": "~13.0.7", - "expo-keep-awake": "^15.0.7", - "expo-linear-gradient": "~15.0.7", - "expo-linking": "~8.0.8", - "expo-localization": "~17.0.7", - "expo-location": "~19.0.7", - "expo-media-library": "~18.2.0", - "expo-notifications": "~0.32.12", - "expo-screen-orientation": "~9.0.7", - "expo-sharing": "~14.0.7", - "expo-splash-screen": "~31.0.10", - "expo-system-ui": "~6.0.8", - "expo-task-manager": "~14.0.8", - "expo-updates": "~29.0.12", - "expo-video": "~3.0.13", - "expo-web-browser": "~15.0.9", + "expo-image-manipulator": "~14.0.8", + "expo-image-picker": "~17.0.9", + "expo-intent-launcher": "~13.0.8", + "expo-keep-awake": "~15.0.8", + "expo-linear-gradient": "~15.0.8", + "expo-linking": "~8.0.10", + "expo-localization": "~17.0.8", + "expo-location": "~19.0.8", + "expo-media-library": "~18.2.1", + "expo-notifications": "~0.32.14", + "expo-screen-orientation": "~9.0.8", + "expo-sharing": "~14.0.8", + "expo-sms": "^14.0.7", + "expo-splash-screen": "~31.0.12", + "expo-system-ui": "~6.0.9", + "expo-task-manager": "~14.0.9", + "expo-updates": "~29.0.14", + "expo-video": "~3.0.15", + "expo-web-browser": "~15.0.10", "fast-text-encoding": "^1.0.6", "history": "^5.3.0", "hls.js": "^1.6.2", "js-sha256": "^0.9.0", "jwt-decode": "^4.0.0", "lande": "^1.0.10", + "libphonenumber-js": "^1.12.31", "lodash.chunk": "^4.2.0", "lodash.debounce": "^4.0.8", "lodash.isequal": "^4.5.0", @@ -222,7 +225,7 @@ "zod": "^3.20.2" }, "devDependencies": { - "@atproto/dev-env": "^0.3.193", + "@atproto/dev-env": "^0.3.196", "@babel/core": "^7.26.0", "@babel/preset-env": "^7.26.0", "@babel/runtime": "^7.26.0", @@ -264,7 +267,7 @@ "husky": "^8.0.3", "is-ci": "^3.0.1", "jest": "^29.7.0", - "jest-expo": "^54.0.14", + "jest-expo": "~54.0.14", "jest-junit": "^16.0.0", "lint-staged": "^13.2.3", "lockfile-lint": "^4.14.0", diff --git a/patches/expo-haptics+15.0.7.patch b/patches/expo-haptics+15.0.8.patch similarity index 100% rename from patches/expo-haptics+15.0.7.patch rename to patches/expo-haptics+15.0.8.patch diff --git a/patches/expo-haptics+15.0.7.patch.md b/patches/expo-haptics+15.0.8.patch.md similarity index 100% rename from patches/expo-haptics+15.0.7.patch.md rename to patches/expo-haptics+15.0.8.patch.md diff --git a/patches/expo-media-library+18.2.0.patch b/patches/expo-media-library+18.2.1.patch similarity index 100% rename from patches/expo-media-library+18.2.0.patch rename to patches/expo-media-library+18.2.1.patch diff --git a/patches/expo-modules-core+3.0.24.patch b/patches/expo-modules-core+3.0.28.patch similarity index 100% rename from patches/expo-modules-core+3.0.24.patch rename to patches/expo-modules-core+3.0.28.patch diff --git a/patches/expo-modules-core+3.0.24.patch.md b/patches/expo-modules-core+3.0.28.patch.md similarity index 100% rename from patches/expo-modules-core+3.0.24.patch.md rename to patches/expo-modules-core+3.0.28.patch.md diff --git a/patches/expo-notifications+0.32.12.patch b/patches/expo-notifications+0.32.14.patch similarity index 100% rename from patches/expo-notifications+0.32.12.patch rename to patches/expo-notifications+0.32.14.patch diff --git a/patches/expo-notifications+0.32.12.patch.md b/patches/expo-notifications+0.32.14.patch.md similarity index 100% rename from patches/expo-notifications+0.32.12.patch.md rename to patches/expo-notifications+0.32.14.patch.md diff --git a/patches/expo-updates+29.0.12.patch b/patches/expo-updates+29.0.15.patch similarity index 51% rename from patches/expo-updates+29.0.12.patch rename to patches/expo-updates+29.0.15.patch index 7f198e96e..06841f0be 100644 --- a/patches/expo-updates+29.0.12.patch +++ b/patches/expo-updates+29.0.15.patch @@ -1,24 +1,3 @@ -diff --git a/node_modules/expo-updates/android/src/main/java/expo/modules/updates/loader/LoaderTask.kt b/node_modules/expo-updates/android/src/main/java/expo/modules/updates/loader/LoaderTask.kt -index e9a8e3d..3c684e0 100644 ---- a/node_modules/expo-updates/android/src/main/java/expo/modules/updates/loader/LoaderTask.kt -+++ b/node_modules/expo-updates/android/src/main/java/expo/modules/updates/loader/LoaderTask.kt -@@ -296,14 +296,13 @@ class LoaderTask( - ) { - try { - val embeddedLoader = EmbeddedLoader(context, configuration, logger, database, directory) -- val result = embeddedLoader.load { updateResponse -> -+ embeddedLoader.load { _ -> - Loader.OnUpdateResponseLoadedResult(shouldDownloadManifestIfPresentInResponse = true) - } -- launcher.launch(database) - } catch (e: Exception) { - logger.error("Unexpected error copying embedded update", e, UpdatesErrorCode.Unknown) -- launcher.launch(database) - } -+ launcher.launch(database) - } else { - launcher.launch(database) - } diff --git a/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift b/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift index 68086bd..78c7761 100644 --- a/node_modules/expo-updates/ios/EXUpdates/Update/ExpoUpdatesUpdate.swift diff --git a/patches/expo-updates+29.0.12.patch.md b/patches/expo-updates+29.0.15.patch.md similarity index 100% rename from patches/expo-updates+29.0.12.patch.md rename to patches/expo-updates+29.0.15.patch.md diff --git a/src/Navigation.tsx b/src/Navigation.tsx index fa33a9d56..3e68bd07d 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -18,7 +18,9 @@ import { } from '@react-navigation/native' import {timeout} from '#/lib/async/timeout' +import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher' import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle' +import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import { getNotificationPayload, type NotificationPayload, @@ -45,10 +47,12 @@ import {logger} from '#/logger' import {isNative, isWeb} from '#/platform/detection' import {useUnreadNotifications} from '#/state/queries/notifications/unread' import {useSession} from '#/state/session' +import {useLoggedOutViewControls} from '#/state/shell/logged-out' import { shouldRequestEmailConfirmation, snoozeEmailConfirmationPrompt, } from '#/state/shell/reminders' +import {useCloseAllActiveElements} from '#/state/util' import {CommunityGuidelinesScreen} from '#/view/screens/CommunityGuidelines' import {CopyrightPolicyScreen} from '#/view/screens/CopyrightPolicy' import {DebugModScreen} from '#/view/screens/DebugMod' @@ -71,6 +75,7 @@ import {BottomBar} from '#/view/shell/bottom-bar/BottomBar' import {createNativeStackNavigatorWithAuth} from '#/view/shell/createNativeStackNavigatorWithAuth' import {BookmarksScreen} from '#/screens/Bookmarks' import {SharedPreferencesTesterScreen} from '#/screens/E2E/SharedPreferencesTesterScreen' +import {FindContactsFlowScreen} from '#/screens/FindContactsFlowScreen' import HashtagScreen from '#/screens/Hashtag' import {LogScreen} from '#/screens/Log' import {MessagesScreen} from '#/screens/Messages/ChatList' @@ -102,6 +107,7 @@ import {AppIconSettingsScreen} from '#/screens/Settings/AppIconSettings' import {AppPasswordsScreen} from '#/screens/Settings/AppPasswords' import {ContentAndMediaSettingsScreen} from '#/screens/Settings/ContentAndMediaSettings' import {ExternalMediaPreferencesScreen} from '#/screens/Settings/ExternalMediaPreferences' +import {FindContactsSettingsScreen} from '#/screens/Settings/FindContactsSettings' import {FollowingFeedPreferencesScreen} from '#/screens/Settings/FollowingFeedPreferences' import {InterestsSettingsScreen} from '#/screens/Settings/InterestsSettings' import {LanguageSettingsScreen} from '#/screens/Settings/LanguageSettings' @@ -134,10 +140,6 @@ import { } from '#/components/dialogs/EmailDialog' import {router} from '#/routes' import {Referrer} from '../modules/expo-bluesky-swiss-army' -import {useAccountSwitcher} from './lib/hooks/useAccountSwitcher' -import {useNonReactiveCallback} from './lib/hooks/useNonReactiveCallback' -import {useLoggedOutViewControls} from './state/shell/logged-out' -import {useCloseAllActiveElements} from './state/util' const navigationRef = createNavigationContainerRef() @@ -416,6 +418,14 @@ function commonScreens(Stack: typeof Flat, unreadCountLabel?: string) { requireAuth: true, }} /> + FindContactsSettingsScreen} + options={{ + title: title(msg`Find Contacts`), + requireAuth: true, + }} + /> NotificationSettingsScreen} @@ -609,6 +619,15 @@ function commonScreens(Stack: typeof Flat, unreadCountLabel?: string) { requireAuth: true, }} /> + FindContactsFlowScreen} + options={{ + title: title(msg`Find Contacts`), + requireAuth: true, + gestureEnabled: false, + }} + /> ) } diff --git a/src/components/InternationalPhoneCodeSelect.tsx b/src/components/InternationalPhoneCodeSelect.tsx index f42f4a21a..0cfd4d6b5 100644 --- a/src/components/InternationalPhoneCodeSelect.tsx +++ b/src/components/InternationalPhoneCodeSelect.tsx @@ -4,6 +4,7 @@ import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import { + type CountryCode, getDefaultCountry, INTERNATIONAL_TELEPHONE_CODES, } from '#/lib/international-telephone-codes' @@ -23,8 +24,8 @@ export function InternationalPhoneCodeSelect({ value, onChange, }: { - value?: string - onChange: (value: string) => void + value?: CountryCode + onChange: (value: CountryCode) => void }) { const {_, i18n} = useLingui() const location = useGeolocation() @@ -62,7 +63,7 @@ export function InternationalPhoneCodeSelect({ }, [value, items]) return ( - + void}> {selected => ( diff --git a/src/components/Layout/Header/index.tsx b/src/components/Layout/Header/index.tsx index 762223fc3..59c360fa1 100644 --- a/src/components/Layout/Header/index.tsx +++ b/src/components/Layout/Header/index.tsx @@ -38,7 +38,7 @@ export function Outer({ }: { children: React.ReactNode noBottomBorder?: boolean - headerRef?: React.MutableRefObject + headerRef?: React.RefObject sticky?: boolean }) { const t = useTheme() @@ -129,6 +129,7 @@ export function BackButton({onPress, style, ...props}: Partial) { size="small" variant="ghost" color="secondary" + shape="round" onPress={onPressBack} hitSlop={HITSLOP_30} style={[ @@ -183,7 +184,7 @@ export function TitleText({ +}) { const t = useTheme() const handle = sanitizeHandle(profile.handle, '@') return ( {handle} diff --git a/src/components/ProgressGuide/FollowDialog.tsx b/src/components/ProgressGuide/FollowDialog.tsx index 4d1d27d15..d1017c46f 100644 --- a/src/components/ProgressGuide/FollowDialog.tsx +++ b/src/components/ProgressGuide/FollowDialog.tsx @@ -31,7 +31,7 @@ import { import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {useInteractionState} from '#/components/hooks/useInteractionState' -import {MagnifyingGlass2_Stroke2_Corner0_Rounded as SearchIcon} from '#/components/icons/MagnifyingGlass2' +import {MagnifyingGlass_Stroke2_Corner0_Rounded as SearchIcon} from '#/components/icons/MagnifyingGlass' import {PersonGroup_Stroke2_Corner2_Rounded as PersonGroupIcon} from '#/components/icons/Person' import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' import {boostInterests, InterestTabs} from '#/components/InterestTabs' diff --git a/src/components/RichTextTag.tsx b/src/components/RichTextTag.tsx index a24ebb15c..4f1af6e1e 100644 --- a/src/components/RichTextTag.tsx +++ b/src/components/RichTextTag.tsx @@ -12,7 +12,7 @@ import { useRemoveMutedWordsMutation, useUpsertMutedWordsMutation, } from '#/state/queries/preferences' -import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' +import {MagnifyingGlass_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass' import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' import {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person' import { diff --git a/src/components/SearchError.tsx b/src/components/SearchError.tsx index d478ac885..4c9b40261 100644 --- a/src/components/SearchError.tsx +++ b/src/components/SearchError.tsx @@ -1,10 +1,9 @@ import {View} from 'react-native' -import {usePalette} from '#/lib/hooks/usePalette' -import {atoms as a, useBreakpoints} from '#/alf' +import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times' import * as Layout from '#/components/Layout' import {Text} from '#/components/Typography' -import {TimesLarge_Stroke2_Corner0_Rounded} from './icons/Times' export function SearchError({ title, @@ -14,7 +13,7 @@ export function SearchError({ children?: React.ReactNode }) { const {gtMobile} = useBreakpoints() - const pal = usePalette('default') + const t = useTheme() return ( @@ -27,7 +26,7 @@ export function SearchError({ paddingVertical: 150, }, ]}> - + + + { + logger.metric('contacts:nux:bannerPressed', {}) + }} + style={[ + a.w_full, + a.rounded_xl, + a.curve_continuous, + a.overflow_hidden, + ]}> + + + + + Import contacts to find your friends + + + + + + + + ) +} +function useInternalState() { + const {nux} = useNux(Nux.FindContactsDismissibleBanner) + const {mutate: save, variables} = useSaveNux() + const hidden = !!variables + + const visible = useMemo(() => { + if (isWeb) return false + if (hidden) return false + if (nux && nux.completed) return false + return true + }, [hidden, nux]) + + const close = () => { + save({ + id: Nux.FindContactsDismissibleBanner, + completed: true, + data: undefined, + }) + logger.metric('contacts:nux:bannerDismissed', {}) + } + + return {visible, close} +} diff --git a/src/components/contacts/FindContactsFlow.tsx b/src/components/contacts/FindContactsFlow.tsx new file mode 100644 index 000000000..66f52bbd0 --- /dev/null +++ b/src/components/contacts/FindContactsFlow.tsx @@ -0,0 +1,56 @@ +import {GetContacts} from './screens/GetContacts' +import {PhoneInput} from './screens/PhoneInput' +import {VerifyNumber} from './screens/VerifyNumber' +import {ViewMatches} from './screens/ViewMatches' +import {type Action, FindContactsGoBackContext, type State} from './state' + +export function FindContactsFlow({ + state, + dispatch, + onBack, + onCancel, + context = 'Standalone', +}: { + state: State + dispatch: React.ActionDispatch<[Action]> + onBack?: () => void + onCancel: () => void + context: 'Onboarding' | 'Standalone' +}) { + return ( + + {state.step === '1: phone input' && ( + + )} + {state.step === '2: verify number' && ( + + )} + {state.step === '3: get contacts' && ( + + )} + {state.step === '4: view matches' && ( + + )} + + ) +} diff --git a/src/components/contacts/FindContactsFlow.web.tsx b/src/components/contacts/FindContactsFlow.web.tsx new file mode 100644 index 000000000..9def7df16 --- /dev/null +++ b/src/components/contacts/FindContactsFlow.web.tsx @@ -0,0 +1,3 @@ +export function FindContactsFlow() { + throw new Error('FindContactsFlow is not available on web') +} diff --git a/src/components/contacts/components/HeroImage.tsx b/src/components/contacts/components/HeroImage.tsx new file mode 100644 index 000000000..5e710fd9a --- /dev/null +++ b/src/components/contacts/components/HeroImage.tsx @@ -0,0 +1,33 @@ +import {View} from 'react-native' +import {Image} from 'expo-image' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {atoms as a, useTheme} from '#/alf' + +export function ContactsHeroImage() { + const t = useTheme() + const {_} = useLingui() + + return ( + + {_( + + ) +} diff --git a/src/components/contacts/components/InviteInfo.tsx b/src/components/contacts/components/InviteInfo.tsx new file mode 100644 index 000000000..54100a2a0 --- /dev/null +++ b/src/components/contacts/components/InviteInfo.tsx @@ -0,0 +1,85 @@ +import {type StyleProp, type TextStyle} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {HITSLOP_20} from '#/lib/constants' +import {android, atoms as a} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import * as Dialog from '#/components/Dialog' +import {CircleInfo_Stroke2_Corner0_Rounded as InfoIcon} from '#/components/icons/CircleInfo' +import {Text} from '#/components/Typography' + +export function InviteInfo({ + iconStyle, + iconOffset = 0, +}: { + iconStyle: StyleProp + /** + * Adjust the vertical position of the icon via `translateY` + * + * @platform android + */ + iconOffset?: number +}) { + const {_} = useLingui() + const control = Dialog.useDialogControl() + + const style = [a.text_md, a.leading_snug, a.mt_xs] + + return ( + <> + + + + + + + Invite Friends + + + + It looks like some of your contacts have not tried to find you + here yet. You can personally invite them by customizing a draft + message we will provide. + + + + How it works: + + + • Choose who to invite + + + • Personalize the message + + + • Send the message from your phone + + + •{' '} + + We don't store your friends' phone numbers or send any messages + + + + + + + + ) +} diff --git a/src/components/contacts/components/OTPInput.tsx b/src/components/contacts/components/OTPInput.tsx new file mode 100644 index 000000000..da68bf8d5 --- /dev/null +++ b/src/components/contacts/components/OTPInput.tsx @@ -0,0 +1,143 @@ +import {useRef, useState} from 'react' +import { + Pressable, + TextInput, + type TextInputSelectionChangeEvent, + View, +} from 'react-native' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {mergeRefs} from '#/lib/merge-refs' +import {isAndroid, isIOS} from '#/platform/detection' +import {atoms as a, ios, platform, useTheme} from '#/alf' +import {useInteractionState} from '#/components/hooks/useInteractionState' +import {Text} from '#/components/Typography' + +export function OTPInput({ + label, + value, + onChange, + ref, + numberOfDigits = 6, + onComplete, +}: { + label: string + value: string + onChange: (text: string) => void + ref?: React.Ref + numberOfDigits?: number + onComplete?: (code: string) => void +}) { + const t = useTheme() + const {_} = useLingui() + const innerRef = useRef(null) + const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() + const [selection, setSelection] = useState({start: 0, end: 0}) + + const onChangeText = (text: string) => { + // only numbers + text = text.replace(/[^0-9]/g, '') + text = text.slice(0, numberOfDigits) + onChange(text) + if (text.length === numberOfDigits) { + onComplete?.(text) + innerRef.current?.blur() + } + } + + const onSelectionChange = (evt: TextInputSelectionChangeEvent) => { + setSelection(evt.nativeEvent.selection) + } + + return ( + { + innerRef.current?.focus() + innerRef.current?.clear() + }}> + + {[...value.padEnd(numberOfDigits, ' ')].map((digit, index) => { + const selected = focused + ? selection.start === selection.end + ? selection.start === index + : index >= selection.start && index < selection.end + : false + + return ( + + + {digit} + + + ) + })} + + setTimeout(() => innerRef.current?.focus(), 100))} + autoFocus={isAndroid} + accessible + accessibilityLabel={label} + accessibilityHint="" + accessibilityRole="text" + ref={mergeRefs(ref ? [ref, innerRef] : [innerRef])} + value={value} + onChangeText={onChangeText} + onSelectionChange={onSelectionChange} + keyboardAppearance={t.scheme} + inputMode="numeric" + keyboardType="number-pad" + textContentType="oneTimeCode" + autoComplete={platform({ + android: 'sms-otp', + ios: 'one-time-code', + })} + onFocus={onFocus} + onBlur={onBlur} + maxLength={numberOfDigits} + style={[ + a.absolute, + a.inset_0, + // roughly vibe align the characters + // with the visible ones so that + // moving the caret via long press + // still kinda sorta works + { + fontVariant: ['tabular-nums'], + textAlignVertical: 'center', + letterSpacing: 24, + fontSize: 60, + paddingLeft: 6, + }, + platform({ + // completely transparent inputs on iOS cannot be pasted into + ios: {opacity: 0.02, color: 'transparent'}, + android: {opacity: 0}, + }), + ]} + caretHidden={isIOS} + clearTextOnFocus + /> + + ) +} diff --git a/src/components/contacts/contacts.ts b/src/components/contacts/contacts.ts new file mode 100644 index 000000000..205c2ccb4 --- /dev/null +++ b/src/components/contacts/contacts.ts @@ -0,0 +1,100 @@ +import {type AppBskyContactDefs} from '@atproto/api' + +import {type CountryCode} from '#/lib/international-telephone-codes' +import {normalizePhoneNumber} from './phone-number' +import {type Contact, type Match} from './state' + +/** + * Filters out contacts that do not have any associated phone numbers, + * as well as businesses + */ +export function contactsWithPhoneNumbersOnly(contacts: Contact[]) { + return contacts.filter( + contact => + contact.phoneNumbers && + contact.phoneNumbers.length > 0 && + contact.contactType !== 'company', + ) +} + +/** + * Takes the raw contact book and returns a plain list of numbers in E.164 format, along + * with a mapping to retrieve the contact ID when we get the results back. + * + * `countryCode` is used as a fallback for local numbers that don't have a country code associated with them. + * I'm making the assumption that most local numbers in someone's phone book will be the same as theirs. + */ +export function normalizeContactBook( + contacts: Contact[], + countryCode: CountryCode, + ownNumber: string, +): { + phoneNumbers: string[] + indexToContactId: Map +} { + const phoneNumbers: string[] = [] + const indexToContactId = new Map() + + for (const contact of contacts) { + for (const number of contact.phoneNumbers ?? []) { + let rawNumber: string + + if (number.number) { + rawNumber = number.number + } else if (number.digits) { + rawNumber = number.digits + } else { + continue + } + + const normalized = normalizePhoneNumber( + rawNumber, + number.countryCode, + countryCode, + ) + if (normalized === null) continue + + // skip if it's your own number + if (normalized === ownNumber) continue + + phoneNumbers.push(normalized) + indexToContactId.set(phoneNumbers.length - 1, contact.id) + } + } + + return { + phoneNumbers, + indexToContactId, + } +} + +export function filterMatchedNumbers( + contacts: Contact[], + results: AppBskyContactDefs.MatchAndContactIndex[], + mapping: Map, +) { + const filteredIds = new Set() + + for (const result of results) { + const id = mapping.get(result.contactIndex) + if (id !== undefined) { + filteredIds.add(id) + } + } + + return contacts.filter(contact => !filteredIds.has(contact.id)) +} + +export function getMatchedContacts( + contacts: Contact[], + results: AppBskyContactDefs.MatchAndContactIndex[], + mapping: Map, +): Array { + const contactsById = new Map(contacts.map(c => [c.id, c])) + + return results.map(result => { + const id = mapping.get(result.contactIndex) + const contact = id !== undefined ? contactsById.get(id) : undefined + return {profile: result.match, contact} + }) +} diff --git a/src/components/contacts/country-allowlist.ts b/src/components/contacts/country-allowlist.ts new file mode 100644 index 000000000..97d3d4458 --- /dev/null +++ b/src/components/contacts/country-allowlist.ts @@ -0,0 +1,37 @@ +import {type CountryCode} from '#/lib/international-telephone-codes' +import {IS_DEV} from '#/env' +import {useGeolocation} from '#/geolocation' + +const FIND_CONTACTS_FEATURE_COUNTRY_ALLOWLIST = [ + 'US', + 'GB', + 'JP', + 'CA', + 'DE', + 'FR', + 'ES', + 'BR', + 'KR', + 'NL', + 'AU', + 'SE', + 'IT', +] satisfies CountryCode[] as string[] + +export function isFindContactsFeatureEnabled(countryCode: string): boolean { + return FIND_CONTACTS_FEATURE_COUNTRY_ALLOWLIST.includes( + countryCode.toUpperCase(), + ) +} + +export function useIsFindContactsFeatureEnabledBasedOnGeolocation() { + const location = useGeolocation() + + if (IS_DEV) return true + + // they can try, by they'll need a phone number + // from one of the allowlisted countries + if (!location.countryCode) return true + + return isFindContactsFeatureEnabled(location.countryCode) +} diff --git a/src/components/contacts/phone-number.ts b/src/components/contacts/phone-number.ts new file mode 100644 index 000000000..9510a614c --- /dev/null +++ b/src/components/contacts/phone-number.ts @@ -0,0 +1,162 @@ +import {t} from '@lingui/macro' +import { + isSupportedCountry, + ParseError, + parsePhoneNumber, + parsePhoneNumberWithError, + type PhoneNumber, +} from 'libphonenumber-js/max' + +import {type CountryCode} from '#/lib/international-telephone-codes' + +/** + * Intended for after the user has finished inputting their phone number. + */ +export function processPhoneNumber( + number: string, + country: CountryCode, +): + | { + valid: true + formatted: string + countryCode: CountryCode + } + | { + valid: false + reason?: string + } { + try { + const phoneNumber = parsePhoneNumberWithError(number, { + defaultCountry: country, + }) + if (!phoneNumber.isValid()) { + return {valid: false, reason: t`Invalid phone number`} + } + const type = phoneNumber.getType() + if ( + type !== 'MOBILE' && + type !== 'FIXED_LINE_OR_MOBILE' && + type !== 'PERSONAL_NUMBER' + ) { + return { + valid: false, + reason: t`Number should be a mobile number`, + } + } + let countryCode = country + if (phoneNumber.country && phoneNumber.country !== country) { + if (phoneNumber.country === 'AC' || phoneNumber.country === 'TA') { + countryCode = 'SH' + } else { + countryCode = phoneNumber.country + } + } + return { + valid: true, + formatted: formatE164lWithoutCountryCode(phoneNumber), + countryCode, + } + } catch (error) { + if (error instanceof ParseError) { + return {valid: false, reason: error.message} + } else { + return {valid: false} + } + } +} + +/** + * Format a phone number as the international format with the prefix + * removed. + */ +function formatE164lWithoutCountryCode(phoneNumber: PhoneNumber) { + const intl = phoneNumber.format('E.164') + const prefix = '+' + phoneNumber.countryCallingCode + return intl.replace(prefix, '').trim() +} + +/** + * Takes a country code and a prefix-less phone number and constructs a full phone number. + * + * Does not have nice error handling - if you're unsure if the number is valid, use + * `processPhoneNumber` instead + */ +export function constructFullPhoneNumber( + countryCode: CountryCode, + phoneNumber: string, +) { + const result = parsePhoneNumber(phoneNumber, {defaultCountry: countryCode}) + if (!result.isValid()) + throw new Error('Invalid phone number passed to constructFullPhoneNumber') + return result.format('E.164') +} + +/** + * Takes a phone number and applies human-readable formatting. Do not sent to the API - they + * expect E.164 format. + */ +export function prettyPhoneNumber(phoneNumber: string) { + const result = parsePhoneNumber(phoneNumber) + return result.formatNational() +} + +/** + * Attempts to parse a phone number from a string, and returns the country code + * and the rest of the number if possible. If the number is invalid, returns undefined. + */ +export function getCountryCodeFromPastedNumber( + text: string, +): {countryCode: CountryCode; rest: string} | undefined { + try { + const phoneNumber = parsePhoneNumber(text) + if (!phoneNumber.isValid()) { + return undefined + } + const countryCode = phoneNumber.country + // we don't have AC and TA in our dropdown - see `#/lib/international-telephone-codes` + if (countryCode && countryCode !== 'AC' && countryCode !== 'TA') { + return { + countryCode, + rest: formatE164lWithoutCountryCode(phoneNumber), + } + } else { + return undefined + } + } catch (error) { + return undefined + } +} + +/** + * Normalizes a phone number into E.164 format + */ +export function normalizePhoneNumber( + rawNumber: string, + countryCode: string | undefined, + fallbackCountryCode: CountryCode, +): string | null { + try { + const result = parsePhoneNumber(rawNumber, { + defaultCountry: + countryCode && isSupportedCountry(countryCode) + ? countryCode + : fallbackCountryCode, + }) + + if (!result.isValid()) return null + + const type = result.getType() + if ( + type !== 'MOBILE' && + type !== 'FIXED_LINE_OR_MOBILE' && + type !== 'PERSONAL_NUMBER' + ) { + return null + } + + return result.format('E.164') + } catch (error) { + console.log('Failed to normalize phone number:', error) + return null + } +} diff --git a/src/components/contacts/screens/GetContacts.tsx b/src/components/contacts/screens/GetContacts.tsx new file mode 100644 index 000000000..7057819e1 --- /dev/null +++ b/src/components/contacts/screens/GetContacts.tsx @@ -0,0 +1,290 @@ +import {Alert, View} from 'react-native' +import {useSafeAreaInsets} from 'react-native-safe-area-context' +import * as Contacts from 'expo-contacts' +import {AppBskyContactImportContacts} from '@atproto/api' +import {msg, t, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useMutation, useQueryClient} from '@tanstack/react-query' + +import {cleanError, isNetworkError} from '#/lib/strings/errors' +import {logger} from '#/logger' +import {findContactsStatusQueryKey} from '#/state/queries/find-contacts' +import {useAgent} from '#/state/session' +import {atoms as a, ios, tokens, useGutters} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import * as Layout from '#/components/Layout' +import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' +import {Text} from '#/components/Typography' +import { + contactsWithPhoneNumbersOnly, + filterMatchedNumbers, + getMatchedContacts, + normalizeContactBook, +} from '../contacts' +import {constructFullPhoneNumber} from '../phone-number' +import {type Action, type State} from '../state' + +const MAX_UPLOAD_COUNT = 1000 + +export function GetContacts({ + state, + dispatch, + onCancel, + context, +}: { + state: Extract + dispatch: React.ActionDispatch<[Action]> + onCancel: () => void + context: 'Onboarding' | 'Standalone' +}) { + const {_} = useLingui() + const agent = useAgent() + const insets = useSafeAreaInsets() + const gutters = useGutters([0, 'wide']) + const queryClient = useQueryClient() + + const {mutate: uploadContacts, isPending: isUploadPending} = useMutation({ + mutationFn: async (contacts: Contacts.ExistingContact[]) => { + const {phoneNumbers, indexToContactId} = normalizeContactBook( + contacts, + state.phoneCountryCode, + constructFullPhoneNumber(state.phoneCountryCode, state.phoneNumber), + ) + + if (phoneNumbers.length > 0) { + const res = await agent.app.bsky.contact.importContacts({ + token: state.token, + contacts: phoneNumbers.slice(0, MAX_UPLOAD_COUNT), + }) + + return { + matches: res.data.matchesAndContactIndexes, + indexToContactId, + } + } else { + return { + matches: [], + indexToContactId, + } + } + }, + onSuccess: (result, contacts) => { + if (context === 'Onboarding') { + logger.metric('onboarding:contacts:contactsShared', {}) + } + if (result.matches.length > 0) { + logger.metric('contacts:import:success', { + contactCount: contacts.length, + matchCount: result.matches.length, + entryPoint: context, + }) + } else { + logger.metric('contacts:import:failure', { + reason: 'noValidNumbers', + entryPoint: context, + }) + } + dispatch({ + type: 'SYNC_CONTACTS_SUCCESS', + payload: { + matches: getMatchedContacts( + contacts, + result.matches, + result.indexToContactId, + ), + contacts: filterMatchedNumbers( + contacts, + result.matches, + result.indexToContactId, + ), + }, + }) + queryClient.invalidateQueries({ + queryKey: findContactsStatusQueryKey, + }) + }, + onError: err => { + logger.metric('contacts:import:failure', { + reason: isNetworkError(err) ? 'networkError' : 'unknown', + entryPoint: context, + }) + if (isNetworkError(err)) { + Toast.show( + _( + msg`There was a problem with your internet connection, please try again`, + ), + {type: 'error'}, + ) + } else if ( + err instanceof AppBskyContactImportContacts.TooManyContactsError + ) { + Toast.show( + _( + msg`Too many contacts - you've exceeded the number of contacts you can import to find your friends`, + ), + {type: 'error'}, + ) + } else if ( + err instanceof AppBskyContactImportContacts.InvalidTokenError + ) { + Toast.show( + _( + msg`Could not upload contacts. You need to re-verify your phone number to proceed`, + ), + {type: 'error'}, + ) + } else { + logger.error('Error uploading contacts', {safeMessage: err}) + Toast.show(_(msg`Could not upload contacts. ${cleanError(err)}`), { + type: 'error', + }) + } + }, + }) + + const {mutate: getContacts, isPending: isGetContactsPending} = useMutation({ + mutationFn: async () => { + let permissions = await Contacts.getPermissionsAsync() + + if (!permissions.granted && permissions.canAskAgain) { + permissions = await Contacts.requestPermissionsAsync() + } + + logger.metric('contacts:permission:request', { + status: permissions.granted ? 'granted' : 'denied', + accessLevelIOS: ios(permissions.accessPrivileges), + }) + + if (!permissions.granted) { + throw new PermissionDeniedError() + } + + const contacts = await Contacts.getContactsAsync({ + fields: [ + Contacts.Fields.FirstName, + Contacts.Fields.LastName, + Contacts.Fields.PhoneNumbers, + Contacts.Fields.Image, + ], + }) + + return contactsWithPhoneNumbersOnly(contacts.data) + }, + onSuccess: contacts => { + dispatch({ + type: 'GET_CONTACTS_SUCCESS', + payload: {contacts}, + }) + uploadContacts(contacts) + }, + onError: err => { + if (err instanceof PermissionDeniedError) { + showPermissionDeniedAlert() + } else { + logger.error('Error getting contacts', {safeMessage: err}) + } + }, + }) + + const isPending = isUploadPending || isGetContactsPending + + const style = [a.text_md, a.leading_snug, a.mt_md] + + return ( + + + + Share your contacts to find friends + + + + Bluesky helps friends find each other by creating an encoded digital + fingerprint, called a "hash," and then looking for matching hashes. + + + + • We never store plain phone numbers + + + • We delete hashes after matches are made + + + • We only suggest follows if both people consent + + + • You can always opt out and delete your data + + + + We apply the highest privacy standards, and never share or sell your + contact information. + + + + + + + I consent to Bluesky using my contacts for mutual friend discovery + and to retain hashed data for matching until I opt out. + + + + + + + ) +} + +class PermissionDeniedError extends Error { + constructor() { + super('Permission denied') + } +} + +function showPermissionDeniedAlert() { + Alert.alert( + t`You've denied access to your contacts`, + t`You'll need to go to the System Settings for Bluesky and give permission if you want to use this feature.`, + [ + { + text: t`OK`, + style: 'default', + }, + ], + ) +} diff --git a/src/components/contacts/screens/PhoneInput.tsx b/src/components/contacts/screens/PhoneInput.tsx new file mode 100644 index 000000000..0e08c0965 --- /dev/null +++ b/src/components/contacts/screens/PhoneInput.tsx @@ -0,0 +1,326 @@ +import {useState} from 'react' +import {Keyboard, View} from 'react-native' +import {KeyboardAvoidingView} from 'react-native-keyboard-controller' +import {useSafeAreaInsets} from 'react-native-safe-area-context' +import {AppBskyContactStartPhoneVerification} from '@atproto/api' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useMutation} from '@tanstack/react-query' + +import { + type CountryCode, + getDefaultCountry, +} from '#/lib/international-telephone-codes' +import {cleanError, isNetworkError} from '#/lib/strings/errors' +import {logger} from '#/logger' +import {useAgent} from '#/state/session' +import {OnboardingPosition} from '#/screens/Onboarding/Layout' +import { + android, + atoms as a, + platform, + tokens, + useGutters, + useTheme, +} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import * as TextField from '#/components/forms/TextField' +import {InternationalPhoneCodeSelect} from '#/components/InternationalPhoneCodeSelect' +import * as Layout from '#/components/Layout' +import {InlineLinkText} from '#/components/Link' +import {Loader} from '#/components/Loader' +import {Text} from '#/components/Typography' +import {useGeolocation} from '#/geolocation' +import {isFindContactsFeatureEnabled} from '../country-allowlist' +import { + constructFullPhoneNumber, + getCountryCodeFromPastedNumber, + processPhoneNumber, +} from '../phone-number' +import {type Action, type State, useOnPressBackButton} from '../state' + +export function PhoneInput({ + state, + dispatch, + context, + onSkip, +}: { + state: Extract + dispatch: React.ActionDispatch<[Action]> + context: 'Onboarding' | 'Standalone' + onSkip: () => void +}) { + const {_} = useLingui() + const t = useTheme() + const agent = useAgent() + const location = useGeolocation() + const [countryCode, setCountryCode] = useState( + () => state.phoneCountryCode ?? getDefaultCountry(location), + ) + const [phoneNumber, setPhoneNumber] = useState(state.phoneNumber ?? '') + const gutters = useGutters([0, 'wide']) + const insets = useSafeAreaInsets() + // for API/generic errors + const [error, setError] = useState('') + // for issues with parsing the number + const [formatError, setFormatError] = useState('') + + const {mutate: submit, isPending} = useMutation({ + mutationFn: async ({ + phoneCountryCode, + phoneNumber, + }: { + phoneCountryCode: CountryCode + phoneNumber: string + }) => { + // sends a onetime code to the user's phone number + await agent.app.bsky.contact.startPhoneVerification({ + phone: constructFullPhoneNumber(phoneCountryCode, phoneNumber), + }) + }, + onSuccess: (_data, {phoneCountryCode, phoneNumber}) => { + dispatch({ + type: 'SUBMIT_PHONE_NUMBER', + payload: {phoneCountryCode, phoneNumber}, + }) + + logger.metric('contacts:phone:phoneEntered', {entryPoint: context}) + }, + onMutate: () => { + Keyboard.dismiss() + setError('') + setFormatError('') + }, + onError: err => { + if (isNetworkError(err)) { + setError( + _( + msg`A network error occurred. Please check your internet connection`, + ), + ) + } else if ( + err instanceof + AppBskyContactStartPhoneVerification.RateLimitExceededError + ) { + setError(_(msg`Rate limit exceeded. Please try again later.`)) + } else if ( + err instanceof AppBskyContactStartPhoneVerification.InvalidPhoneError + ) { + setError( + _( + msg`The verification provider was unable to send a code to your phone number. Please check your phone number and try again.`, + ), + ) + } else { + logger.error('Verify phone number failed', {safeMessage: err}) + setError(_(msg`An error occurred. ${cleanError(err)}`)) + } + }, + }) + + const isFeatureEnabled = isFindContactsFeatureEnabled(countryCode) + + const onSubmitNumber = () => { + if (!isFeatureEnabled) return + if (!phoneNumber) return + const result = processPhoneNumber(phoneNumber, countryCode) + if (result.valid) { + setPhoneNumber(result.formatted) + setCountryCode(result.countryCode) + + if (!isFindContactsFeatureEnabled(result.countryCode)) return + + submit({ + phoneCountryCode: result.countryCode, + phoneNumber: result.formatted, + }) + } else { + setFormatError(result.reason ?? _(msg`Invalid phone number`)) + } + } + + const paddingBottom = Math.max(insets.bottom, tokens.space.xl) + + const onPressBack = useOnPressBackButton() + + return ( + + + + + {context === 'Onboarding' ? ( + + ) : ( + + )} + + + {context === 'Onboarding' && } + + Verify phone number + + + + We need to verify your number before we can look for your friends. A + verification code will be sent to this number. + + + + + + Phone number + + + + setCountryCode(value)} + /> + + + + { + if (formatError) setFormatError('') + if (Math.abs(text.length - phoneNumber.length) > 1) { + // possibly pasted/autocompleted? auto-switch + // country code if possible + const result = getCountryCodeFromPastedNumber(text) + if (result) { + setCountryCode(result.countryCode) + setPhoneNumber(result.rest) + return + } + } + setPhoneNumber(text) + }} + placeholder={null} + keyboardType={platform({ + ios: 'number-pad', + android: 'phone-pad', + })} + autoComplete="tel" + returnKeyType={android('next')} + onSubmitEditing={onSubmitNumber} + /> + + + + + + {!isFeatureEnabled && ( + + + Support for this feature in your country has not been enabled yet! + Please check back later. + + + )} + {error && {error}} + {formatError && {formatError}} + + + + + + + + + + + + ) +} + +function LegalDisclaimer() { + const t = useTheme() + const {_} = useLingui() + + const style = [a.text_xs, t.atoms.text_contrast_medium, a.leading_snug] + + return ( + + + How we use your number: + + + •{' '} + Sent to our phone number verification provider Plivo + + + • Deleted by Plivo after verification + + + •{' '} + Held by Bluesky for 7 days to prevent abuse, then deleted + + + •{' '} + Stored as part of a secure code for matching with others + + + + By continuing, you consent to this use. You may change your mind any + time by visiting settings.{' '} + + Learn more + + + + + ) +} + +function ErrorText({children}: {children: React.ReactNode}) { + const t = useTheme() + return ( + + {children} + + ) +} diff --git a/src/components/contacts/screens/VerifyNumber.tsx b/src/components/contacts/screens/VerifyNumber.tsx new file mode 100644 index 000000000..ec676ad72 --- /dev/null +++ b/src/components/contacts/screens/VerifyNumber.tsx @@ -0,0 +1,386 @@ +import {useEffect, useMemo, useState} from 'react' +import {Text as NestedText, View} from 'react-native' +import { + AppBskyContactStartPhoneVerification, + AppBskyContactVerifyPhone, +} from '@atproto/api' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useMutation} from '@tanstack/react-query' + +import {clamp} from '#/lib/numbers' +import {cleanError, isNetworkError} from '#/lib/strings/errors' +import {logger} from '#/logger' +import {useAgent} from '#/state/session' +import {OnboardingPosition} from '#/screens/Onboarding/Layout' +import {atoms as a, useGutters, useTheme} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as RetryIcon} from '#/components/icons/ArrowRotate' +import {CircleCheck_Stroke2_Corner0_Rounded as CircleCheckIcon} from '#/components/icons/CircleCheck' +import {type Props as SVGIconProps} from '#/components/icons/common' +import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' +import * as Layout from '#/components/Layout' +import {Loader} from '#/components/Loader' +import * as Toast from '#/components/Toast' +import {Text} from '#/components/Typography' +import {OTPInput} from '../components/OTPInput' +import {constructFullPhoneNumber, prettyPhoneNumber} from '../phone-number' +import {type Action, type State, useOnPressBackButton} from '../state' + +export function VerifyNumber({ + state, + dispatch, + context, + onSkip, +}: { + state: Extract + dispatch: React.ActionDispatch<[Action]> + context: 'Onboarding' | 'Standalone' + onSkip: () => void +}) { + const t = useTheme() + const {_} = useLingui() + const agent = useAgent() + const gutters = useGutters([0, 'wide']) + + const [otpCode, setOtpCode] = useState('') + const [error, setError] = useState<{ + retryable: boolean + isResendError: boolean + message: string + } | null>(null) + + const [prevOtpCode, setPrevOtpCode] = useState(otpCode) + if (otpCode !== prevOtpCode) { + setPrevOtpCode(otpCode) + setError(null) + } + + const phone = useMemo( + () => constructFullPhoneNumber(state.phoneCountryCode, state.phoneNumber), + [state.phoneCountryCode, state.phoneNumber], + ) + + const prettyNumber = useMemo(() => prettyPhoneNumber(phone), [phone]) + + const { + mutate: verifyNumber, + isPending, + isSuccess, + } = useMutation({ + mutationFn: async (code: string) => { + const res = await agent.app.bsky.contact.verifyPhone({code, phone}) + return res.data.token + }, + onSuccess: async token => { + // let the success state show for a moment + setTimeout(() => { + dispatch({ + type: 'VERIFY_PHONE_NUMBER_SUCCESS', + payload: { + token, + }, + }) + }, 1000) + + logger.metric('contacts:phone:phoneVerified', {entryPoint: context}) + }, + onMutate: () => setError(null), + onError: err => { + setOtpCode('') + if (isNetworkError(err)) { + setError({ + retryable: true, + isResendError: false, + message: _( + msg`A network error occurred. Please check your internet connection.`, + ), + }) + } else if (err instanceof AppBskyContactVerifyPhone.InvalidCodeError) { + setError({ + retryable: true, + isResendError: true, + message: _(msg`This code is invalid. Resend to get a new code.`), + }) + } else if (err instanceof AppBskyContactVerifyPhone.InvalidPhoneError) { + setError({ + retryable: false, + isResendError: false, + message: _( + msg`The verification provider was unable to send a code to your phone number. Please check your phone number and try again.`, + ), + }) + } else if ( + err instanceof AppBskyContactVerifyPhone.RateLimitExceededError + ) { + setError({ + retryable: true, + isResendError: false, + message: _( + msg`Too many attempts. Please wait a few minutes and try again.`, + ), + }) + } else { + logger.error('Verify phone number failed', {safeMessage: err}) + setError({ + retryable: true, + isResendError: false, + message: _(msg`An error occurred. ${cleanError(err)}`), + }) + } + }, + }) + + const {mutate: resendCode, isPending: isResendingCode} = useMutation({ + mutationFn: async () => { + await agent.app.bsky.contact.startPhoneVerification({phone: phone}) + }, + onSuccess: () => { + dispatch({type: 'RESEND_VERIFICATION_CODE'}) + Toast.show(_(msg`A new code has been sent`)) + }, + onMutate: () => { + setOtpCode('') + setError(null) + }, + onError: err => { + if (isNetworkError(err)) { + setError({ + retryable: true, + isResendError: true, + message: _( + msg`A network error occurred. Please check your internet connection.`, + ), + }) + } else if ( + err instanceof AppBskyContactStartPhoneVerification.InvalidPhoneError + ) { + setError({ + retryable: false, + isResendError: true, + message: _( + msg`The verification provider was unable to send a code to your phone number. Please check your phone number and try again.`, + ), + }) + } else if ( + err instanceof + AppBskyContactStartPhoneVerification.RateLimitExceededError + ) { + setError({ + retryable: true, + isResendError: true, + message: _( + msg`Too many codes sent. Please wait a few minutes and try again.`, + ), + }) + } else { + logger.error('Resend failed', {safeMessage: err}) + setError({ + retryable: true, + isResendError: true, + message: _(msg`An error occurred. ${cleanError(err)}`), + }) + } + }, + }) + + const onPressBack = useOnPressBackButton() + + return ( + + + + + {context === 'Onboarding' ? ( + + ) : ( + + )} + + + {context === 'Onboarding' && } + + Verify phone number + + + Enter the 6-digit code sent to {prettyNumber} + + + verifyNumber(code)} + /> + + + resendCode()} + onRetry={() => verifyNumber(otpCode)} + lastCodeSentAt={state.lastSentAt} + /> + + + + ) +} + +/** + * Horrible component that takes all the state above and figures out what messages + * and buttons to display. + */ +function OTPStatus({ + error, + isPending, + isResendingCode, + isSuccess, + onResend, + onRetry, + lastCodeSentAt, +}: { + error: { + retryable: boolean + isResendError: boolean + message: string + } | null + isPending: boolean + isResendingCode: boolean + isSuccess: boolean + onResend: () => void + onRetry: () => void + lastCodeSentAt: Date | null +}) { + const {_} = useLingui() + const t = useTheme() + + const [time, setTime] = useState(Date.now()) + useEffect(() => { + const interval = setInterval(() => { + setTime(Date.now()) + }, 1000) + return () => clearInterval(interval) + }, []) + + const timeUntilCanResend = Math.max( + 0, + 30000 - (time - (lastCodeSentAt?.getTime() ?? 0)), + ) + const isWaiting = timeUntilCanResend > 0 + + let Icon: React.ComponentType | null = null + let text = '' + let textColor = t.atoms.text_contrast_medium.color + let showResendButton = false + let showRetryButton = false + + if (isSuccess) { + Icon = CircleCheckIcon + text = _(msg`Phone number verified`) + textColor = t.palette.positive_500 + } else if (isPending) { + text = _(msg`Verifying...`) + } else if (error) { + Icon = WarningIcon + text = error.message + textColor = t.palette.negative_500 + if (error.retryable) { + if (error.isResendError) { + showResendButton = true + } else { + showRetryButton = true + } + } + } else { + showResendButton = true + } + + return ( + + {text && ( + + {Icon && } + + {text} + + + )} + + {showRetryButton && ( + + )} + + {showResendButton && ( + + )} + + ) +} diff --git a/src/components/contacts/screens/ViewMatches.tsx b/src/components/contacts/screens/ViewMatches.tsx new file mode 100644 index 000000000..9b4ff9382 --- /dev/null +++ b/src/components/contacts/screens/ViewMatches.tsx @@ -0,0 +1,683 @@ +import {useCallback, useMemo, useRef, useState} from 'react' +import {View} from 'react-native' +import {useSafeAreaInsets} from 'react-native-safe-area-context' +import * as SMS from 'expo-sms' +import {type ModerationOpts} from '@atproto/api' +import {msg, Plural, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useMutation, useQueryClient} from '@tanstack/react-query' + +import {wait} from '#/lib/async/wait' +import {cleanError, isNetworkError} from '#/lib/strings/errors' +import {logger} from '#/logger' +import { + updateProfileShadow, + useProfileShadow, +} from '#/state/cache/profile-shadow' +import {useModerationOpts} from '#/state/preferences/moderation-opts' +import { + optimisticRemoveMatch, + useMatchesPassthroughQuery, +} from '#/state/queries/find-contacts' +import {useAgent, useSession} from '#/state/session' +import {List, type ListMethods} from '#/view/com/util/List' +import {UserAvatar} from '#/view/com/util/UserAvatar' +import {OnboardingPosition} from '#/screens/Onboarding/Layout' +import {bulkWriteFollows} from '#/screens/Onboarding/util' +import {atoms as a, tokens, useGutters, useTheme} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import {SearchInput} from '#/components/forms/SearchInput' +import {useInteractionState} from '#/components/hooks/useInteractionState' +import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check' +import {MagnifyingGlassX_Stroke2_Corner0_Rounded_Large as SearchFailedIcon} from '#/components/icons/MagnifyingGlass' +import {PersonX_Stroke2_Corner0_Rounded_Large as PersonXIcon} from '#/components/icons/Person' +import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' +import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times' +import * as Layout from '#/components/Layout' +import {ListFooter} from '#/components/Lists' +import {Loader} from '#/components/Loader' +import * as ProfileCard from '#/components/ProfileCard' +import * as Toast from '#/components/Toast' +import {Text} from '#/components/Typography' +import type * as bsky from '#/types/bsky' +import {InviteInfo} from '../components/InviteInfo' +import {type Action, type Contact, type Match, type State} from '../state' + +type Item = + | { + type: 'matches header' + count: number + } + | { + type: 'match' + match: Match + } + | { + type: 'contacts header' + } + | { + type: 'contact' + contact: Contact + } + | { + type: 'no matches header' + } + | { + type: 'search empty state' + query: string + } + | { + type: 'totally empty state' + } + +export function ViewMatches({ + state, + dispatch, + context, + onNext, +}: { + state: Extract + dispatch: React.ActionDispatch<[Action]> + context: 'Onboarding' | 'Standalone' + onNext: () => void +}) { + const t = useTheme() + const {_} = useLingui() + const gutter = useGutters([0, 'wide']) + const moderationOpts = useModerationOpts() + const queryClient = useQueryClient() + const agent = useAgent() + const insets = useSafeAreaInsets() + const listRef = useRef(null) + + const [search, setSearch] = useState('') + const { + state: searchFocused, + onIn: onFocus, + onOut: onBlur, + } = useInteractionState() + + // HACK: Although we already have the match data, we need to pass it through + // a query to get it into the shadow state + const allMatches = useMatchesPassthroughQuery(state.matches) + const matches = allMatches.filter( + match => !state.dismissedMatches.includes(match.profile.did), + ) + + console.log(matches) + + const followableDids = matches.map(match => match.profile.did) + const [didFollowAll, setDidFollowAll] = useState(followableDids.length === 0) + + const cumulativeFollowCount = useRef(0) + const onFollow = useCallback(() => { + logger.metric('contacts:matches:follow', {entryPoint: context}) + cumulativeFollowCount.current += 1 + }, [context]) + + const {mutate: followAll, isPending: isFollowingAll} = useMutation({ + mutationFn: async () => { + for (const did of followableDids) { + updateProfileShadow(queryClient, did, { + followingUri: 'pending', + }) + } + + const uris = await wait(500, bulkWriteFollows(agent, followableDids)) + + for (const did of followableDids) { + const uri = uris.get(did) + updateProfileShadow(queryClient, did, { + followingUri: uri, + }) + } + return followableDids + }, + onMutate: () => + logger.metric('contacts:matches:followAll', { + followCount: followableDids.length, + entryPoint: context, + }), + onSuccess: () => { + setDidFollowAll(true) + Toast.show(_(msg`All friends followed!`), {type: 'success'}) + cumulativeFollowCount.current += followableDids.length + }, + onError: _err => { + Toast.show(_(msg`Failed to follow all your friends, please try again`), { + type: 'error', + }) + for (const did of followableDids) { + updateProfileShadow(queryClient, did, { + followingUri: undefined, + }) + } + }, + }) + + const items = useMemo(() => { + const all: Item[] = [] + + if (searchFocused || search.length > 0) { + for (const match of matches) { + if ( + search.length === 0 || + (match.profile.displayName ?? '') + .toLocaleLowerCase() + .includes(search.toLocaleLowerCase()) || + match.profile.handle + .toLocaleLowerCase() + .includes(search.toLocaleLowerCase()) + ) { + all.push({type: 'match', match}) + } + } + + for (const contact of state.contacts) { + if ( + search.length === 0 || + [contact.firstName, contact.lastName] + .filter(Boolean) + .join(' ') + .toLocaleLowerCase() + .includes(search.toLocaleLowerCase()) + ) { + all.push({type: 'contact', contact}) + } + } + + if (all.length === 0) { + all.push({type: 'search empty state', query: search}) + } + } else { + if (matches.length > 0) { + all.push({type: 'matches header', count: matches.length}) + for (const match of matches) { + all.push({type: 'match', match}) + } + + if (state.contacts.length > 0) { + all.push({type: 'contacts header'}) + } + } else if (state.contacts.length > 0) { + all.push({type: 'no matches header'}) + } + + for (const contact of state.contacts) { + all.push({type: 'contact', contact}) + } + + if (all.length === 0) { + all.push({type: 'totally empty state'}) + } + } + + return all + }, [matches, state.contacts, search, searchFocused]) + + const {mutate: dismissMatch} = useMutation({ + mutationFn: async (did: string) => { + await agent.app.bsky.contact.dismissMatch({subject: did}) + }, + onMutate: did => { + logger.metric('contacts:matches:dismiss', {entryPoint: context}) + dispatch({type: 'DISMISS_MATCH', payload: {did}}) + }, + onSuccess: (_res, did) => { + // for the other screen + optimisticRemoveMatch(queryClient, did) + }, + onError: (err, did) => { + dispatch({type: 'DISMISS_MATCH_FAILED', payload: {did}}) + if (isNetworkError(err)) { + Toast.show( + _( + msg`Failed to hide suggestion, please check your internet connection`, + ), + {type: 'error'}, + ) + } else { + logger.error('Dismissing match failed', {safeMessage: err}) + Toast.show( + _(msg`An error occurred while hiding suggestion. ${cleanError(err)}`), + {type: 'error'}, + ) + } + }, + }) + + const renderItem = ({item}: {item: Item}) => { + switch (item.type) { + case 'match': + return ( + + ) + case 'contact': + return + case 'matches header': + return ( +
+ }> + {item.count > 1 && ( + + )} +
+ ) + case 'contacts header': + return ( +
+ Invite friends{' '} + + + } + hasContentAbove + /> + ) + case 'no matches header': + return ( +
+ Bluesky is more fun with friends. Do you want to invite some of + yours?{' '} + + + } + /> + ) + case 'search empty state': + return + case 'totally empty state': + return + } + } + + const isSearchEmpty = items?.[0]?.type === 'search empty state' + const isTotallyEmpty = items?.[0]?.type === 'totally empty state' + + const isEmpty = isSearchEmpty || isTotallyEmpty + + return ( + + {context === 'Standalone' && ( + + + + + + )} + {!isTotallyEmpty && ( + + {context === 'Onboarding' && } + { + onFocus() + listRef.current?.scrollToOffset({offset: 0, animated: false}) + }} + onBlur={() => { + onBlur() + listRef.current?.scrollToOffset({offset: 0, animated: false}) + }} + onChangeText={text => { + setSearch(text) + listRef.current?.scrollToOffset({offset: 0, animated: false}) + }} + onClearText={() => setSearch('')} + /> + + )} + : null} + keyExtractor={keyExtractor} + keyboardDismissMode="interactive" + automaticallyAdjustKeyboardInsets + /> + + + + + ) +} + +function keyExtractor(item: Item) { + switch (item.type) { + case 'contact': + return item.contact.id + case 'match': + return item.match.profile.did + default: + return item.type + } +} + +function MatchItem({ + profile, + contact, + moderationOpts, + onRemoveSuggestion, + onFollow, +}: { + profile: bsky.profile.AnyProfileView + contact?: Contact + moderationOpts?: ModerationOpts + onRemoveSuggestion: (did: string) => void + onFollow: () => void +}) { + const gutter = useGutters([0, 'wide']) + const t = useTheme() + const {_} = useLingui() + const shadow = useProfileShadow(profile) + + const contactName = useMemo(() => { + if (!contact) return null + + const name = contact.firstName ?? contact.lastName ?? contact.name + if (name) return _(msg`Your contact ${name}`) + const phone = + contact.phoneNumbers?.find(p => p.isPrimary) ?? contact.phoneNumbers?.[0] + if (phone?.number) return phone.number + return null + }, [contact, _]) + + if (!moderationOpts) return null + + return ( + + + + + + + {contactName && ( + + {contactName} + + )} + + + {!shadow.viewer?.following && ( + + )} + + + ) +} + +function ContactItem({ + contact, + context, +}: { + contact: Contact + context: 'Onboarding' | 'Standalone' +}) { + const gutter = useGutters([0, 'wide']) + const t = useTheme() + const {_} = useLingui() + const {currentAccount} = useSession() + + const name = contact.firstName ?? contact.lastName ?? contact.name + const phone = + contact.phoneNumbers?.find(phone => phone.isPrimary) ?? + contact.phoneNumbers?.[0] + const phoneNumber = phone?.number + + return ( + + + {contact.image ? ( + + ) : ( + + + {name?.[0]?.toLocaleUpperCase()} + + + )} + + {name ?? No name} + + {phoneNumber && currentAccount && ( + + )} + + + ) +} + +function Header({ + titleText, + largeTitle, + subtitleText, + children, + hasContentAbove, +}: { + titleText: React.ReactNode + largeTitle?: boolean + subtitleText?: React.ReactNode + children?: React.ReactNode + hasContentAbove?: boolean +}) { + const gutter = useGutters([0, 'wide']) + const t = useTheme() + + return ( + + + + {titleText} + + {children} + + {subtitleText && ( + + {subtitleText} + + )} + + ) +} + +function SearchEmptyState({query}: {query: string}) { + const t = useTheme() + + return ( + + + + No contacts with the name “{query}” found + + + ) +} + +function TotallyEmptyState() { + const t = useTheme() + + return ( + + + + No contacts found + + + ) +} diff --git a/src/components/contacts/state.ts b/src/components/contacts/state.ts new file mode 100644 index 000000000..2514a6a65 --- /dev/null +++ b/src/components/contacts/state.ts @@ -0,0 +1,198 @@ +import {createContext, useContext, useReducer} from 'react' +import {type GestureResponderEvent} from 'react-native' +import {type ExistingContact} from 'expo-contacts' + +import {type CountryCode} from '#/lib/international-telephone-codes' +import type * as bsky from '#/types/bsky' + +export type Contact = ExistingContact + +export type Match = { + profile: bsky.profile.AnyProfileView + contact?: Contact +} + +export type State = + | { + step: '1: phone input' + phoneCountryCode?: CountryCode + phoneNumber?: string + } + | { + step: '2: verify number' + phoneCountryCode: CountryCode + phoneNumber: string + lastSentAt: Date | null + } + | { + step: '3: get contacts' + phoneCountryCode: CountryCode + phoneNumber: string + token: string + contacts?: Contact[] + } + | { + step: '4: view matches' + contacts: Contact[] + matches: Match[] + // rather than mutating `matches`, we keep track of dismissed matches + // so we can roll back optimistic updates + dismissedMatches: string[] + } + +export type Action = + | { + type: 'SUBMIT_PHONE_NUMBER' + payload: { + phoneCountryCode: CountryCode + phoneNumber: string + } + } + | { + type: 'RESEND_VERIFICATION_CODE' + } + | { + type: 'VERIFY_PHONE_NUMBER_SUCCESS' + payload: { + token: string + } + } + | { + type: 'GET_CONTACTS_SUCCESS' + payload: { + contacts: Contact[] + } + } + | { + type: 'SYNC_CONTACTS_SUCCESS' + payload: { + matches: Match[] + // filter out matched contacts + contacts: Contact[] + } + } + | { + type: 'BACK' + } + | { + type: 'DISMISS_MATCH' + payload: { + did: string + } + } + | { + type: 'DISMISS_MATCH_FAILED' + payload: { + did: string + } + } + +function reducer(state: State, action: Action): State { + switch (action.type) { + case 'SUBMIT_PHONE_NUMBER': { + assertCurrentStep(state, '1: phone input') + return { + step: '2: verify number', + ...action.payload, + lastSentAt: null, + } + } + case 'RESEND_VERIFICATION_CODE': { + assertCurrentStep(state, '2: verify number') + return { + ...state, + lastSentAt: new Date(), + } + } + case 'VERIFY_PHONE_NUMBER_SUCCESS': { + assertCurrentStep(state, '2: verify number') + return { + step: '3: get contacts', + token: action.payload.token, + phoneCountryCode: state.phoneCountryCode, + phoneNumber: state.phoneNumber, + } + } + case 'BACK': { + assertCurrentStep(state, '2: verify number') + return { + step: '1: phone input', + phoneNumber: state.phoneNumber, + phoneCountryCode: state.phoneCountryCode, + } + } + case 'GET_CONTACTS_SUCCESS': { + assertCurrentStep(state, '3: get contacts') + return { + ...state, + contacts: action.payload.contacts, + } + } + case 'SYNC_CONTACTS_SUCCESS': { + assertCurrentStep(state, '3: get contacts') + return { + step: '4: view matches', + contacts: action.payload.contacts, + matches: action.payload.matches, + dismissedMatches: [], + } + } + case 'DISMISS_MATCH': { + assertCurrentStep(state, '4: view matches') + return { + ...state, + dismissedMatches: [ + ...new Set(state.dismissedMatches), + action.payload.did, + ], + } + } + case 'DISMISS_MATCH_FAILED': { + assertCurrentStep(state, '4: view matches') + return { + ...state, + dismissedMatches: state.dismissedMatches.filter( + did => did !== action.payload.did, + ), + } + } + } +} + +class InvalidStateTransitionError extends Error { + constructor(message: string) { + super(message) + this.name = 'InvalidStateTransitionError' + } +} + +function assertCurrentStep( + state: State, + step: S, +): asserts state is Extract { + if (state.step !== step) { + throw new InvalidStateTransitionError( + `Invalid state transition: expecting ${step}, got ${state.step}`, + ) + } +} + +export function useFindContactsFlowState( + initialState: State = {step: '1: phone input'}, +) { + return useReducer(reducer, initialState) +} + +export const FindContactsGoBackContext = createContext< + (() => void) | undefined +>(undefined) +export function useOnPressBackButton() { + const goBack = useContext(FindContactsGoBackContext) + if (!goBack) { + return undefined + } + return (evt: GestureResponderEvent) => { + evt.preventDefault() + goBack() + } +} diff --git a/src/components/dialogs/GifSelect.tsx b/src/components/dialogs/GifSelect.tsx index 536483b08..58d669f0e 100644 --- a/src/components/dialogs/GifSelect.tsx +++ b/src/components/dialogs/GifSelect.tsx @@ -29,7 +29,7 @@ import * as Dialog from '#/components/Dialog' import * as TextField from '#/components/forms/TextField' import {useThrottledValue} from '#/components/hooks/useThrottledValue' import {ArrowLeft_Stroke2_Corner0_Rounded as Arrow} from '#/components/icons/Arrow' -import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' +import {MagnifyingGlass_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass' import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' export function GifSelectDialog({ diff --git a/src/components/dialogs/SearchablePeopleList.tsx b/src/components/dialogs/SearchablePeopleList.tsx index 41b31b255..d8c44c309 100644 --- a/src/components/dialogs/SearchablePeopleList.tsx +++ b/src/components/dialogs/SearchablePeopleList.tsx @@ -25,7 +25,7 @@ import {Button, ButtonIcon} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {canBeMessaged} from '#/components/dms/util' import {useInteractionState} from '#/components/hooks/useInteractionState' -import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' +import {MagnifyingGlass_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass' import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' import * as ProfileCard from '#/components/ProfileCard' import {Text} from '#/components/Typography' diff --git a/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx b/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx new file mode 100644 index 000000000..13f62a3e2 --- /dev/null +++ b/src/components/dialogs/nuxs/FindContactsAnnouncement.tsx @@ -0,0 +1,116 @@ +import {useCallback} from 'react' +import {View} from 'react-native' +import {Image} from 'expo-image' +import {LinearGradient} from 'expo-linear-gradient' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {logger} from '#/logger' +import {isWeb} from '#/platform/detection' +import {atoms as a, useTheme, web} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import * as Dialog from '#/components/Dialog' +import {useNuxDialogContext} from '#/components/dialogs/nuxs' +import {Text} from '#/components/Typography' +import {navigate} from '#/Navigation' + +export function FindContactsAnnouncement() { + const t = useTheme() + const {_} = useLingui() + const nuxDialogs = useNuxDialogContext() + const control = Dialog.useDialogControl() + + Dialog.useAutoOpen(control) + + const onClose = useCallback(() => { + nuxDialogs.dismissActiveNux() + }, [nuxDialogs]) + + return ( + + + + + + + + {_( + + + + + + Find your friends + + + + Bluesky is more fun with friends! Import your contacts to see + who’s already here. + + + + + + + + + + + ) +} diff --git a/src/components/dialogs/nuxs/index.tsx b/src/components/dialogs/nuxs/index.tsx index 4076708fc..63e11a7f4 100644 --- a/src/components/dialogs/nuxs/index.tsx +++ b/src/components/dialogs/nuxs/index.tsx @@ -1,8 +1,16 @@ -import React from 'react' +import { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useState, +} from 'react' import {type AppBskyActorDefs} from '@atproto/api' import {useGate} from '#/lib/statsig/statsig' import {logger} from '#/logger' +import {isNative} from '#/platform/detection' import {STALE} from '#/state/queries' import {Nux, useNuxs, useResetNuxs, useSaveNux} from '#/state/queries/nuxs' import { @@ -12,11 +20,11 @@ import { import {useProfileQuery} from '#/state/queries/profile' import {type SessionAccount, useSession} from '#/state/session' import {useOnboardingState} from '#/state/shell' -import {BookmarksAnnouncement} from '#/components/dialogs/nuxs/BookmarksAnnouncement' +import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing' /* * NUXs */ -import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing' +import {FindContactsAnnouncement} from './FindContactsAnnouncement' import {isExistingUserAsOf} from './utils' type Context = { @@ -34,24 +42,24 @@ const queuedNuxs: { }) => boolean }[] = [ { - id: Nux.BookmarksAnnouncement, + id: Nux.FindContactsAnnouncement, enabled: ({currentProfile}) => { - return isExistingUserAsOf( - '2025-09-08T00:00:00.000Z', - currentProfile.createdAt, + return ( + isNative && + isExistingUserAsOf('2025-12-16T00:00:00.000Z', currentProfile.createdAt) ) }, }, ] -const Context = React.createContext({ +const Context = createContext({ activeNux: undefined, dismissActiveNux: () => {}, }) Context.displayName = 'NuxDialogContext' export function useNuxDialogContext() { - return React.useContext(Context) + return useContext(Context) } export function NuxDialogs() { @@ -92,19 +100,19 @@ function Inner({ }) { const gate = useGate() const {nuxs} = useNuxs() - const [snoozed, setSnoozed] = React.useState(() => { + const [snoozed, setSnoozed] = useState(() => { return isSnoozed() }) - const [activeNux, setActiveNux] = React.useState() + const [activeNux, setActiveNux] = useState() const {mutateAsync: saveNux} = useSaveNux() const {mutate: resetNuxs} = useResetNuxs() - const snoozeNuxDialog = React.useCallback(() => { + const snoozeNuxDialog = useCallback(() => { snooze() setSnoozed(true) }, [setSnoozed]) - const dismissActiveNux = React.useCallback(() => { + const dismissActiveNux = useCallback(() => { if (!activeNux) return setActiveNux(undefined) }, [activeNux, setActiveNux]) @@ -118,7 +126,7 @@ function Inner({ } } - React.useEffect(() => { + useEffect(() => { if (snoozed) return // comment this out to test if (!nuxs) return @@ -170,7 +178,7 @@ function Inner({ preferences, ]) - const ctx = React.useMemo(() => { + const ctx = useMemo(() => { return { activeNux, dismissActiveNux, @@ -180,7 +188,9 @@ function Inner({ return ( {/*For example, activeNux === Nux.NeueTypography && */} - {activeNux === Nux.BookmarksAnnouncement && } + {activeNux === Nux.FindContactsAnnouncement && ( + + )} ) } diff --git a/src/components/forms/SearchInput.tsx b/src/components/forms/SearchInput.tsx index 618a0040e..ae0335abd 100644 --- a/src/components/forms/SearchInput.tsx +++ b/src/components/forms/SearchInput.tsx @@ -8,7 +8,7 @@ import {isNative} from '#/platform/detection' import {atoms as a, useTheme} from '#/alf' import {Button, ButtonIcon} from '#/components/Button' import * as TextField from '#/components/forms/TextField' -import {MagnifyingGlass2_Stroke2_Corner0_Rounded as MagnifyingGlassIcon} from '#/components/icons/MagnifyingGlass2' +import {MagnifyingGlass_Stroke2_Corner0_Rounded as MagnifyingGlassIcon} from '#/components/icons/MagnifyingGlass' import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' type SearchInputProps = Omit & { diff --git a/src/components/forms/TextField.tsx b/src/components/forms/TextField.tsx index 62f30db47..6e8846ddd 100644 --- a/src/components/forms/TextField.tsx +++ b/src/components/forms/TextField.tsx @@ -141,17 +141,28 @@ export function useSharedInputStyles() { }, [t]) } -export type InputProps = Omit & { +export type InputProps = Omit< + TextInputProps, + 'value' | 'onChangeText' | 'placeholder' +> & { label: string /** * @deprecated Controlled inputs are *strongly* discouraged. Use `defaultValue` instead where possible. * * See https://github.com/facebook/react-native-website/pull/4247 + * + * Note: This guidance no longer applies once we migrate to the New Architecture! */ value?: string onChangeText?: (value: string) => void isInvalid?: boolean inputRef?: React.RefObject | React.ForwardedRef + /** + * Note: this currently falls back to the label if not specified. However, + * most new designs have no placeholder. We should eventually remove this fallback + * behaviour, but for now just pass `null` if you want no placeholder -sfn + */ + placeholder?: string | null | undefined } export function createInput(Component: typeof TextInput) { @@ -255,7 +266,7 @@ export function createInput(Component: typeof TextInput) { ctx.onBlur() onBlur?.(e) }} - placeholder={placeholder || label} + placeholder={placeholder === null ? undefined : placeholder || label} placeholderTextColor={t.palette.contrast_500} keyboardAppearance={t.name === 'light' ? 'light' : 'dark'} style={flattened} @@ -292,12 +303,7 @@ export function LabelText({ return ( + style={[a.text_sm, a.font_medium, t.atoms.text_contrast_medium, a.mb_sm]}> {children} ) diff --git a/src/components/icons/ArrowRotateCounterClockwise.tsx b/src/components/icons/ArrowRotate.tsx similarity index 52% rename from src/components/icons/ArrowRotateCounterClockwise.tsx rename to src/components/icons/ArrowRotate.tsx index 35cd23a97..290b42313 100644 --- a/src/components/icons/ArrowRotateCounterClockwise.tsx +++ b/src/components/icons/ArrowRotate.tsx @@ -4,3 +4,9 @@ export const ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded = createSinglePathSVG({ path: 'M5 3a1 1 0 0 1 1 1v1.423c.498-.46 1.02-.869 1.58-1.213C8.863 3.423 10.302 3 12.028 3a9 9 0 1 1-8.487 12 1 1 0 0 1 1.885-.667A7 7 0 1 0 12.028 5c-1.37 0-2.444.327-3.402.915-.474.29-.93.652-1.383 1.085H9a1 1 0 0 1 0 2H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z', }) + +export const ArrowRotateClockwise_Stroke2_Corner0_Rounded = createSinglePathSVG( + { + path: 'M2.972 12a9 9 0 0 1 9-9c1.726 0 3.165.423 4.448 1.21.561.344 1.082.756 1.58 1.218V4a1 1 0 1 1 2 0v4a1 1 0 0 1-1 1h-4a1 1 0 1 1 0-2h1.756a8.3 8.3 0 0 0-1.382-1.085C14.417 5.327 13.341 5 11.972 5a7 7 0 1 0 6.601 9.333A1 1 0 0 1 20.46 15a9 9 0 0 1-17.487-3Z', + }, +) diff --git a/src/components/icons/Contacts.tsx b/src/components/icons/Contacts.tsx new file mode 100644 index 000000000..93a08e30d --- /dev/null +++ b/src/components/icons/Contacts.tsx @@ -0,0 +1,9 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const Contacts_Stroke2_Corner2_Rounded = createSinglePathSVG({ + path: 'M7 4a1 1 0 0 0-1 1v12.05q.243-.05.5-.05H18V4H7Zm5 7c.894 0 1.57.188 2.068.513.445.29.683.647.806.937l.046.12c.285.836-.43 1.43-1.03 1.43h-3.78c-.6 0-1.315-.594-1.03-1.43l.046-.12c.123-.29.361-.647.806-.937C10.43 11.188 11.106 11 12 11Zm0-4a1.75 1.75 0 1 1 0 3.5A1.75 1.75 0 0 1 12 7Zm8 11a1 1 0 0 1-1 1H6.5a.5.5 0 0 0 0 1H19a1 1 0 1 1 0 2H6.5A2.5 2.5 0 0 1 4 19.5V5a3 3 0 0 1 3-3h11a2 2 0 0 1 2 2v14Z', +}) + +export const Contacts_Filled_Corner2_Rounded = createSinglePathSVG({ + path: 'M7 2a3 3 0 0 0-3 3v14.5A2.5 2.5 0 0 0 6.5 22H19a1 1 0 1 0 0-2H6.5a.5.5 0 0 1 0-1H19a1 1 0 0 0 1-1V4a2 2 0 0 0-2-2H7Zm5 5a1.75 1.75 0 1 0 0 3.5A1.75 1.75 0 0 0 12 7Zm0 4c-.894 0-1.57.188-2.068.512a2.07 2.07 0 0 0-.852 1.058c-.286.838.432 1.43 1.03 1.43h3.78c.598 0 1.316-.592 1.03-1.43a2.07 2.07 0 0 0-.852-1.058C13.57 11.189 12.894 11 12 11Z', +}) diff --git a/src/components/icons/MagnifyingGlass.tsx b/src/components/icons/MagnifyingGlass.tsx index de5f83c9c..b10b32627 100644 --- a/src/components/icons/MagnifyingGlass.tsx +++ b/src/components/icons/MagnifyingGlass.tsx @@ -1,6 +1,20 @@ import {createSinglePathSVG} from './TEMPLATE' +export const MagnifyingGlass_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M11 5a6 6 0 1 0 0 12 6 6 0 0 0 0-12Zm-8 6a8 8 0 1 1 14.32 4.906l3.387 3.387a1 1 0 0 1-1.414 1.414l-3.387-3.387A8 8 0 0 1 3 11Z', +}) + export const MagnifyingGlass_Filled_Stroke2_Corner0_Rounded = createSinglePathSVG({ path: 'M5 11a6 6 0 1 1 12 0 6 6 0 0 1-12 0Zm6-8a8 8 0 1 0 4.906 14.32l3.387 3.387a1 1 0 0 0 1.414-1.414l-3.387-3.387A8 8 0 0 0 11 3Zm4 8a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z', }) + +export const MagnifyingGlassX_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M20 12a8 8 0 1 0-8 8c2.204 0 4.2-.89 5.648-2.333A7.97 7.97 0 0 0 20 12Zm-5.707-3.707a1 1 0 1 1 1.414 1.414L13.414 12l2.293 2.293a1 1 0 1 1-1.414 1.414L12 13.414l-2.293 2.293a1 1 0 1 1-1.414-1.414L10.586 12 8.293 9.707a1 1 0 1 1 1.414-1.414L12 10.586l2.293-2.293ZM22 12a9.96 9.96 0 0 1-2.269 6.34l2.891 2.89a1 1 0 1 1-1.414 1.415l-2.893-2.893A9.96 9.96 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10Z', +}) + +export const MagnifyingGlassX_Stroke2_Corner0_Rounded_Large = + createSinglePathSVG({ + viewBox: '0 0 64 64', + path: 'M55 32C55 19.298 44.703 9 32 9S9 19.298 9 32s10.298 23 23 23a22.93 22.93 0 0 0 16.235-6.708A22.93 22.93 0 0 0 55 32Zm-15.707-8.707a1 1 0 1 1 1.414 1.414L33.414 32l7.293 7.293a1 1 0 1 1-1.414 1.414L32 33.414l-7.293 7.293a1 1 0 1 1-1.414-1.414L30.586 32l-7.293-7.293a1 1 0 1 1 1.414-1.414L32 30.586l7.293-7.293ZM57 32a24.9 24.9 0 0 1-6.66 16.985l8.808 8.808a1 1 0 0 1-1.414 1.414l-8.81-8.81A24.9 24.9 0 0 1 32 57C18.193 57 7 45.807 7 32S18.193 7 32 7s25 11.193 25 25Z', + }) diff --git a/src/components/icons/MagnifyingGlass2.tsx b/src/components/icons/MagnifyingGlass2.tsx deleted file mode 100644 index 3ca403400..000000000 --- a/src/components/icons/MagnifyingGlass2.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import {createSinglePathSVG} from './TEMPLATE' - -export const MagnifyingGlass2_Stroke2_Corner0_Rounded = createSinglePathSVG({ - path: 'M11 5a6 6 0 1 0 0 12 6 6 0 0 0 0-12Zm-8 6a8 8 0 1 1 14.32 4.906l3.387 3.387a1 1 0 0 1-1.414 1.414l-3.387-3.387A8 8 0 0 1 3 11Z', -}) diff --git a/src/components/icons/Person.tsx b/src/components/icons/Person.tsx index 8428fcce1..55324f10d 100644 --- a/src/components/icons/Person.tsx +++ b/src/components/icons/Person.tsx @@ -16,6 +16,11 @@ export const PersonX_Stroke2_Corner0_Rounded = createSinglePathSVG({ path: 'M12 4a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5ZM7.5 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM5.679 19c.709-2.902 3.079-5 6.321-5 .302 0 .595.018.878.053a1 1 0 0 0 .243-1.985A9.235 9.235 0 0 0 12 12c-4.3 0-7.447 2.884-8.304 6.696-.29 1.29.767 2.304 1.902 2.304H12a1 1 0 1 0 0-2H5.679Zm9.614-3.707a1 1 0 0 1 1.414 0L18 16.586l1.293-1.293a1 1 0 0 1 1.414 1.414L19.414 18l1.293 1.293a1 1 0 0 1-1.414 1.414L18 19.414l-1.293 1.293a1 1 0 0 1-1.414-1.414L16.586 18l-1.293-1.293a1 1 0 0 1 0-1.414Z', }) +export const PersonX_Stroke2_Corner0_Rounded_Large = createSinglePathSVG({ + viewBox: '0 0 64 64', + path: 'M24.952 33.435c10.897 0 19.195 6.496 22.58 15.65.784 2.117.258 4.183-1 5.683-1.242 1.48-3.194 2.414-5.33 2.415h-32.5c-2.136 0-4.089-.935-5.331-2.415-1.258-1.5-1.783-3.566-1-5.682 3.386-9.155 11.683-15.651 22.58-15.651Zm0 2.298c-9.885 0-17.355 5.849-20.425 14.15-.47 1.271-.174 2.48.604 3.407.795.947 2.096 1.594 3.57 1.594h32.5c1.476 0 2.777-.647 3.571-1.594.778-.928 1.074-2.136.605-3.406-3.07-8.302-10.54-14.15-20.425-14.15Zm33.262-14.59a1.15 1.15 0 1 1 1.625 1.626l-5.688 5.687 5.686 5.688a1.15 1.15 0 1 1-1.625 1.625l-5.686-5.688-5.687 5.688a1.15 1.15 0 1 1-1.625-1.625l5.687-5.688-5.689-5.687a1.15 1.15 0 1 1 1.625-1.625l5.689 5.687 5.688-5.687ZM24.949 5.552c6.557 0 11.874 5.316 11.874 11.874 0 6.557-5.317 11.874-11.874 11.874s-11.874-5.317-11.874-11.874S18.39 5.55 24.949 5.55Zm0 2.299a9.575 9.575 0 0 0-9.575 9.575A9.575 9.575 0 0 0 24.949 27a9.575 9.575 0 0 0 9.575-9.575A9.575 9.575 0 0 0 24.95 7.85Z', +}) + export const PersonPlus_Stroke2_Corner0_Rounded = createSinglePathSVG({ path: 'M12 4a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5ZM7.5 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM5.678 19c.71-2.909 3.092-5 6.322-5 .621 0 1.206.077 1.748.218a1 1 0 1 0 .504-1.936A8.931 8.931 0 0 0 12 12c-4.758 0-8.083 3.521-8.496 7.906A1 1 0 0 0 4.5 21H11a1 1 0 1 0 0-2H5.678ZM18 14a1 1 0 0 1 1 1v2h2a1 1 0 1 1 0 2h-2v2a1 1 0 1 1-2 0v-2h-2a1 1 0 1 1 0-2h2v-2a1 1 0 0 1 1-1Z', }) diff --git a/src/components/intents/VerifyEmailIntentDialog.tsx b/src/components/intents/VerifyEmailIntentDialog.tsx index da59dc0e6..36f98cb18 100644 --- a/src/components/intents/VerifyEmailIntentDialog.tsx +++ b/src/components/intents/VerifyEmailIntentDialog.tsx @@ -11,7 +11,7 @@ import * as Dialog from '#/components/Dialog' import {type DialogControlProps} from '#/components/Dialog' import {useConfirmEmail} from '#/components/dialogs/EmailDialog/data/useConfirmEmail' import {Divider} from '#/components/Divider' -import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Resend} from '#/components/icons/ArrowRotateCounterClockwise' +import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Resend} from '#/components/icons/ArrowRotate' import {useIntentDialogs} from '#/components/intents/IntentDialogs' import {Loader} from '#/components/Loader' import {Text} from '#/components/Typography' diff --git a/src/components/moderation/ReportDialog/index.tsx b/src/components/moderation/ReportDialog/index.tsx index 2331db3ea..3b7cd916e 100644 --- a/src/components/moderation/ReportDialog/index.tsx +++ b/src/components/moderation/ReportDialog/index.tsx @@ -18,7 +18,7 @@ import * as Admonition from '#/components/Admonition' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {useDelayedLoading} from '#/components/hooks/useDelayedLoading' -import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Retry} from '#/components/icons/ArrowRotateCounterClockwise' +import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as Retry} from '#/components/icons/ArrowRotate' import { Check_Stroke2_Corner0_Rounded as CheckThin, CheckThick_Stroke2_Corner0_Rounded as Check, diff --git a/src/lib/international-telephone-codes.ts b/src/lib/international-telephone-codes.ts index 355769b47..b7368e888 100644 --- a/src/lib/international-telephone-codes.ts +++ b/src/lib/international-telephone-codes.ts @@ -1,3 +1,14 @@ +import {type CountryCode as LibPhoneNumberJsCountryCode} from 'libphonenumber-js' + +// Exclude Ascension Island and Tristan da Cunha - merged into `SH` in 2009 +export type CountryCode = Exclude + +/** + * Note: data is from Wikipedia, but some have been removed to match `libphonenumber-js` + * Mostly tiny British overseas territories + Antarctica, all of which + * share codes with a larger country. If you've one of the 10 people from these + * places, you probably know what to do. + */ export const INTERNATIONAL_TELEPHONE_CODES = { AD: { code: '+376', @@ -34,11 +45,13 @@ export const INTERNATIONAL_TELEPHONE_CODES = { unicodeFlag: '🇦🇴', svgFlag: require('../../assets/icons/flags/AO.svg'), }, - AQ: { - code: '+672', - unicodeFlag: '🇦🇶', - svgFlag: require('../../assets/icons/flags/AQ.svg'), - }, + // sorry penguins :( + // same as Norfolk Island + // AQ: { + // code: '+672', + // unicodeFlag: '🇦🇶', + // svgFlag: require('../../assets/icons/flags/AQ.svg'), + // }, AR: { code: '+54', unicodeFlag: '🇦🇷', @@ -154,11 +167,12 @@ export const INTERNATIONAL_TELEPHONE_CODES = { unicodeFlag: '🇧🇹', svgFlag: require('../../assets/icons/flags/BT.svg'), }, - BV: { - code: '+47', - unicodeFlag: '🇧🇻', - svgFlag: require('../../assets/icons/flags/BV.svg'), - }, + // same as Norway + // BV: { + // code: '+47', + // unicodeFlag: '🇧🇻', + // svgFlag: require('../../assets/icons/flags/BV.svg'), + // }, BW: { code: '+267', unicodeFlag: '🇧🇼', @@ -379,11 +393,12 @@ export const INTERNATIONAL_TELEPHONE_CODES = { unicodeFlag: '🇬🇷', svgFlag: require('../../assets/icons/flags/GR.svg'), }, - GS: { - code: '+500', - unicodeFlag: '🇬🇸', - svgFlag: require('../../assets/icons/flags/GS.svg'), - }, + // same as Falkland Islands + // GS: { + // code: '+500', + // unicodeFlag: '🇬🇸', + // svgFlag: require('../../assets/icons/flags/GS.svg'), + // }, GT: { code: '+502', unicodeFlag: '🇬🇹', @@ -779,11 +794,12 @@ export const INTERNATIONAL_TELEPHONE_CODES = { unicodeFlag: '🇵🇲', svgFlag: require('../../assets/icons/flags/PM.svg'), }, - PN: { - code: '+64', - unicodeFlag: '🇵🇳', - svgFlag: require('../../assets/icons/flags/PN.svg'), - }, + // same as New Zealand + // PN: { + // code: '+64', + // unicodeFlag: '🇵🇳', + // svgFlag: require('../../assets/icons/flags/PN.svg'), + // }, PR: { code: '+1', unicodeFlag: '🇵🇷', @@ -1199,11 +1215,12 @@ export const INTERNATIONAL_TELEPHONE_CODES = { unicodeFlag: '🇫🇴', svgFlag: require('../../assets/icons/flags/FO.svg'), }, - HM: { - code: '+672', - unicodeFlag: '🇭🇲', - svgFlag: require('../../assets/icons/flags/HM.svg'), - }, + // same as Norfolk Island + // HM: { + // code: '+672', + // unicodeFlag: '🇭🇲', + // svgFlag: require('../../assets/icons/flags/HM.svg'), + // }, KM: { code: '+269', unicodeFlag: '🇰🇲', @@ -1229,16 +1246,18 @@ export const INTERNATIONAL_TELEPHONE_CODES = { unicodeFlag: '🇹🇨', svgFlag: require('../../assets/icons/flags/TC.svg'), }, - TF: { - code: '+672', - unicodeFlag: '🇹🇫', - svgFlag: require('../../assets/icons/flags/TF.svg'), - }, - UM: { - code: '+1', - unicodeFlag: '🇺🇲', - svgFlag: require('../../assets/icons/flags/UM.svg'), - }, + // same as Norfolk Island + // TF: { + // code: '+672', + // unicodeFlag: '🇹🇫', + // svgFlag: require('../../assets/icons/flags/TF.svg'), + // }, + // same as US mainland + // UM: { + // code: '+1', + // unicodeFlag: '🇺🇲', + // svgFlag: require('../../assets/icons/flags/UM.svg'), + // }, VA: { code: '+39', unicodeFlag: '🇻🇦', @@ -1249,25 +1268,26 @@ export const INTERNATIONAL_TELEPHONE_CODES = { unicodeFlag: '🇽🇰', svgFlag: require('../../assets/icons/flags/XK.svg'), }, -} +} satisfies Record< + CountryCode, + { + code: string + unicodeFlag: string + svgFlag: any + } +> -const DEFAULT_PHONE_COUNTRY = 'US' +const DEFAULT_PHONE_COUNTRY = 'US' as const -export function getDefaultCountry(location?: {countryCode?: string}) { +export function getDefaultCountry(location?: { + countryCode?: string +}): CountryCode { + const locationCountryCode = location?.countryCode?.toUpperCase() if ( - location?.countryCode && - location.countryCode.toUpperCase() in INTERNATIONAL_TELEPHONE_CODES + locationCountryCode && + locationCountryCode in INTERNATIONAL_TELEPHONE_CODES ) { - return location.countryCode.toUpperCase() + return locationCountryCode as CountryCode } return DEFAULT_PHONE_COUNTRY } - -export function getPhoneCodeFromCountryCode(countryCode: string) { - const country = - INTERNATIONAL_TELEPHONE_CODES[ - countryCode.toUpperCase() as keyof typeof INTERNATIONAL_TELEPHONE_CODES - ] - if (!country) throw new Error(`Country ${countryCode} not found`) - return country.code -} diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts index c315a8341..0a3a0d545 100644 --- a/src/lib/routes/types.ts +++ b/src/lib/routes/types.ts @@ -67,6 +67,7 @@ export type CommonNavigatorParams = { InterestsSettings: undefined AboutSettings: undefined AppIconSettings: undefined + FindContactsSettings: undefined Search: {q?: string; tab?: 'user' | 'profile' | 'feed'} Hashtag: {tag: string; author?: string} Topic: {topic: string} @@ -87,6 +88,7 @@ export type CommonNavigatorParams = { StarterPackEdit: {rkey?: string} VideoFeed: VideoFeedSourceContext Bookmarks: undefined + FindContactsFlow: undefined } export type BottomTabNavigatorParams = CommonNavigatorParams & { diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts index ea263e22e..8c757a016 100644 --- a/src/lib/statsig/gates.ts +++ b/src/lib/statsig/gates.ts @@ -3,6 +3,7 @@ export type Gate = | 'alt_share_icon' | 'debug_show_feedcontext' | 'debug_subscriptions' + | 'disable_onboarding_find_contacts' | 'explore_show_suggested_feeds' | 'feed_reply_button_open_thread' | 'old_postonboarding' diff --git a/src/logger/metrics.ts b/src/logger/metrics.ts index 43690f1f7..6908f3a05 100644 --- a/src/logger/metrics.ts +++ b/src/logger/metrics.ts @@ -309,6 +309,7 @@ export type MetricEvents = { | 'ImmersiveVideo' | 'ExploreSuggestedAccounts' | 'OnboardingSuggestedAccounts' + | 'FindContacts' } 'profile:followers:view': { contextProfileDid: string @@ -396,6 +397,7 @@ export type MetricEvents = { | 'ImmersiveVideo' | 'ExploreSuggestedAccounts' | 'OnboardingSuggestedAccounts' + | 'FindContacts' } 'chat:create': { logContext: 'ProfileHeader' | 'NewChatDialog' | 'SendViaChatDialog' @@ -625,4 +627,91 @@ export type MetricEvents = { 'blockedGeoOverlay:shown': {} 'geo:debug': {} + + /* + * Find Contacts stuff + */ + + // user presses the button on the new feature NUX + 'contacts:nux:ctaPressed': {} + // user presses the banner NUX + 'contacts:nux:bannerPressed': {} + // user dismisses the banner + 'contacts:nux:bannerDismissed': {} + + // user lands on the contacts step + 'onboarding:contacts:presented': {} + // user pressed "Import Contacts" button to begin flow + 'onboarding:contacts:begin': {} + // skips the step entirely + 'onboarding:contacts:skipPressed': {} + // user shared their contacts + 'onboarding:contacts:contactsShared': {} + // user leaves the matches page + 'onboarding:contacts:nextPressed': { + matchCount: number + followCount: number + dismissedMatchCount: number + } + + // user entered a number + 'contacts:phone:phoneEntered': { + entryPoint: 'Onboarding' | 'Standalone' + } + // user entered the correct one-time-code + 'contacts:phone:phoneVerified': { + entryPoint: 'Onboarding' | 'Standalone' + } + // user responded to the contacts permission prompt + 'contacts:permission:request': { + status: 'granted' | 'denied' + accessLevelIOS?: 'all' | 'limited' | 'none' + } + // contacts were successfully imported and matched + 'contacts:import:success': { + contactCount: number + matchCount: number + entryPoint: 'Onboarding' | 'Standalone' + } + // contacts import failed + 'contacts:import:failure': { + reason: 'noValidNumbers' | 'networkError' | 'unknown' + entryPoint: 'Onboarding' | 'Standalone' + } + // user followed a single match + 'contacts:matches:follow': { + entryPoint: 'Onboarding' | 'Standalone' + } + // user pressed "Follow All" on matches + 'contacts:matches:followAll': { + followCount: number + entryPoint: 'Onboarding' | 'Standalone' + } + // user dismissed a match + 'contacts:matches:dismiss': { + entryPoint: 'Onboarding' | 'Standalone' + } + // user pressed invite to send an SMS to a non-match + 'contacts:matches:invite': { + entryPoint: 'Onboarding' | 'Standalone' + } + // user opened the Find Contacts settings screen + 'contacts:settings:presented': { + hasPreviouslySynced: boolean + matchCount?: number + } + // user followed a single match from settings + 'contacts:settings:follow': {} + // user pressed "Follow All" from settings + 'contacts:settings:followAll': { + followCount: number + } + // user dismissed a match from settings + 'contacts:settings:dismiss': {} + // user re-entered the flow via the resync button + 'contacts:settings:resync': { + daysSinceLastSync: number + } + // user pressed the remove all data button + 'contacts:settings:removeData': {} } diff --git a/src/routes.ts b/src/routes.ts index 1ed913bb2..614b24872 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -69,6 +69,7 @@ export const router = new Router({ '/settings/notifications/reposts-on-reposts', ActivityNotificationSettings: '/settings/notifications/activity', MiscellaneousNotificationSettings: '/settings/notifications/miscellaneous', + FindContactsSettings: '/settings/find-contacts', // support Support: '/support', PrivacyPolicy: '/support/privacy', @@ -91,4 +92,5 @@ export const router = new Router({ StarterPackWizard: '/starter-pack/create', VideoFeed: '/video-feed', Bookmarks: '/saved', + FindContactsFlow: '/find-contacts', }) diff --git a/src/screens/FindContactsFlowScreen.tsx b/src/screens/FindContactsFlowScreen.tsx new file mode 100644 index 000000000..43fab79b5 --- /dev/null +++ b/src/screens/FindContactsFlowScreen.tsx @@ -0,0 +1,77 @@ +import {useCallback, useLayoutEffect, useState} from 'react' +import {LayoutAnimationConfig} from 'react-native-reanimated' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {usePreventRemove} from '@react-navigation/native' + +import {useEnableKeyboardControllerScreen} from '#/lib/hooks/useEnableKeyboardController' +import { + type AllNavigatorParams, + type NativeStackScreenProps, +} from '#/lib/routes/types' +import {isNative} from '#/platform/detection' +import {useSetMinimalShellMode} from '#/state/shell' +import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' +import {FindContactsFlow} from '#/components/contacts/FindContactsFlow' +import {useFindContactsFlowState} from '#/components/contacts/state' +import * as Layout from '#/components/Layout' +import {ScreenTransition} from '#/components/ScreenTransition' + +type Props = NativeStackScreenProps +export function FindContactsFlowScreen({navigation}: Props) { + const {_} = useLingui() + + const [state, dispatch] = useFindContactsFlowState() + + const [transitionDirection, setTransitionDirection] = useState< + 'Forward' | 'Backward' + >('Forward') + + const overrideGoBack = state.step === '2: verify number' + + usePreventRemove(overrideGoBack, () => { + setTransitionDirection('Backward') + dispatch({type: 'BACK'}) + setTimeout(() => { + setTransitionDirection('Forward') + }) + }) + + useEnableKeyboardControllerScreen(true) + + const setMinimalShellMode = useSetMinimalShellMode() + const effect = useCallback(() => { + setMinimalShellMode(true) + return () => setMinimalShellMode(false) + }, [setMinimalShellMode]) + useLayoutEffect(effect) + + return ( + + {isNative ? ( + + + + navigation.canGoBack() + ? navigation.goBack() + : navigation.navigate('FindContactsFlow', undefined, { + pop: true, + }) + } + context="Standalone" + /> + + + ) : ( + + )} + + ) +} diff --git a/src/screens/Messages/ChatList.tsx b/src/screens/Messages/ChatList.tsx index 906fcb017..696c9b812 100644 --- a/src/screens/Messages/ChatList.tsx +++ b/src/screens/Messages/ChatList.tsx @@ -29,7 +29,7 @@ import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {type DialogControlProps, useDialogControl} from '#/components/Dialog' import {NewChat} from '#/components/dms/dialogs/NewChatDialog' import {useRefreshOnFocus} from '#/components/hooks/useRefreshOnFocus' -import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as RetryIcon} from '#/components/icons/ArrowRotateCounterClockwise' +import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as RetryIcon} from '#/components/icons/ArrowRotate' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfoIcon} from '#/components/icons/CircleInfo' import {Message_Stroke2_Corner0_Rounded as MessageIcon} from '#/components/icons/Message' import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' diff --git a/src/screens/Messages/Inbox.tsx b/src/screens/Messages/Inbox.tsx index 6d2fc1cd8..433d2ccd6 100644 --- a/src/screens/Messages/Inbox.tsx +++ b/src/screens/Messages/Inbox.tsx @@ -37,7 +37,7 @@ import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {useRefreshOnFocus} from '#/components/hooks/useRefreshOnFocus' import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeftIcon} from '#/components/icons/Arrow' -import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as RetryIcon} from '#/components/icons/ArrowRotateCounterClockwise' +import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as RetryIcon} from '#/components/icons/ArrowRotate' import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfoIcon} from '#/components/icons/CircleInfo' import {Message_Stroke2_Corner0_Rounded as MessageIcon} from '#/components/icons/Message' diff --git a/src/screens/Onboarding/Layout.tsx b/src/screens/Onboarding/Layout.tsx index 84448d97d..0fcc5488d 100644 --- a/src/screens/Onboarding/Layout.tsx +++ b/src/screens/Onboarding/Layout.tsx @@ -1,13 +1,12 @@ -import React, {useState} from 'react' +import {useEffect, useRef, useState} from 'react' import {ScrollView, View} from 'react-native' -import {Dimensions} from 'react-native' import {useSafeAreaInsets} from 'react-native-safe-area-context' -import {msg} from '@lingui/macro' +import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {isAndroid, isWeb} from '#/platform/detection' import {useOnboardingDispatch} from '#/state/shell' -import {Context} from '#/screens/Onboarding/state' +import {useOnboardingInternalState} from '#/screens/Onboarding/state' import { atoms as a, native, @@ -22,6 +21,7 @@ import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeft} from '#/components/icons import {HEADER_SLOT_SIZE} from '#/components/Layout' import {createPortalGroup} from '#/components/Portal' import {P, Text} from '#/components/Typography' +import {IS_INTERNAL} from '#/env' const ONBOARDING_COL_WIDTH = 420 @@ -34,20 +34,20 @@ export function Layout({children}: React.PropsWithChildren<{}>) { const insets = useSafeAreaInsets() const {gtMobile} = useBreakpoints() const onboardDispatch = useOnboardingDispatch() - const {state, dispatch} = React.useContext(Context) - const scrollview = React.useRef(null) - const prevActiveStep = React.useRef(state.activeStep) + const {state, dispatch} = useOnboardingInternalState() + const scrollview = useRef(null) + const prevActiveStep = useRef(state.activeStep) - React.useEffect(() => { + useEffect(() => { if (state.activeStep !== prevActiveStep.current) { prevActiveStep.current = state.activeStep scrollview.current?.scrollTo({y: 0, animated: false}) } }, [state]) - const paddingTop = gtMobile ? a.py_5xl : a.py_lg const dialogLabel = _(msg`Set up your account`) + const [headerHeight, setHeaderHeight] = useState(0) const [footerHeight, setFooterHeight] = useState(0) return ( @@ -59,33 +59,12 @@ export function Layout({children}: React.PropsWithChildren<{}>) { accessibilityLabel={dialogLabel} accessibilityHint={_(msg`Customizes your Bluesky experience`)} style={[isWeb ? a.fixed : a.absolute, a.inset_0, a.flex_1, t.atoms.bg]}> - {__DEV__ && ( - - )} - - {!gtMobile && ( + {!gtMobile ? ( ) { a.justify_center, a.z_20, a.px_xl, - {top: paddingTop.paddingTop + insets.top - 1}, - ]}> + {paddingTop: (web(tokens.space.lg) ?? 0) + insets.top}, + native([t.atoms.bg, a.pb_xs, {minHeight: 48}]), + web(a.pointer_events_box_none), + ]} + onLayout={evt => setHeaderHeight(evt.nativeEvent.layout.height)}> - {state.hasPrev ? ( + + {state.canGoBack && ( + + )} + + + {IS_INTERNAL && ( - ) : ( - )} - + + + + ) : ( + <> + {IS_INTERNAL && ( + + + + )} + )} + dataSet={{'stable-gutters': 1}} + centerContent={gtMobile}> - - - - {Array(state.totalSteps) - .fill(0) - .map((__, i) => ( - - ))} - - - - - {children} - - - + + {children} @@ -200,7 +188,7 @@ export function Layout({children}: React.PropsWithChildren<{}>) { gtMobile && [a.flex_row, a.justify_between, a.align_center], ]}> {gtMobile && - (state.hasPrev ? ( + (state.canGoBack ? ( + + + + + ) +} diff --git a/src/screens/Onboarding/StepFindContactsIntro/index.web.tsx b/src/screens/Onboarding/StepFindContactsIntro/index.web.tsx new file mode 100644 index 000000000..bb58f202b --- /dev/null +++ b/src/screens/Onboarding/StepFindContactsIntro/index.web.tsx @@ -0,0 +1,3 @@ +export function StepFindContactsIntro() { + throw new Error('StepFindContactsIntro is not available on web') +} diff --git a/src/screens/Onboarding/StepFinished/index.tsx b/src/screens/Onboarding/StepFinished/index.tsx index c1cb3f02f..abf21d51d 100644 --- a/src/screens/Onboarding/StepFinished/index.tsx +++ b/src/screens/Onboarding/StepFinished/index.tsx @@ -1,4 +1,4 @@ -import {useCallback, useContext, useState} from 'react' +import {useCallback, useState} from 'react' import {View} from 'react-native' import { type AppBskyActorDefs, @@ -35,28 +35,23 @@ import { useSetActiveStarterPack, } from '#/state/shell/starter-pack' import { - DescriptionText, OnboardingControls, OnboardingHeaderSlot, - TitleText, } from '#/screens/Onboarding/Layout' -import {Context, type OnboardingState} from '#/screens/Onboarding/state' +import { + type OnboardingState, + useOnboardingInternalState, +} from '#/screens/Onboarding/state' import {bulkWriteFollows} from '#/screens/Onboarding/util' -import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {atoms as a, useBreakpoints} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' -import {IconCircle} from '#/components/IconCircle' import {ArrowRight_Stroke2_Corner0_Rounded as ArrowRight} from '#/components/icons/Arrow' -import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' -import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth' -import {News2_Stroke2_Corner0_Rounded as News} from '#/components/icons/News2' -import {Trending2_Stroke2_Corner2_Rounded as Trending} from '#/components/icons/Trending' import {Loader} from '#/components/Loader' -import {Text} from '#/components/Typography' import * as bsky from '#/types/bsky' import {ValuePropositionPager} from './ValuePropositionPager' export function StepFinished() { - const {state, dispatch} = useContext(Context) + const {state, dispatch} = useOnboardingInternalState() const onboardDispatch = useOnboardingDispatch() const [saving, setSaving] = useState(false) const queryClient = useQueryClient() @@ -247,18 +242,12 @@ export function StepFinished() { gate, ]) - return state.experiments?.onboarding_value_prop ? ( + return ( - ) : ( - ) } @@ -359,90 +348,3 @@ function ValueProposition({ ) } - -function LegacyFinalStep({ - finishOnboarding, - saving, - state, -}: { - finishOnboarding: () => void - saving: boolean - state: OnboardingState -}) { - const t = useTheme() - const {_} = useLingui() - - return ( - - - - - You're ready to go! - - - We hope you have a wonderful time. Remember, Bluesky is: - - - - - - - - Public - - - - Your posts, likes, and blocks are public. Mutes are private. - - - - - - - - - Open - - - Never lose access to your followers or data. - - - - - - - - Flexible - - - Choose the algorithms that power your custom feeds. - - - - - - - - - - ) -} diff --git a/src/screens/Onboarding/StepInterests/index.tsx b/src/screens/Onboarding/StepInterests/index.tsx index 3e5140975..c85993091 100644 --- a/src/screens/Onboarding/StepInterests/index.tsx +++ b/src/screens/Onboarding/StepInterests/index.tsx @@ -8,25 +8,23 @@ import {logEvent} from '#/lib/statsig/statsig' import {capitalize} from '#/lib/strings/capitalize' import {logger} from '#/logger' import { - DescriptionText, OnboardingControls, - TitleText, + OnboardingDescriptionText, + OnboardingPosition, + OnboardingTitleText, } from '#/screens/Onboarding/Layout' -import {Context} from '#/screens/Onboarding/state' +import {useOnboardingInternalState} from '#/screens/Onboarding/state' import {InterestButton} from '#/screens/Onboarding/StepInterests/InterestButton' import {atoms as a} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Toggle from '#/components/forms/Toggle' -import {IconCircle} from '#/components/IconCircle' -import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron' -import {Hashtag_Stroke2_Corner0_Rounded as Hashtag} from '#/components/icons/Hashtag' import {Loader} from '#/components/Loader' export function StepInterests() { const {_} = useLingui() const interestsDisplayNames = useInterestsDisplayNames() - const {state, dispatch} = React.useContext(Context) + const {state, dispatch} = useOnboardingInternalState() const [saving, setSaving] = React.useState(false) const [selectedInterests, setSelectedInterests] = React.useState( state.interestsStepResults.selectedInterests.map(i => i), @@ -53,17 +51,16 @@ export function StepInterests() { }, [selectedInterests, setSaving, dispatch]) return ( - - - - + + + What are your interests? - - + + We'll use this to help customize your experience. - + - + Continue - + {saving && } diff --git a/src/screens/Onboarding/StepProfile/index.tsx b/src/screens/Onboarding/StepProfile/index.tsx index 453184639..787711bf4 100644 --- a/src/screens/Onboarding/StepProfile/index.tsx +++ b/src/screens/Onboarding/StepProfile/index.tsx @@ -19,11 +19,12 @@ import {isCancelledError} from '#/lib/strings/errors' import {logger} from '#/logger' import {isNative, isWeb} from '#/platform/detection' import { - DescriptionText, OnboardingControls, - TitleText, + OnboardingDescriptionText, + OnboardingPosition, + OnboardingTitleText, } from '#/screens/Onboarding/Layout' -import {Context} from '#/screens/Onboarding/state' +import {useOnboardingInternalState} from '#/screens/Onboarding/state' import {AvatarCircle} from '#/screens/Onboarding/StepProfile/AvatarCircle' import {AvatarCreatorCircle} from '#/screens/Onboarding/StepProfile/AvatarCreatorCircle' import {AvatarCreatorItems} from '#/screens/Onboarding/StepProfile/AvatarCreatorItems' @@ -32,13 +33,10 @@ import { type PlaceholderCanvasRef, } from '#/screens/Onboarding/StepProfile/PlaceholderCanvas' import {atoms as a, useBreakpoints, useTheme} from '#/alf' -import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import {Button, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper' -import {IconCircle} from '#/components/IconCircle' -import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron' import {CircleInfo_Stroke2_Corner0_Rounded} from '#/components/icons/CircleInfo' -import {StreamingLive_Stroke2_Corner0_Rounded as StreamingLive} from '#/components/icons/StreamingLive' import {Text} from '#/components/Typography' import {type AvatarColor, avatarColors, type Emoji, emojiItems} from './types' @@ -78,7 +76,7 @@ export function StepProfile() { const creatorControl = Dialog.useDialogControl() const [error, setError] = React.useState('') - const {state, dispatch} = React.useContext(Context) + const {state, dispatch} = useOnboardingInternalState() const [avatar, setAvatar] = React.useState({ image: state.profileStepResults?.image, placeholder: state.profileStepResults.creatorState?.emoji || emojiItems.at, @@ -237,19 +235,21 @@ export function StepProfile() { return ( - - - - Give your profile a face - - - - Help people know you're not a bot by uploading a picture or creating - an avatar. - - + + + + + Give your profile a face + + + + Help people know you're not a bot by uploading a picture or + creating an avatar. + + + + style={[a.w_full, a.align_center, {paddingTop: gtMobile ? 80 : 60}]}> + )} + + + + ) +} + +function StatusHeader({ + numMatches, + isPending, + isAnyUnfollowed, +}: { + numMatches: number + isPending: boolean + isAnyUnfollowed: boolean +}) { + const {_} = useLingui() + const agent = useAgent() + const queryClient = useQueryClient() + const {currentAccount} = useSession() + + const { + mutate: onFollowAll, + isPending: isFollowingAll, + isSuccess: hasFollowedAll, + } = useMutation({ + mutationFn: async () => { + const didsToFollow = [] + + let cursor: string | undefined + do { + const page = await agent.app.bsky.contact.getMatches({ + limit: 100, + cursor, + }) + cursor = page.data.cursor + for (const profile of page.data.matches) { + if ( + profile.did !== currentAccount?.did && + !isBlockedOrBlocking(profile) && + !isMuted(profile) && + !profile.viewer?.following + ) { + didsToFollow.push(profile.did) + } + } + } while (cursor) + + logger.metric('contacts:settings:followAll', { + followCount: didsToFollow.length, + }) + + const uris = await wait(500, bulkWriteFollows(agent, didsToFollow)) + + for (const did of didsToFollow) { + const uri = uris.get(did) + updateProfileShadow(queryClient, did, { + followingUri: uri, + }) + } + }, + onSuccess: () => { + Toast.show(_(msg`Followed all matches`), {type: 'success'}) + }, + onError: err => { + if (isNetworkError(err)) { + Toast.show( + _( + msg`Could not follow all matches - please check your network connection.`, + ), + {type: 'error'}, + ) + } else { + logger.error('Failed to follow all matches', {safeMessage: err}) + Toast.show(_(msg`Could not follow all matches. ${cleanError(err)}`), { + type: 'error', + }) + } + }, + }) + + if (numMatches > 0) { + if (isPending) { + return ( + + + + ) + } + + return ( + + + + + {isAnyUnfollowed && ( + + )} + + ) + } + + return null +} + +function StatusFooter({syncedAt}: {syncedAt: string}) { + const {_, i18n} = useLingui() + const t = useTheme() + const agent = useAgent() + const queryClient = useQueryClient() + + const {mutate: removeData, isPending} = useMutation({ + mutationFn: async () => { + await agent.app.bsky.contact.removeData({}) + }, + onMutate: () => logger.metric('contacts:settings:removeData', {}), + onSuccess: () => { + Toast.show(_(msg`Contacts removed`)) + queryClient.setQueryData( + findContactsStatusQueryKey, + {syncStatus: undefined}, + ) + }, + onError: err => { + if (isNetworkError(err)) { + Toast.show( + _( + msg`Failed to remove data due to a network error, please check your internet connection.`, + ), + {type: 'error'}, + ) + } else { + logger.error('Remove data failed', {safeMessage: err}) + Toast.show(_(msg`Failed to remove data. ${cleanError(err)}`), { + type: 'error', + }) + } + }, + }) + + return ( + + + + Contacts uploaded + + + + We will notify you when we find your friends. + + + + Uploaded on{' '} + {i18n.date(new Date(syncedAt), { + dateStyle: 'long', + })} + + + + { + const daysSinceLastSync = Math.floor( + (Date.now() - new Date(syncedAt).getTime()) / + (1000 * 60 * 60 * 24), + ) + logger.metric('contacts:settings:resync', { + daysSinceLastSync, + }) + }} + size="small" + color="primary_subtle" + style={[a.mt_xs]}> + + + Resync contacts + + + + + + + Delete contacts + + + + Bluesky stores your contacts as encoded data. Removing your contacts + will immediately delete this data. + + + + + + ) +} diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx index 1703036b5..6b0e184c0 100644 --- a/src/screens/Settings/Settings.tsx +++ b/src/screens/Settings/Settings.tsx @@ -37,6 +37,7 @@ import {atoms as a, platform, tokens, useBreakpoints, useTheme} from '#/alf' import {AgeAssuranceDismissibleNotice} from '#/components/ageAssurance/AgeAssuranceDismissibleNotice' import {AvatarStackWithFetch} from '#/components/AvatarStack' import {Button, ButtonText} from '#/components/Button' +import {useIsFindContactsFeatureEnabledBasedOnGeolocation} from '#/components/contacts/country-allowlist' import {useDialogControl} from '#/components/Dialog' import {SwitchAccountDialog} from '#/components/dialogs/SwitchAccount' import {Accessibility_Stroke2_Corner2_Rounded as AccessibilityIcon} from '#/components/icons/Accessibility' @@ -45,6 +46,7 @@ import {BubbleInfo_Stroke2_Corner2_Rounded as BubbleInfoIcon} from '#/components import {ChevronTop_Stroke2_Corner0_Rounded as ChevronUpIcon} from '#/components/icons/Chevron' import {CircleQuestion_Stroke2_Corner2_Rounded as CircleQuestionIcon} from '#/components/icons/CircleQuestion' import {CodeBrackets_Stroke2_Corner2_Rounded as CodeBracketsIcon} from '#/components/icons/CodeBrackets' +import {Contacts_Stroke2_Corner2_Rounded as ContactsIcon} from '#/components/icons/Contacts' import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid' import {Earth_Stroke2_Corner2_Rounded as EarthIcon} from '#/components/icons/Globe' import {Lock_Stroke2_Corner2_Rounded as LockIcon} from '#/components/icons/Lock' @@ -89,6 +91,8 @@ export function SettingsScreen({}: Props) { const {pendingDid, onPressSwitchAccount} = useAccountSwitcher() const [showAccounts, setShowAccounts] = useState(false) const [showDevOptions, setShowDevOptions] = useState(false) + const findContactsEnabled = + useIsFindContactsFeatureEnabledBasedOnGeolocation() return ( @@ -207,6 +211,16 @@ export function SettingsScreen({}: Props) { Content and media + {isNative && findContactsEnabled && ( + + + + Find friends from contacts + + + )} diff --git a/src/screens/Settings/components/OTAInfo.tsx b/src/screens/Settings/components/OTAInfo.tsx index ee63d150f..8b7ca9c23 100644 --- a/src/screens/Settings/components/OTAInfo.tsx +++ b/src/screens/Settings/components/OTAInfo.tsx @@ -5,7 +5,7 @@ import {useMutation, useQuery} from '@tanstack/react-query' import * as Toast from '#/view/com/util/Toast' import {Button, ButtonIcon, ButtonText} from '#/components/Button' -import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as RetryIcon} from '#/components/icons/ArrowRotateCounterClockwise' +import {ArrowRotateCounterClockwise_Stroke2_Corner0_Rounded as RetryIcon} from '#/components/icons/ArrowRotate' import {Shapes_Stroke2_Corner0_Rounded as ShapesIcon} from '#/components/icons/Shapes' import {Loader} from '#/components/Loader' import * as SettingsList from '../components/SettingsList' diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts index 5ee7c9c42..0fdef08ad 100644 --- a/src/state/cache/profile-shadow.ts +++ b/src/state/cache/profile-shadow.ts @@ -7,6 +7,7 @@ import {batchedUpdates} from '#/lib/batchedUpdates' import {findAllProfilesInQueryData as findAllProfilesInActivitySubscriptionsQueryData} from '#/state/queries/activity-subscriptions' import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '#/state/queries/actor-search' import {findAllProfilesInQueryData as findAllProfilesInExploreFeedPreviewsQueryData} from '#/state/queries/explore-feed-previews' +import {findAllProfilesInQueryData as findAllProfilesInContactMatchesQueryData} from '#/state/queries/find-contacts' import {findAllProfilesInQueryData as findAllProfilesInKnownFollowersQueryData} from '#/state/queries/known-followers' import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '#/state/queries/list-members' import {findAllProfilesInQueryData as findAllProfilesInListConvosQueryData} from '#/state/queries/messages/list-conversations' @@ -256,4 +257,5 @@ function* findProfilesInCache( yield* findAllProfilesInExploreFeedPreviewsQueryData(queryClient, did) yield* findAllProfilesInActivitySubscriptionsQueryData(queryClient, did) yield* findAllProfilesInNotifsQueryData(queryClient, did) + yield* findAllProfilesInContactMatchesQueryData(queryClient, did) } diff --git a/src/state/queries/find-contacts.ts b/src/state/queries/find-contacts.ts new file mode 100644 index 000000000..b1eb6c9c5 --- /dev/null +++ b/src/state/queries/find-contacts.ts @@ -0,0 +1,128 @@ +import {type AppBskyContactGetMatches} from '@atproto/api' +import { + type InfiniteData, + type QueryClient, + useInfiniteQuery, + useQuery, +} from '@tanstack/react-query' + +import {useAgent} from '#/state/session' +import {type Match} from '#/components/contacts/state' +import type * as bsky from '#/types/bsky' +import {STALE} from '.' + +const RQ_KEY_ROOT = 'find-contacts' +export const findContactsStatusQueryKey = [RQ_KEY_ROOT, 'sync-status'] + +export function useContactsSyncStatusQuery() { + const agent = useAgent() + + return useQuery({ + queryKey: findContactsStatusQueryKey, + queryFn: async () => { + const status = await agent.app.bsky.contact.getSyncStatus() + return status.data + }, + staleTime: STALE.SECONDS.THIRTY, + }) +} + +export const findContactsGetMatchesQueryKey = [RQ_KEY_ROOT, 'matches'] + +export function useContactsMatchesQuery() { + const agent = useAgent() + + return useInfiniteQuery({ + queryKey: findContactsGetMatchesQueryKey, + queryFn: async ({pageParam}) => { + const matches = await agent.app.bsky.contact.getMatches({ + cursor: pageParam, + }) + return matches.data + }, + initialPageParam: undefined as string | undefined, + getNextPageParam: lastPage => lastPage.cursor, + staleTime: STALE.MINUTES.ONE, + }) +} + +export function optimisticRemoveMatch(queryClient: QueryClient, did: string) { + queryClient.setQueryData>( + findContactsGetMatchesQueryKey, + old => { + if (!old) return old + + return { + ...old, + pages: old.pages.map(page => ({ + ...page, + matches: page.matches.filter(match => match.did !== did), + })), + } + }, + ) +} + +export const findContactsMatchesPassthroughQueryKey = (dids: string[]) => [ + RQ_KEY_ROOT, + 'passthrough', + dids, +] + +/** + * DIRTY HACK WARNING! + * + * The only way to get shadow state to work is to put it into React Query. + * However, when we get the matches it's via a POST, not a GET, so we use a mutation, + * which means we can't use shadowing! + * + * In lieu of any better ideas, I'm just going to take the contacts we have and + * "launder" them through a dummy query. This will then return "shadow-able" profiles. + */ +export function useMatchesPassthroughQuery(matches: Match[]) { + const dids = matches.map(match => match.profile.did) + const {data} = useQuery({ + queryKey: findContactsMatchesPassthroughQueryKey(dids), + queryFn: () => { + return matches + }, + }) + return data ?? matches +} + +export function* findAllProfilesInQueryData( + queryClient: QueryClient, + did: string, +): Generator { + const queryDatas = queryClient.getQueriesData< + InfiniteData + >({ + queryKey: findContactsGetMatchesQueryKey, + }) + for (const [_queryKey, queryData] of queryDatas) { + if (!queryData?.pages) { + continue + } + for (const page of queryData?.pages) { + for (const match of page.matches) { + if (match.did === did) { + yield match + } + } + } + } + + const passthroughQueryDatas = queryClient.getQueriesData({ + queryKey: [RQ_KEY_ROOT, 'passthrough'], + }) + for (const [_queryKey, queryData] of passthroughQueryDatas) { + if (!queryData) { + continue + } + for (const match of queryData) { + if (match.profile.did === did) { + yield match.profile + } + } + } +} diff --git a/src/state/queries/notifications/feed.ts b/src/state/queries/notifications/feed.ts index 7959c67a7..57d83cb5b 100644 --- a/src/state/queries/notifications/feed.ts +++ b/src/state/queries/notifications/feed.ts @@ -319,7 +319,10 @@ export function* findAllProfilesInQueryData( } for (const page of queryData?.pages) { for (const item of page.items) { - if (item.type === 'follow' && item.notification.author.did === did) { + if ( + (item.type === 'follow' || item.type === 'contact-match') && + item.notification.author.did === did + ) { yield item.notification.author } else if ( item.type !== 'starterpack-joined' && diff --git a/src/state/queries/notifications/types.ts b/src/state/queries/notifications/types.ts index a7b837086..1b66dd175 100644 --- a/src/state/queries/notifications/types.ts +++ b/src/state/queries/notifications/types.ts @@ -49,6 +49,7 @@ type OtherNotificationType = | 'like-via-repost' | 'repost-via-repost' | 'subscribed-post' + | 'contact-match' | 'unknown' type FeedNotificationBase = { diff --git a/src/state/queries/notifications/util.ts b/src/state/queries/notifications/util.ts index a47659a84..a8c15e82c 100644 --- a/src/state/queries/notifications/util.ts +++ b/src/state/queries/notifications/util.ts @@ -273,7 +273,8 @@ function toKnownType( notif.reason === 'unverified' || notif.reason === 'like-via-repost' || notif.reason === 'repost-via-repost' || - notif.reason === 'subscribed-post' + notif.reason === 'subscribed-post' || + notif.reason === 'contact-match' ) { return notif.reason as NotificationType } diff --git a/src/state/queries/nuxs/definitions.ts b/src/state/queries/nuxs/definitions.ts index 165649447..6c03c936a 100644 --- a/src/state/queries/nuxs/definitions.ts +++ b/src/state/queries/nuxs/definitions.ts @@ -10,6 +10,8 @@ export enum Nux { AgeAssuranceDismissibleNotice = 'AgeAssuranceDismissibleNotice', AgeAssuranceDismissibleFeedBanner = 'AgeAssuranceDismissibleFeedBanner', BookmarksAnnouncement = 'BookmarksAnnouncement', + FindContactsAnnouncement = 'FindContactsAnnouncement', + FindContactsDismissibleBanner = 'FindContactsDismissibleBanner', /* * Blocking announcements. New IDs are required for each new announcement. @@ -52,6 +54,14 @@ export type AppNux = BaseNux< id: Nux.BookmarksAnnouncement data: undefined } + | { + id: Nux.FindContactsAnnouncement + data: undefined + } + | { + id: Nux.FindContactsDismissibleBanner + data: undefined + } > export const NuxSchemas: Record | undefined> = { @@ -63,4 +73,6 @@ export const NuxSchemas: Record | undefined> = { [Nux.AgeAssuranceDismissibleFeedBanner]: undefined, [Nux.PolicyUpdate202508]: undefined, [Nux.BookmarksAnnouncement]: undefined, + [Nux.FindContactsAnnouncement]: undefined, + [Nux.FindContactsDismissibleBanner]: undefined, } diff --git a/src/view/com/notifications/NotificationFeedItem.tsx b/src/view/com/notifications/NotificationFeedItem.tsx index 6d3f57b71..8d622f3bf 100644 --- a/src/view/com/notifications/NotificationFeedItem.tsx +++ b/src/view/com/notifications/NotificationFeedItem.tsx @@ -1,11 +1,4 @@ -import { - memo, - type ReactElement, - useCallback, - useEffect, - useMemo, - useState, -} from 'react' +import {memo, useCallback, useEffect, useMemo, useState} from 'react' import { Animated, type GestureResponderEvent, @@ -61,6 +54,7 @@ import { ChevronBottom_Stroke2_Corner0_Rounded as ChevronDownIcon, ChevronTop_Stroke2_Corner0_Rounded as ChevronUpIcon, } from '#/components/icons/Chevron' +import {Contacts_Filled_Corner2_Rounded as ContactsIconFilled} from '#/components/icons/Contacts' import {Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled} from '#/components/icons/Heart2' import {PersonPlus_Filled_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' @@ -116,6 +110,7 @@ let NotificationFeedItem = ({ break } case 'follow': + case 'contact-match': case 'verified': case 'unverified': { return makeProfileLink(item.notification.author) @@ -279,7 +274,7 @@ let NotificationFeedItem = ({ : '' let a11yLabel = '' - let notificationContent: ReactElement + let notificationContent: React.ReactElement let icon = ( + } else if (item.type === 'contact-match') { + a11yLabel = _(msg`Your contact ${firstAuthorName} is on Bluesky`) + notificationContent = ( + Your contact {firstAuthorLink} is on Bluesky + ) + icon = ( + + ) } else if (item.type === 'feedgen-like') { a11yLabel = hasMultipleAuthors ? _( @@ -438,7 +441,7 @@ let NotificationFeedItem = ({ notificationContent = hasMultipleAuthors ? ( {firstAuthorLink} and{' '} - + {firstAuthorLink} and{' '} - + - {item.type === 'follow' && !hasMultipleAuthors && !isFollowBack ? ( + {(item.type === 'follow' && !hasMultipleAuthors && !isFollowBack) || + (item.type === 'contact-match' && + !item.notification.author.viewer?.following) ? ( ) : null} {item.type === 'post-like' || @@ -809,6 +814,7 @@ function FollowBackButton({profile}: {profile: AppBskyActorDefs.ProfileView}) { } const isFollowing = profileShadow.viewer.following + const isFollowedBy = profileShadow.viewer.followedBy const followingLabel = _( msg({ message: 'Following', @@ -832,14 +838,14 @@ function FollowBackButton({profile}: {profile: AppBskyActorDefs.ProfileView}) { ) : ( )} diff --git a/src/view/com/profile/ProfileFollows.tsx b/src/view/com/profile/ProfileFollows.tsx index 243f3705b..44d4aeaee 100644 --- a/src/view/com/profile/ProfileFollows.tsx +++ b/src/view/com/profile/ProfileFollows.tsx @@ -12,6 +12,7 @@ import {isWeb} from '#/platform/detection' import {useProfileFollowsQuery} from '#/state/queries/profile-follows' import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {useSession} from '#/state/session' +import {FindContactsBannerNUX} from '#/components/contacts/FindContactsBannerNUX' import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2' import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' import {List} from '../util/List' @@ -208,6 +209,7 @@ export function ProfileFollows({name}: {name: string}) { onEndReached={onEndReached} onEndReachedThreshold={4} onItemSeen={onItemSeen} + ListHeaderComponent={} ListFooterComponent={