diff --git a/src/App.js b/src/App.js
index 035e89e..80ccf0e 100644
--- a/src/App.js
+++ b/src/App.js
@@ -15,6 +15,8 @@ import ProfileJsx, { ViewProfileJsx } from "src/components/pages/profile";
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 DirectJsx from "src/components/pages/direct";
+import ConversationJsx from "src/components/pages/direct/conversation";
import NotificationsJsx from 'src/components/pages/profile/notifications';
import UserListJsx from "src/components/pages/user-list.js";
import SettingsJsx from "src/components/pages/profile/settings.js";
@@ -23,6 +25,8 @@ const Stack = createStackNavigator({
Authenticate: { screen: AuthenticateJsx },
Feed: { screen: FeedJsx, },
Discover: { screen: DiscoverJsx },
+ Direct: { screen: DirectJsx },
+ Conversation: { screen: ConversationJsx },
Notifications: { screen: NotificationsJsx },
Profile: { screen: ProfileJsx, },
Settings: { screen: SettingsJsx },
diff --git a/src/components/navigation/back-bar.js b/src/components/navigation/back-bar.js
index 3b83cbb..556ebd6 100644
--- a/src/components/navigation/back-bar.js
+++ b/src/components/navigation/back-bar.js
@@ -1,33 +1,44 @@
import React from "react";
import { Image } from "react-native";
-import { TouchableWithoutFeedback, View } from "react-native";
+import { TouchableOpacity, View } from "react-native";
const BackBarJsx = (props) => {
const backIcon = require("assets/eva-icons/back.png");
return (
- props.navigation.goBack() }>
+ props.navigation.goBack() }
+ style = { styles.button }>
-
+
+
+ { props.children }
+
);
};
const styles = {
nav: {
- padding: 15,
-
borderBottom: "2px solid #CCC",
- backgroundColor: "white"
+ backgroundColor: "white",
+
+ flexDirection: "row",
+ alignItems: "center",
+ },
+ rest: {
+ flexGrow: 1,
+ },
+ chevron: {
+ width: 30,
+ height: 30,
},
button: {
- width: 30,
- height: 30
- }
+ padding: 10,
+ },
}
-export default BackBarJsx;
\ No newline at end of file
+export default BackBarJsx;
diff --git a/src/components/navigation/navigators.js b/src/components/navigation/navigators.js
index d3776c1..6e43850 100644
--- a/src/components/navigation/navigators.js
+++ b/src/components/navigation/navigators.js
@@ -36,7 +36,12 @@ export const ScreenWithBackBarJsx = (props) => {
return (
-
+
+ { props.renderBackBar != undefined
+ ? props.renderBackBar()
+ : <>>
+ }
+
{ props.children }
@@ -49,7 +54,12 @@ export const ScreenWithFullNavigationJsx = (props) => {
return (
-
+
+ { props.renderBackBar != undefined
+ ? props.renderBackBar()
+ : <>>
+ }
+
{ props.children }
diff --git a/src/components/pages/direct.js b/src/components/pages/direct.js
new file mode 100644
index 0000000..60a5488
--- /dev/null
+++ b/src/components/pages/direct.js
@@ -0,0 +1,195 @@
+import React, { useState, useEffect } from "react";
+import {
+ View,
+ Text,
+ TouchableOpacity,
+ Image,
+ FlatList,
+ TextInput,
+ Dimensions,
+} from "react-native";
+
+import { Ionicons } from "@expo/vector-icons";
+
+import { ScreenWithTrayJsx } from "src/components/navigation/navigators";
+import ModerateMenuJsx from "src/components/moderate-menu.js";
+
+const TEST_IMAGE_1 = "https://cache.desktopnexus.com/thumbseg/2255/2255124-bigthumbnail.jpg";
+const TEST_IMAGE_2 = "https://natureproducts.net/Forest_Products/Cutflowers/Musella_cut.jpg";
+const TEST_ACCOUNT_1 = { acct: "njms", display_name: "Nat🔆", avatar: TEST_IMAGE_1 };
+const TEST_ACCOUNT_2 = { acct: "someone", display_name: "Some person", avatar: TEST_IMAGE_2 };
+
+const TEST_STATUS = {
+ id: 1,
+ account: TEST_ACCOUNT_1,
+ content: "This is a direct message",
+};
+
+function filterConversations(convs, query) {
+ return convs.filter(conv => {
+ const accts = conv.accounts.map(account => account.acct).join();
+ const names = conv.accounts.map(account => account.display_name).join();
+
+ return accts.includes(query) || names.includes(query)
+ });
+}
+
+const DirectJsx = ({ navigation }) => {
+ const [state, setState] = useState({
+ loaded: false,
+ query: ""
+ });
+
+ useEffect(() => {
+ setState({...state,
+ loaded: true,
+ conversations: [
+ {
+ id: 1,
+ unread: true,
+ accounts: [TEST_ACCOUNT_1],
+ last_status: TEST_STATUS,
+ },
+ {
+ id: 2,
+ unread: false,
+ accounts: [TEST_ACCOUNT_1, TEST_ACCOUNT_2],
+ last_status: TEST_STATUS,
+ }
+ ],
+ });
+ }, []);
+
+ const onPressConversationFactory = (conv) => {
+ return () => {
+ navigation.navigate("Conversation", {
+ conversation: conv,
+ });
+ }
+ };
+
+ const renderConversation = ({ item }) => {
+ const boldIfUnread = item.unread ? styles.bold : {};
+
+ return
+
+
+
+
+
+
+ { item.accounts.map(account => account.acct).join(", ") }
+
+
+ {
+ // Prefix message with acct
+ [
+ item.accounts.length > 1 ?
+ item.last_status.account.acct + ": "
+ : "",
+ item.last_status.content,
+ ].join("")
+ }
+
+
+
+
+
+
+
+ };
+
+ return (
+
+
+ {
+ setState({...state,
+ query: value,
+ });
+ }
+ }/>
+
+
+
+
+ { state.loaded ?
+ conv.id }/>
+ : <>>
+ }
+
+ );
+};
+
+const SCREEN_WIDTH = Dimensions.get("window").width;
+const styles = {
+ row: {
+ flexDirection: "row",
+ alignItems: "center",
+ },
+ form: {
+ container: {
+ marginLeft: 20,
+ marginTop: 20,
+ marginBottom: 20,
+ },
+ searchBar: {
+ padding: 10,
+ width: SCREEN_WIDTH * 3 / 4,
+ borderWidth: 1,
+ borderRadius: 5,
+ borderColor: "#888",
+ },
+ compose: {
+ marginLeft: "auto",
+ marginRight: "auto",
+ },
+ },
+ conv: {
+ container: {
+ paddingBottom: 20,
+ paddingLeft: 10,
+ paddingRight: 20,
+ },
+ containerButton: { flexGrow: 1 },
+ avatar: {
+ image: {
+ width: 40,
+ height: 40,
+ borderRadius: 20,
+ }
+ },
+ body: {
+ marginLeft: 10,
+ },
+ context: {
+ marginLeft: "auto",
+ }
+ },
+ menu: {
+ trigger: {
+ width: 20,
+ height: 20,
+ },
+ },
+ bold: { fontWeight: "bold" },
+};
+
+export { DirectJsx as default };
diff --git a/src/components/pages/direct/conversation.js b/src/components/pages/direct/conversation.js
new file mode 100644
index 0000000..909931e
--- /dev/null
+++ b/src/components/pages/direct/conversation.js
@@ -0,0 +1,294 @@
+import React, { useState, useEffect } from "react";
+import {
+ View,
+ Text,
+ Image,
+ TextInput,
+ FlatList,
+ ScrollView,
+ Dimensions,
+ TouchableOpacity,
+} from "react-native";
+
+import AsyncStorage from "@react-native-async-storage/async-storage";
+
+import { Ionicons } from "@expo/vector-icons";
+
+import {
+ Menu,
+ MenuOptions,
+ MenuOption,
+ MenuTrigger,
+ renderers
+} from "react-native-popup-menu";
+
+const { SlideInMenu } = renderers;
+
+import BackBarJsx from "src/components/navigation/back-bar";
+import { ContextJsx } from "src/components/navigation/navigators";
+
+import { timeToAge } from "src/interface/rendering";
+
+const TEST_IMAGE_1 = "https://cache.desktopnexus.com/thumbseg/2255/2255124-bigthumbnail.jpg";
+const TEST_IMAGE_2 = "https://natureproducts.net/Forest_Products/Cutflowers/Musella_cut.jpg";
+const TEST_ACCOUNT_1 = { acct: "someone", display_name: "Someone", avatar: TEST_IMAGE_1 };
+const TEST_ACCOUNT_2 = { acct: "someone_else", display_name: "Another person", avatar: TEST_IMAGE_2 };
+
+const TEST_STATUS = {
+ account: TEST_ACCOUNT_1,
+ content: "This is a direct message",
+ created_at: 1596745156000,
+};
+
+const TEST_MESSAGES = [
+ { ...TEST_STATUS, id: 1 },
+ { ...TEST_STATUS, id: 2, account: TEST_ACCOUNT_2 },
+ { ...TEST_STATUS, id: 3 },
+ { ...TEST_STATUS, id: 4, account: { acct: "njms" } },
+ { ...TEST_STATUS, id: 5 },
+];
+
+const ConversationJsx = ({ navigation }) => {
+ const conversation = navigation.getParam("conversation", {});
+ const [state, setState] = useState({
+ loaded: false,
+ newMessage: "",
+ });
+
+ useEffect(() => {
+ // Get the context of last_status, then profile from AsyncStorage
+ AsyncStorage.getItem("@user_profile").then((profile) => {
+ setState({...state,
+ loaded: true,
+ profile: JSON.parse(profile),
+ messages: TEST_MESSAGES,
+ });
+ });
+ }, []);
+
+ const accountListOptionsStyles = {
+ optionWrapper: { // The wrapper around a single option
+ flexDirection: "row",
+ alignItems: "center",
+
+ 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
+ }
+ };
+
+ const renderBackBar = () => (
+
+
+
+ );
+
+ const renderMessage = ({ item }) => {
+ const yours = state.profile.acct == item.account.acct;
+ return <>
+ { !yours
+ ?
+ { item.account.acct }
+
+ : <>>
+ }
+
+ { !yours
+ ?
+ : <>>
+ }
+
+
+
+ { item.content + "\n" }
+
+
+ { timeToAge(item.created_at) }
+
+
+
+
+ >;
+ };
+
+ return (
+
+
+
+ { renderBackBar() }
+
+
+ { state.loaded
+ ? item.id }/>
+ : <>>
+ }
+
+
+ {
+ setState({...state,
+ newMessage: value,
+ });
+ }
+ }/>
+
+
+
+
+
+
+ );
+};
+
+const SCREEN_WIDTH = Dimensions.get("window").width;
+const styles = {
+ row: {
+ flexDirection: "row",
+ alignItems: "center",
+ },
+ backBar: {
+ accountList: {
+ avatar: {
+ width: 40,
+ height: 40,
+ borderRadius: 20,
+ marginRight: 10,
+ },
+ },
+ container: {
+ marginLeft: 20,
+ paddingTop: 10,
+ paddingBottom: 10,
+ },
+ avatar: {
+ width: 40,
+ height: 40,
+ borderRadius: 20,
+ marginRight: 10,
+ },
+ },
+ message: {
+ container: {
+ paddingTop: 5,
+ paddingBottom: 10,
+ paddingLeft: 10,
+ paddingRight: 10,
+ flexDirection: "row",
+ },
+ acct: {
+ paddingLeft: 60,
+ fontSize: 12,
+ color: "#888",
+ },
+ avatar: {
+ width: 40,
+ height: 40,
+ borderRadius: 20,
+ marginRight: 10,
+ },
+ bubble: {
+ width: SCREEN_WIDTH * 3/4,
+ borderWidth: 1,
+ borderColor: "#888",
+ borderRadius: 10,
+ padding: 10,
+ },
+ yourBubble: {
+ backgroundColor: "#CCC",
+ marginLeft: "auto",
+ },
+ yourText: {
+ //color: "white",
+ textAlign: "right",
+ },
+ age: {
+ fontSize: 10,
+ color: "#888",
+ },
+ },
+ send: {
+ container: {
+ marginTop: 10,
+ marginBottom: 10,
+ marginLeft: 10,
+ },
+ input: {
+ padding: 10,
+ borderWidth: 1,
+ borderColor: "#888",
+ borderRadius: 5,
+ flexGrow: 1,
+ },
+ button: {
+ marginLeft: 10,
+ marginRight: 10,
+ }
+ },
+ bold: { fontWeight: "bold", },
+};
+
+export { ConversationJsx as default };