From 93415948c2ed22e391e09c953284eed10ec5cb76 Mon Sep 17 00:00:00 2001 From: natjms Date: Mon, 15 Mar 2021 13:07:55 -0300 Subject: [PATCH 1/7] Add rendering for profile metadata --- src/components/pages/profile.js | 205 ++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 63 deletions(-) diff --git a/src/components/pages/profile.js b/src/components/pages/profile.js index ea5c299..adf8179 100644 --- a/src/components/pages/profile.js +++ b/src/components/pages/profile.js @@ -1,5 +1,13 @@ import React, { useState, useEffect } from "react"; -import { View, Dimensions, Image, Text, TouchableWithoutFeedback } from "react-native"; +import { + View, + Dimensions, + Image, + Text, + TouchableWithoutFeedback +} from "react-native"; + +import * as Linking from "expo-linking"; import { activeOrNot } from "src/interface/interactions" @@ -37,6 +45,54 @@ const TEST_POSTS = [ } ]; +const TEST_PROFILE = { + username: "njms", + acct: "njms", + display_name: "Nat🔆", + locked: false, + bot: false, + note: "Yeah heart emoji.", + avatar: TEST_IMAGE, + followers_count: "1 jillion", + statuses_count: 334, + fields: [ + { + name: "Blog", + value: "https://njms.ca", + verified_at: "some time" + }, + { + name: "Github", + value: "https://github.com/natjms", + verified_at: null + } + ] +}; + +function withoutHTML(string) { + return string.replaceAll(/<[^>]*>/ig, ""); +} + +const HTMLLink = ({link}) => { + let url = link.match(/https?:\/\/\w+\.\w+/); + + if (url) { + return ( + { + Linking.openURL(url[0]); + } + }> + { withoutHTML(link) } + + ); + } else { + return ( { withoutHTML(link) } ); + } +} + const ProfileJsx = ({navigation}) => { return ( { const ProfileDisplayJsx = ({navigation}) => { const accountName = navigation.getParam("acct", ""); let [state, setState] = useState({ - avatar: "", - displayName: "Somebody", - username: "somebody", - statusesCount: 0, - followersCount: 0, - followingCount: 0, - note: "Not much here...", - unread_notifications: false, - own: false, loaded: false }); @@ -80,21 +127,11 @@ const ProfileDisplayJsx = ({navigation}) => { useEffect(() => { // do something to get the profile based on given account name - if (!state.loaded) { - setState({ - avatar: TEST_IMAGE, - displayName: "Nat🔆", - username: "njms", - statusesCount: 334, - followersCount: "1 jillion", - followingCount: 7, - note: "Yeah heart emoji.", - own: true, - unread_notifs: false, - loaded: true - }); - } - }); + setState({ + profile: TEST_PROFILE, + loaded: true + }); + }, []); let profileButton; if (state.own) { @@ -117,45 +154,71 @@ const ProfileDisplayJsx = ({navigation}) => { return ( - - - - - - {state.displayName} + { state.loaded ? + <> + + + + + + {state.profile.display_name} + + + @{state.profile.username } + + + + + + + + { state.profile.statuses_count } posts •  + { state.profile.followers_count } followers •  + { state.profile.following_count } following - @{state.username} + + {state.profile.note} + + + { + state.profile.fields.map((row, i) => + + + + + ) + } +
+ { row.name } + + + + +
+ {profileButton}
- - - -
- - { state.statusesCount } posts •  - { state.followersCount } followers •  - { state.followingCount } following - - - {state.note} - - {profileButton} -
- { - navigation.navigate("ViewPost", { - id: id, - originTab: "Profile" - }); - } - } /> + { + navigation.navigate("ViewPost", { + id: id, + originTab: "Profile" + }); + } + } /> + + : + }
); }; @@ -171,7 +234,6 @@ const styles = { display: "flex", flexDirection: "row", alignItems: "center", - marginBottom: screen_width / 20 }, displayName: { @@ -199,6 +261,23 @@ const styles = { fontSize: 16, marginTop: 10, }, + + metaData: { + marginTop: 20 + }, + row: { + padding: 10 + }, + rowName: { + width: "33%", + textAlign: "center" + }, + rowValue: { width: "67%" }, + anchor: { + color: "#888", + textDecoration: "underline" + }, + button: { borderWidth: 1, borderStyle: "solid", @@ -217,4 +296,4 @@ const styles = { }; export { ViewProfileJsx, ProfileDisplayJsx }; -export default ProfileJsx; \ No newline at end of file +export default ProfileJsx; From 59cf1ff4512c162ee0ebee917427a694459540ec Mon Sep 17 00:00:00 2001 From: natjms Date: Wed, 17 Mar 2021 15:14:14 -0300 Subject: [PATCH 2/7] Display only mutual followers on profiles --- src/components/pages/profile.js | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/components/pages/profile.js b/src/components/pages/profile.js index adf8179..2d7a4ae 100644 --- a/src/components/pages/profile.js +++ b/src/components/pages/profile.js @@ -69,10 +69,34 @@ const TEST_PROFILE = { ] }; +const TEST_YOUR_FOLLOWERS = [ + { id: 1 }, + { id: 2 }, + { id: 3 }, + { id: 4 }, + { id: 5 }, +]; + +const TEST_THEIR_FOLLOWERS = [ + { id: 2 }, + { id: 3 }, + { id: 4 }, + { id: 6 }, +]; + function withoutHTML(string) { return string.replaceAll(/<[^>]*>/ig, ""); } +function getMutuals(yours, theirs) { + // Where yours and theirs are arrays of followers, as returned by the oAPI + + const idify = ({id}) => id; + const asIDs = new Set(theirs.map(idify)); + + return yours.filter(x => asIDs.has(idify(x))); +} + const HTMLLink = ({link}) => { let url = link.match(/https?:\/\/\w+\.\w+/); @@ -129,6 +153,7 @@ const ProfileDisplayJsx = ({navigation}) => { // do something to get the profile based on given account name setState({ profile: TEST_PROFILE, + mutuals: getMutuals(TEST_YOUR_FOLLOWERS, TEST_THEIR_FOLLOWERS), loaded: true }); }, []); @@ -178,8 +203,7 @@ const ProfileDisplayJsx = ({navigation}) => {
{ state.profile.statuses_count } posts •  - { state.profile.followers_count } followers •  - { state.profile.following_count } following + { state.mutuals.length } mutuals {state.profile.note} From 44da58a569516272f5587632061247f5d08442fd Mon Sep 17 00:00:00 2001 From: natjms Date: Sun, 21 Mar 2021 10:56:45 -0300 Subject: [PATCH 3/7] Add moderation context menu to profiles --- src/components/moderate-menu.js | 51 +++++++++++++++++++++++++++++++++ src/components/pages/profile.js | 31 ++++++++++++++------ src/components/posts/post.js | 34 ++++------------------ 3 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 src/components/moderate-menu.js diff --git a/src/components/moderate-menu.js b/src/components/moderate-menu.js new file mode 100644 index 0000000..21987ee --- /dev/null +++ b/src/components/moderate-menu.js @@ -0,0 +1,51 @@ +import React from "react"; +import { Dimensions, View, Image } from "react-native"; +import { + Menu, + MenuOptions, + MenuOption, + MenuTrigger, + renderers +} from "react-native-popup-menu"; + +const { SlideInMenu } = renderers; + +const SCREEN_WIDTH = Dimensions.get("window").width; + +const ModerateMenuJsx = (props) => { + const optionsStyles = { + optionWrapper: { // The wrapper around a single option + paddingLeft: SCREEN_WIDTH / 15, + paddingTop: SCREEN_WIDTH / 30, + paddingBottom: SCREEN_WIDTH / 30 + }, + optionsWrapper: { // The wrapper around all options + marginTop: SCREEN_WIDTH / 20, + marginBottom: SCREEN_WIDTH / 20, + }, + optionsContainer: { // The Animated.View + borderTopLeftRadius: 10, + borderTopRightRadius: 10 + } + }; + + return ( + + + + + + + + + + + + + + ); +} + +export { ModerateMenuJsx as default }; diff --git a/src/components/pages/profile.js b/src/components/pages/profile.js index 2d7a4ae..d9f2c28 100644 --- a/src/components/pages/profile.js +++ b/src/components/pages/profile.js @@ -17,6 +17,8 @@ import { ScreenWithFullNavigationJsx } from "src/components/navigation/navigators"; +import ModerateMenuJsx from "src/components/moderate-menu.js"; + const TEST_IMAGE = "https://cache.desktopnexus.com/thumbseg/2255/2255124-bigthumbnail.jpg"; const TEST_POSTS = [ { @@ -141,7 +143,8 @@ const ViewProfileJsx = ({navigation}) => { const ProfileDisplayJsx = ({navigation}) => { const accountName = navigation.getParam("acct", ""); let [state, setState] = useState({ - loaded: false + loaded: false, + own: false }); const notif_pack = { @@ -195,11 +198,22 @@ const ProfileDisplayJsx = ({navigation}) => { @{state.profile.username } - - - + { + state.own ? + + + + : + } { state.profile.statuses_count } posts •  @@ -270,10 +284,11 @@ const styles = { borderRadius: "100%", marginRight: screen_width / 20 }, - bell: { + profileHeaderIcon: { width: screen_width / 12, height: screen_width / 12, - + }, + profileContextContainer: { marginLeft: "auto", marginRight: screen_width / 15 }, diff --git a/src/components/posts/post.js b/src/components/posts/post.js index 9e38742..52b9b29 100644 --- a/src/components/posts/post.js +++ b/src/components/posts/post.js @@ -8,26 +8,15 @@ import { ScrollView } from "react-native"; -import { - Menu, - MenuOptions, - MenuOption, - MenuTrigger, - renderers -} from "react-native-popup-menu"; - - -import { pluralize, timeToAge } from "src/interface/rendering" +import { pluralize, timeToAge} from "src/interface/rendering" import PostActionBarJsx from "src/components/posts/post-action-bar"; +import ModerateMenuJsx from "src/components/moderate-menu.js"; + const SCREEN_WIDTH = Dimensions.get("window").width; const TEST_IMAGE = "https://cache.desktopnexus.com/thumbseg/2255/2255124-bigthumbnail.jpg"; -// Extract the SlideInMenu function from `renderers` -// This will be used in RawPostJsx -const { SlideInMenu } = renderers; - function getAutoHeight(w1, h1, w2) { /* Given the original dimensions and the new width, calculate what would @@ -90,20 +79,9 @@ export const RawPostJsx = (props) => { source = { { uri: props.data.avatar } } /> { props.data.username } - - - - - - - - - - - - + { props.data.media_attachments.length > 1 ? From a13dcc48a71526f29fe874da6f2c78188b435601 Mon Sep 17 00:00:00 2001 From: natjms Date: Tue, 23 Mar 2021 15:07:20 -0300 Subject: [PATCH 4/7] Add a secondary page to list users, particularly mutual followers --- src/App.js | 30 ++++--- src/components/pages/profile.js | 12 ++- src/components/pages/user-list.js | 145 ++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+), 15 deletions(-) create mode 100644 src/components/pages/user-list.js diff --git a/src/App.js b/src/App.js index 9b7d6db..6e909b7 100644 --- a/src/App.js +++ b/src/App.js @@ -15,23 +15,25 @@ import DiscoverJsx from 'src/components/pages/discover'; import SearchJsx from 'src/components/pages/discover/search'; import ViewHashtagJsx from 'src/components/pages/discover/view-hashtag'; import NotificationsJsx from 'src/components/pages/profile/notifications'; +import UserListJsx from "src/components/pages/user-list.js"; const Stack = createStackNavigator({ - Feed: { screen: FeedJsx, }, - Discover: { screen: DiscoverJsx }, - Notifications: { screen: NotificationsJsx }, - Profile: { screen: ProfileJsx, }, - Search: { screen: SearchJsx }, - ViewPost: { screen: ViewPostJsx }, - ViewComments: { screen: ViewCommentsJsx }, - ViewProfile: { screen: ViewProfileJsx }, - ViewHashtag: { screen: ViewHashtagJsx } + Feed: { screen: FeedJsx, }, + Discover: { screen: DiscoverJsx }, + Notifications: { screen: NotificationsJsx }, + Profile: { screen: ProfileJsx, }, + Search: { screen: SearchJsx }, + ViewPost: { screen: ViewPostJsx }, + ViewComments: { screen: ViewCommentsJsx }, + ViewProfile: { screen: ViewProfileJsx }, + ViewHashtag: { screen: ViewHashtagJsx }, + UserList: { screen: UserListJsx } }, { - initialRouteKey: "Feed", - headerMode: "none", - navigationOptions: { - headerVisible: false - } + initialRouteKey: "Feed", + headerMode: "none", + navigationOptions: { + headerVisible: false + } }); const App = createAppContainer(Stack); diff --git a/src/components/pages/profile.js b/src/components/pages/profile.js index d9f2c28..c8f761c 100644 --- a/src/components/pages/profile.js +++ b/src/components/pages/profile.js @@ -217,7 +217,17 @@ const ProfileDisplayJsx = ({navigation}) => { { state.profile.statuses_count } posts •  - { state.mutuals.length } mutuals + { + navigation.navigate("UserList", { + data: [/*Some array of users*/], + context: "Your mutual followers with " + state.profile.display_name + }); + } + }> + { state.mutuals.length } mutuals + {state.profile.note} diff --git a/src/components/pages/user-list.js b/src/components/pages/user-list.js new file mode 100644 index 0000000..74616b1 --- /dev/null +++ b/src/components/pages/user-list.js @@ -0,0 +1,145 @@ +import React from "react"; +import { + SafeAreaView, + View, + Image, + Text, + FlatList, + Dimensions, + TouchableOpacity, +} from "react-native"; + +import { ScreenWithBackBarJsx } from "src/components/navigation/navigators.js"; +import ModerateMenuJsx from "src/components/moderate-menu.js"; + +const TEST_PROFILE = { + username: "njms", + acct: "njms", + display_name: "Nat🔆", + locked: false, + bot: false, + note: "Yeah heart emoji.", + avatar: "https://cache.desktopnexus.com/thumbseg/2255/2255124-bigthumbnail.jpg", + followers_count: "1 jillion", + statuses_count: 334, + fields: [ + { + name: "Blog", + value: "https://njms.ca", + verified_at: "some time" + }, + { + name: "Github", + value: "https://github.com/natjms", + verified_at: null + } + ] +}; + +const TEST_DATA = [ + {...TEST_PROFILE, id: 1}, + {...TEST_PROFILE, id: 2}, + {...TEST_PROFILE, id: 3}, + {...TEST_PROFILE, id: 4}, + {...TEST_PROFILE, id: 5}, + {...TEST_PROFILE, id: 6} +] + +function renderItemFactory(navigation) { + // Returns a renderItem function with the context of props.navigation so + // that it can enable the person to navigate to the selected account. + return ({item}) => ( + + { + navigation.navigate("Profile", { acct: item.acct }); + } + }> + + + + + @{ item.acct } + + + { item.display_name } + + + + + + + ); +} + +const UserListJsx = ({navigation}) => { + // const data = navigation.getParam("data", []) + const data = TEST_DATA; + const context = navigation.getParam("context", ""); + + const renderItem = renderItemFactory(navigation); + + return ( + + { + context ? + + { context }: + + : <> + } + item.id }/> + + ); +}; + +const SCREEN_WIDTH = Dimensions.get("window").width; + +const styles = { + context: { + fontSize: 18, + //color: "#888", + padding: 10, + }, + flexContainer: { + flex: 1, + flexDirection: "row", + alignItems: "center", + }, + itemContainer: { padding: 10 }, + accountButton: { + flexGrow: 1, + }, + bottomBorder: { + borderBottomWidth: 1, + borderBottomColor: "#888", + }, + avatar: { + width: SCREEN_WIDTH / 8, + height: SCREEN_WIDTH / 8, + borderRadius: SCREEN_WIDTH / 16, + marginRight: 10, + }, + acct: { + fontWeight: "bold", + }, + moderateMenu: { + marginLeft: "auto", + marginRight: 10, + }, + ellipsis: { + width: 20, + height: 20, + }, +}; + +export { UserListJsx as default }; From 63b37274815ed2a4e3b66e44f1a329c4ce4dd28b Mon Sep 17 00:00:00 2001 From: natjms Date: Wed, 24 Mar 2021 11:49:08 -0300 Subject: [PATCH 5/7] Fix rendering inconsistencies between one's own and someone else's profile --- src/components/pages/profile.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/components/pages/profile.js b/src/components/pages/profile.js index c8f761c..568ca50 100644 --- a/src/components/pages/profile.js +++ b/src/components/pages/profile.js @@ -144,7 +144,6 @@ const ProfileDisplayJsx = ({navigation}) => { const accountName = navigation.getParam("acct", ""); let [state, setState] = useState({ loaded: false, - own: false }); const notif_pack = { @@ -157,7 +156,8 @@ const ProfileDisplayJsx = ({navigation}) => { setState({ profile: TEST_PROFILE, mutuals: getMutuals(TEST_YOUR_FOLLOWERS, TEST_THEIR_FOLLOWERS), - loaded: true + own: true, + loaded: true, }); }, []); @@ -200,16 +200,13 @@ const ProfileDisplayJsx = ({navigation}) => { { state.own ? - - - + + + + + : @@ -220,13 +217,21 @@ const ProfileDisplayJsx = ({navigation}) => { { + const context = state.own ? + "People following you" + : "Your mutual followers with " + state.profile.display_name; navigation.navigate("UserList", { data: [/*Some array of users*/], - context: "Your mutual followers with " + state.profile.display_name + context: context }); } }> - { state.mutuals.length } mutuals + { + state.own ? + "View followers" + :state.mutuals.length + " mutuals" + } + From 663f4641f3a5584d5dc9ab4e2273a80b5f81322f Mon Sep 17 00:00:00 2001 From: natjms Date: Sat, 27 Mar 2021 09:16:35 -0300 Subject: [PATCH 6/7] Add settings page --- assets/eva-icons/close.png | Bin 0 -> 7829 bytes assets/eva-icons/plus.png | Bin 0 -> 7411 bytes src/App.js | 2 + src/components/pages/profile.js | 35 +-- src/components/pages/profile/settings.js | 295 +++++++++++++++++++++++ src/interface/rendering.js | 4 + 6 files changed, 319 insertions(+), 17 deletions(-) create mode 100644 assets/eva-icons/close.png create mode 100644 assets/eva-icons/plus.png create mode 100644 src/components/pages/profile/settings.js diff --git a/assets/eva-icons/close.png b/assets/eva-icons/close.png new file mode 100644 index 0000000000000000000000000000000000000000..e85d20a9a6714666530c3ae3f7ca6cebabd08ded GIT binary patch literal 7829 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 literal 0 HcmV?d00001 diff --git a/assets/eva-icons/plus.png b/assets/eva-icons/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..3a7e1478be10a06eafa69a8467421b92c200d524 GIT binary patch literal 7411 zcmeHMc|4Ts+aKv5dqN$FX(&;%7|V>wSVAc45D{vYXBcKPGnhhDDoddwvQ?r*i6WvD z$ySz>Xdz2wO9zQUoA;T~DZRhm^Lx+d_rCu%J~Qs;zQ5P^y6*3NUH5Z8GcisM)-sYR zk`M?)#@5D?0RE2@yyeBf&!mEz(GbX@q+PCCc?4nzl+9sLX>W~ zsoR2=ua~u&HHuYR(39}|jYvVe-q7EoIe2% zXZdx@)pd%)yWhWFZ}H{&Z{A0CZ!bL+yj=3ju3o0-=Z=)-{FJd$RNwVW^$x@Dba%zP z8!3vIuI#;;oT|k~R{hr4E*=4g4%MgKpHV3L;56iC@jO&IEl(;T|3%`-nY+77btcr3 z2QgD|??bYp!b+B_bmR0)$4nU^ue?7p?yD}1z;IJr(t3&$NP{0oj7>r>`M*yI2*Fdm z(#P!aS2-0A0(;-G4*=c!9bbeRjn$Q_WQQ!6Ayrg`ULP>NOkdi?>0)RNnsiZO9>j?& zjD23XhLLC1_DT9tqx$$&uL?%=Z-1?X|kxyrzu^EkrAI@P% z%JS@)1nxU%*r!C_T<8=+-oeJ1DLsg9-k4-}kD!wF+C`@{o&TU{6VBN7M0LonA1$6hl#gEhxWvF0u{DBU z8J`}SH6TamC^U8^`)SK9ad@SvO@$8Rh>mAV$lv$Tz0zJgba=zL)TaY?WBWV+0z1W} z#taoZK`Yk^?nw;Ymk~35i9I3LcWA?u(w*P;k1oCQIl9x)X`3hGtjqxPG%eSmWY1)d z%T%(df9vaziE_~|%?GYt>U@Xa?89u5-*hE!kQ%w%C-_u;33u~)tVgI@;E|P$4+2~} zI$jjz1noGtNkX+#t?*6OMUx!8o$rp&yz(iP^{Lz@JRy2{uQ#1?;bhFReUw#`UJFFs zrml?L2saP8(xw!UY_(mr@r9)E$g7bslt@vtHIrtQ*TQe z5_5I_h<{gH@_Xx6-Ml3Cj>01hrRX=$>a5q-ax&ZO9_eETV!^ zc~!KxtC2J#N%>Ua$d-}oJQ>w<=`BiaZ6$Zx>Wk|Vf^dC@@I!};j=j$YP(D%xh)wq4 ze9ZgWc;qsjk%|1|{Yl+r(MoYXQzM!#366~hiIxx7t86}eoH0Y0SFtRsy1Ux5 zDUbV`e3rt3Uf&&PE*iC>x!pnedQTOh-ZMRT*OlMz_V9JS_})i(?`NN~ONVTk4& z_da$;`(enN?0cCf(mWF#ejiPbRe7qO7j??%a>JSW;+1Cm-_^7}+W2`>j;uzaX4x@?5@a3sX3})h6O;K-_vA#UIMZPg}3*xEp;o_)tQL?DBWx?6C4A`^C zE4fP-t`Q*?siCB-YR^D3_8l1*gV{N6O|L91i$4S;0$W}{=v>MR>GLWHs+3K4B1Ele zr#-J3R*g$+vwz<}sn^`%So=uvnv@&MJ!X>OM|L^)q z-HqVn)HwMdPepFPv4fFe>MBO%8;>lhu8G9gS{%Pv!`*d$XDINo{c!u;>Idhl(Gm0m z_j3&0TX$RuXWdDEncsy-Lpw=7On&vK2)6Q6rFOU)DzP@k9~0w4s6RjKpoW(9S<fn=)HnH@w_0VSeA+ z_)wD(x{t3B9DyCdLBn>NOmA)XkIvJ%q5s@DN=2=7bsJ$q6ERUbn0-uUECgx#q18LGeVkWo>e|jj^82`Z{PtMn)ID*9m1%Ad^}dpUl>cl!k>U7mT?xW@ zM)k$QBM-D42#sw;r3I8K`|~bERqC&J>VuQVmWU@2rI{=z1q)Mt!ImEJ zPN@XVw)J1kH}xO5u-Gv4mFOGH9>j^Jg215L?nbGtkNOH`#KZE*D$V8%hhDXQ3}`73 zKXLKTdhWv&D%3@9Z4m1-*Y?Hko;luYxIJ-&QcRJZsm__st9vgT#g$vS#wKsLM^H{& z<$79kVa1euZ}x#+m>eKgelR0?6M}W2Yy#h zS0_AP-F%FFXEx_lzG<`B$ytb@)5cMsTIfJet-{gq;!R<=pz<5Imo{ARE6hvHJ}s*>K`dQy8;t%tj~ySe-) zNFbL>;2lwzJ*Mbc!)HHB2$@m~8H1d1CZ@L=$ogGpoK0G!o3TwP)Ms%GYD2WfYQ4tP zq|=IF^^frj!fwV*tefRV#G4qfbfHj%7IbxS3?}*rMCVSqkgS` z|EccUP|+t`!_mpc6 z+=aI5NQ)FK*W{i$BuO96lRmB}MeA^!o<8VRX^GhH1)w*?~`e|Hg5 zI}>t!yXqiWap>u9=|S}~Cc&8li{!(^3MQ{sc0i~mwwFpvh8Ewil=1Q^H2~zwo{5N^ zlzw{DTieEEjbh}K-iNcQD7IA8qZ{3xAF<&Obla9;F)VgrUF^}DqZ6au_qxB}9}bU+ z7xZu{JsuCffk5QqXy9>qtGykL%wiyj6c!0U@EL6II1PaqoATL2asa@Ck^o;C6Av3J zuY^Hq6giR>9x>{nUc%3O=_QB#32J#!2pw|G2bbh9>ksR zGl&Zax`c7lDO4mFl+g2h8*5v8r*Ad_8GUICw$MU=o{yxEzv0+H9J&xgAtM1gzyJf` zg3P)<;CVFa_XYZ4K7x^d2?TWajsFMqUwR2+5$cMwWRZgePHipmFhRUH3X4pm;Dk*K z360h>0x)nreJTd7Z-_y|vAQHfxB&*h8j{cyv_6$QkII(GYpm4J!@QjsZS&^uWVuB#6K zaD9{>22MhwNN@}aZDc^kk`0Zpb5w$Lz?nPQ;$dh6N=Pp3aiSA>R2GMUhuP7XLHzFn zt~3VV!XpYq(>2sJ#OmuBVGIm(^)YC@?;tmT!v&LEz^RKupwYq+3K_Q%WF&&gMq?0t z0VJF0D;y9k3l5wNC@fJ>8z8f=ADj!$f&&nFERHLSMaRPgkwFEN!jgg-e=QcA9g8e9 z6oLVYpx(Y#+yxQ78#A! z$NtF9Wl?z{L=Ir?3+4d0&R}T?*BQD-n0?wmqC@-uFh}4hJsb)Jn_FI}F;cLh{xv;g z!IoohkDD)mv0zKW*$OhxC5X+Y(*Vwo!u*ve{{wEG{nw=Ycjoh9bJi9t_D-;9{dkTc z%)fR26W|HABrUvm8;1^yBES9bl9>mMobkHEjO>;FtH$?s3t024gug@Dh`Gt;*pg3sP! zq|MfrkXgZB*3ENCV9z49jRzM3ky;{ni$Kydmw}z)JX?D!@qW?ek_fqH4aX)GPhOu6S1q2*J*w^_Hx1X{Ze0AdLL|#&{$o)@o zEDd>xbcOu15=0(i21Wu|_@6c;h<>j-wQCcOMl8$mAI$BLfgV4*t)t0(UyF*`iScDq zuaB*a8e(-Kv~gN+9x@9T;PT@S@pF1YoUyrtQz{bK|~5a&!YK$fXfl`Bs~ z8bX$f_=JgM^+RPx?KQ$ABo;st&!1f3(_56O*^~mnu!_ ps}X&10-3rt_STC3L}kd]*>/ig, ""); -} - function getMutuals(yours, theirs) { // Where yours and theirs are arrays of followers, as returned by the oAPI @@ -164,19 +161,24 @@ const ProfileDisplayJsx = ({navigation}) => { let profileButton; if (state.own) { profileButton = ( - + { + navigation.navigate("Settings"); + } + }> - Edit profile + Settings - + ); } else { profileButton = ( - + Follow - + ) } @@ -201,11 +203,11 @@ const ProfileDisplayJsx = ({navigation}) => { { state.own ? - + - + : { { state.profile.statuses_count } posts •  - { const context = state.own ? "People following you" @@ -228,8 +229,8 @@ const ProfileDisplayJsx = ({navigation}) => { }> { state.own ? - "View followers" - :state.mutuals.length + " mutuals" + <>View followers + : <>{state.mutuals.length + " mutuals"} } diff --git a/src/components/pages/profile/settings.js b/src/components/pages/profile/settings.js new file mode 100644 index 0000000..81b86fd --- /dev/null +++ b/src/components/pages/profile/settings.js @@ -0,0 +1,295 @@ +import React, { useState, useEffect } from "react"; + +import { + SafeAreaView, + View, + TextInput, + Text, + Image, + TouchableOpacity, + Dimensions, +} from "react-native"; + +import { withoutHTML } from "src/interface/rendering"; + +import { ScreenWithBackBarJsx } from "src/components/navigation/navigators"; + +const TEST_IMAGE = "https://cache.desktopnexus.com/thumbseg/2255/2255124-bigthumbnail.jpg"; +const TEST_PROFILE = { + username: "njms", + acct: "njms", + display_name: "Nat🔆", + locked: false, + bot: false, + note: "Yeah heart emoji.", + avatar: TEST_IMAGE, + followers_count: "1 jillion", + statuses_count: 334, + fields: [ + { + name: "Blog", + value: "https://njms.ca", + verified_at: "some time" + }, + { + name: "Github", + value: "https://github.com/natjms", + verified_at: null + } + ] +}; + +const SettingsJsx = (props) => { + const [state, setState] = useState({ + // Use Context to get this stuff eventually + profile: TEST_PROFILE, + newProfile: TEST_PROFILE, + }); + + useEffect(() => { console.log(state) }); + + const fields = state.newProfile.fields; + + return ( + + + + + + Change profile photo + + + + + Display name + { + setState({...state, + newProfile: {...state.newProfile, display_name: value} + }); + } + }/> + + User name + { + setState({...state, + newProfile: {...state.newProfile, username: value} + }); + } + }/> + + Bio + { + setState({...state, + newProfile: {...state.newProfile, note: value} + }); + } + }/> + { + fields.map((field, i) => + + { + let newFields; + if (fields.length == 1) { + newFields = [{ name: "", value: "" }]; + } else { + newFields = state.newProfile.fields; + newFields.splice(i, 1); + } + + setState({...state, + newProfile: {...state.newProfile, + fields: newFields, + }, + }); + } + }> + + + + Name + { + let newFields = fields; + newFields[i] = {...newFields[i], + name: text, + }; + + setState({...state, + newProfile: {...state.newProfile, + fields: newFields, + }, + }); + } + } /> + + + Value + { + let newFields = fields; + newFields[i] = {...newFields[i], + value: text, + }; + + setState({...state, + newProfile: {...state.newProfile, + fields: newFields, + }, + }); + } + } /> + + + ) + } + { + setState({...state, + newProfile: {...state.newProfile, + fields: state.newProfile.fields.concat({ name: "", value: ""}), + }, + }); + } + }> + + + + Save Profile + + + Log out + + + + ); +}; + +const SCREEN_WIDTH = Dimensions.get("window").width; +const styles = { + label: { + paddingTop: 10, + fontWeight: "bold", + color: "#888", + }, + bar: { + borderBottomWidth: 1, + borderBottomColor: "#888", + padding: 10, + }, + avatar: { + container: { + paddingTop: 10, + paddingBottom: 10, + flex: 1, + alignItems: "center", + }, + image: { + width: SCREEN_WIDTH / 5, + height: SCREEN_WIDTH / 5, + borderRadius: SCREEN_WIDTH / 10, + marginBottom: 10, + }, + change: { + fontSize: 18, + color: "#888", + }, + }, + input: { + container: { + padding: 10, + }, + }, + fields: { + container: { + flex: 1, + flexDirection: "row", + alignItems: "flex-end", + }, + cross: { + width: 30, + height: 30, + marginRight: 10, + marginBottom: 10, + }, + plus: { + width: 30, + height: 30, + marginLeft: "auto", + marginRight: "auto", + marginTop: 10, + }, + subContainer: { + flexGrow: 0.5, + }, + cell: { + width: SCREEN_WIDTH / 2.5, + }, + }, + largeButton: { + width: SCREEN_WIDTH / 1.2, + padding: 15, + marginTop: 10, + marginBottom: 5, + marginLeft: "auto", + marginRight: "auto", + borderWidth: 1, + borderColor: "#888", + borderRadius: 5, + textAlign: "center", + }, + textWarning: { + fontWeight: "bold", + textDecorationLine: "underline", + }, +}; + +export default SettingsJsx; diff --git a/src/interface/rendering.js b/src/interface/rendering.js index 6dee69e..ff2774d 100644 --- a/src/interface/rendering.js +++ b/src/interface/rendering.js @@ -1,3 +1,7 @@ +export function withoutHTML(string) { + return string.replaceAll(/<[^>]*>/ig, ""); +} + export function pluralize(n, singular, plural) { if (n < 2) { return singular; From ae2fff8547b1be96dc0f7a81e762227b2ba82923 Mon Sep 17 00:00:00 2001 From: natjms Date: Sat, 27 Mar 2021 14:42:09 -0300 Subject: [PATCH 7/7] Remove the line that logs the settings.js state to the console --- src/components/pages/profile/settings.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/pages/profile/settings.js b/src/components/pages/profile/settings.js index 81b86fd..0f6d11a 100644 --- a/src/components/pages/profile/settings.js +++ b/src/components/pages/profile/settings.js @@ -46,8 +46,6 @@ const SettingsJsx = (props) => { newProfile: TEST_PROFILE, }); - useEffect(() => { console.log(state) }); - const fields = state.newProfile.fields; return (