Add settings page

This commit is contained in:
Nat 2021-03-27 09:16:35 -03:00
parent 63b3727481
commit 663f4641f3
6 changed files with 319 additions and 17 deletions

BIN
assets/eva-icons/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
assets/eva-icons/plus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -16,12 +16,14 @@ import SearchJsx from 'src/components/pages/discover/search';
import ViewHashtagJsx from 'src/components/pages/discover/view-hashtag'; import ViewHashtagJsx from 'src/components/pages/discover/view-hashtag';
import NotificationsJsx from 'src/components/pages/profile/notifications'; import NotificationsJsx from 'src/components/pages/profile/notifications';
import UserListJsx from "src/components/pages/user-list.js"; import UserListJsx from "src/components/pages/user-list.js";
import SettingsJsx from "src/components/pages/profile/settings.js";
const Stack = createStackNavigator({ const Stack = createStackNavigator({
Feed: { screen: FeedJsx, }, Feed: { screen: FeedJsx, },
Discover: { screen: DiscoverJsx }, Discover: { screen: DiscoverJsx },
Notifications: { screen: NotificationsJsx }, Notifications: { screen: NotificationsJsx },
Profile: { screen: ProfileJsx, }, Profile: { screen: ProfileJsx, },
Settings: { screen: SettingsJsx },
Search: { screen: SearchJsx }, Search: { screen: SearchJsx },
ViewPost: { screen: ViewPostJsx }, ViewPost: { screen: ViewPostJsx },
ViewComments: { screen: ViewCommentsJsx }, ViewComments: { screen: ViewCommentsJsx },

View File

@ -4,12 +4,13 @@ import {
Dimensions, Dimensions,
Image, Image,
Text, Text,
TouchableWithoutFeedback TouchableOpacity
} from "react-native"; } from "react-native";
import * as Linking from "expo-linking"; import * as Linking from "expo-linking";
import { activeOrNot } from "src/interface/interactions" import { activeOrNot } from "src/interface/interactions";
import { withoutHTML } from "src/interface/rendering";
import GridViewJsx from "src/components/posts/grid-view"; import GridViewJsx from "src/components/posts/grid-view";
import { import {
@ -86,10 +87,6 @@ const TEST_THEIR_FOLLOWERS = [
{ id: 6 }, { id: 6 },
]; ];
function withoutHTML(string) {
return string.replaceAll(/<[^>]*>/ig, "");
}
function getMutuals(yours, theirs) { function getMutuals(yours, theirs) {
// Where yours and theirs are arrays of followers, as returned by the oAPI // Where yours and theirs are arrays of followers, as returned by the oAPI
@ -164,19 +161,24 @@ const ProfileDisplayJsx = ({navigation}) => {
let profileButton; let profileButton;
if (state.own) { if (state.own) {
profileButton = ( profileButton = (
<TouchableWithoutFeedback> <TouchableOpacity
onPress = {
() => {
navigation.navigate("Settings");
}
}>
<View style = { styles.button }> <View style = { styles.button }>
<Text style = { styles.buttonText }>Edit profile</Text> <Text style = { styles.buttonText }>Settings</Text>
</View> </View>
</TouchableWithoutFeedback> </TouchableOpacity>
); );
} else { } else {
profileButton = ( profileButton = (
<TouchableWithoutFeedback> <TouchableOpacity>
<View style = { styles.button }> <View style = { styles.button }>
<Text style = { styles.buttonText }>Follow</Text> <Text style = { styles.buttonText }>Follow</Text>
</View> </View>
</TouchableWithoutFeedback> </TouchableOpacity>
) )
} }
@ -201,11 +203,11 @@ const ProfileDisplayJsx = ({navigation}) => {
{ {
state.own ? state.own ?
<View style = { styles.profileContextContainer }> <View style = { styles.profileContextContainer }>
<TouchableWithoutFeedback> <TouchableOpacity>
<Image <Image
source = { activeOrNot(state.unread_notifs, notif_pack) } source = { activeOrNot(state.unread_notifs, notif_pack) }
style = { styles.profileHeaderIcon } /> style = { styles.profileHeaderIcon } />
</TouchableWithoutFeedback> </TouchableOpacity>
</View> </View>
: <ModerateMenuJsx : <ModerateMenuJsx
triggerStyle = { styles.profileHeaderIcon } triggerStyle = { styles.profileHeaderIcon }
@ -214,8 +216,7 @@ const ProfileDisplayJsx = ({navigation}) => {
</View> </View>
<Text style = { styles.accountStats }> <Text style = { styles.accountStats }>
{ state.profile.statuses_count } posts &#8226;&nbsp; { state.profile.statuses_count } posts &#8226;&nbsp;
<Text <Text onPress = {
onPress = {
() => { () => {
const context = state.own ? const context = state.own ?
"People following you" "People following you"
@ -228,8 +229,8 @@ const ProfileDisplayJsx = ({navigation}) => {
}> }>
{ {
state.own ? state.own ?
"View followers" <>View followers</>
:state.mutuals.length + " mutuals" : <>{state.mutuals.length + " mutuals"}</>
} }
</Text> </Text>

View File

@ -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: "<a href=\"https://njms.ca\">https://njms.ca</a>",
verified_at: "some time"
},
{
name: "Github",
value: "<a href=\"https://github.com/natjms\">https://github.com/natjms</a>",
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 (
<ScreenWithBackBarJsx navigation = { props.navigation }>
<View style = { styles.avatar.container }>
<Image
source = { { uri: state.profile.avatar } }
style = { styles.avatar.image }/>
<TouchableOpacity>
<Text style = { styles.avatar.change }>
Change profile photo
</Text>
</TouchableOpacity>
</View>
<View style = { styles.input.container }>
<Text style = { styles.label }>Display name</Text>
<TextInput
style = { styles.bar }
placeholder = { "Display name" }
value = { state.newProfile.display_name }
onChangeText = {
(value) => {
setState({...state,
newProfile: {...state.newProfile, display_name: value}
});
}
}/>
<Text style = { styles.label }>User name</Text>
<TextInput
style = { styles.bar }
placeholder = { "User name" }
value = { state.newProfile.username }
onChangeText = {
(value) => {
setState({...state,
newProfile: {...state.newProfile, username: value}
});
}
}/>
<Text style = { styles.label }>Bio</Text>
<TextInput
style = {
[
styles.bar,
{ height: 100 },
]
}
multiline = { true }
placeholder = { "Bio" }
value = { withoutHTML(state.newProfile.note) }
onChangeText = {
(value) => {
setState({...state,
newProfile: {...state.newProfile, note: value}
});
}
}/>
{
fields.map((field, i) =>
<View
style = { styles.fields.container }
key = { i }>
<TouchableOpacity
onPress = {
() => {
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,
},
});
}
}>
<Image
style = {
[
styles.fields.cross,
fields.length == 1
&& fields[0].name == ""
&& fields[0].value == ""
? { visibility: "hidden" }
: {}
]
}
source = { require("assets/eva-icons/close.png") }/>
</TouchableOpacity>
<View style = { styles.fields.subContainer }>
<Text style = { styles.label }>Name</Text>
<TextInput
style = { [styles.bar, styles.fields.cell] }
placeholder = { "Name" }
value = { withoutHTML(fields[i].name) }
onChangeText = {
(text) => {
let newFields = fields;
newFields[i] = {...newFields[i],
name: text,
};
setState({...state,
newProfile: {...state.newProfile,
fields: newFields,
},
});
}
} />
</View>
<View style = { styles.fields.subContainer }>
<Text style = { styles.label }>Value</Text>
<TextInput
style = { [styles.bar, styles.fields.cell] }
placeholder = { "Value" }
value = { withoutHTML(fields[i].value) }
onChangeText = {
(text) => {
let newFields = fields;
newFields[i] = {...newFields[i],
value: text,
};
setState({...state,
newProfile: {...state.newProfile,
fields: newFields,
},
});
}
} />
</View>
</View>
)
}
<TouchableOpacity
onPress = {
() => {
setState({...state,
newProfile: {...state.newProfile,
fields: state.newProfile.fields.concat({ name: "", value: ""}),
},
});
}
}>
<Image
style = { styles.fields.plus }
source = { require("assets/eva-icons/plus.png") } />
</TouchableOpacity>
<TouchableOpacity style = { styles.largeButton }>
<Text> Save Profile </Text>
</TouchableOpacity>
<TouchableOpacity style = { styles.largeButton }>
<Text style = { styles.textWarning }> Log out </Text>
</TouchableOpacity>
</View>
</ScreenWithBackBarJsx>
);
};
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;

View File

@ -1,3 +1,7 @@
export function withoutHTML(string) {
return string.replaceAll(/<[^>]*>/ig, "");
}
export function pluralize(n, singular, plural) { export function pluralize(n, singular, plural) {
if (n < 2) { if (n < 2) {
return singular; return singular;