diff --git a/__test__/components/Graph/Force-Directed-Graph/ForceDirectedGraph.test.tsx b/__test__/components/Graph/Force-Directed-Graph/ForceDirectedGraph.test.tsx
index a6e4fb12..9203a5c0 100644
--- a/__test__/components/Graph/Force-Directed-Graph/ForceDirectedGraph.test.tsx
+++ b/__test__/components/Graph/Force-Directed-Graph/ForceDirectedGraph.test.tsx
@@ -25,6 +25,12 @@ describe("ForceDirectedGraph", () => {
let graph: Graph
let constrainedNodeId: string
+ const mockFunc = jest.fn()
+
+ beforeEach(() => {
+ mockFunc.mockClear()
+ })
+
beforeEach(() => {
graph = new Graph(["1", "2", "3"], ["1", "2"], ["2", "3"], [1, 2])
constrainedNodeId = "2"
@@ -39,6 +45,7 @@ describe("ForceDirectedGraph", () => {
,
)
expect(component).toBeTruthy()
@@ -49,6 +56,7 @@ describe("ForceDirectedGraph", () => {
,
)
@@ -111,6 +119,7 @@ describe("ForceDirectedGraph", () => {
,
)
@@ -136,35 +145,9 @@ describe("ForceDirectedGraph", () => {
jest.advanceTimersByTime(500)
})
- await waitFor(() => {
- const modal = component.getByTestId("modal")
- expect(modal).toBeTruthy()
- expect(modal.props.visible).toBe(true)
- }, {timeout: 10})
-
+
jest.useRealTimers()
-
- const modale_image = component.getByTestId("modal-profile-picture")
- expect(modale_image).toBeTruthy()
-
- act (() => {
- fireEvent(modale_image, "press")
- })
-
- const quitModal = component.getByTestId("modal-touchable")
- expect(quitModal).toBeTruthy()
-
- act(() => {
- fireEvent(quitModal, "press")
- })
-
- jest.useFakeTimers()
-
- await waitFor(() => {
- expect(component.queryByTestId("modal")).toBeNull()
- }, {timeout: 10})
-
- jest.useRealTimers()
+ expect(mockFunc).toHaveBeenCalled()
})
@@ -174,6 +157,7 @@ describe("ForceDirectedGraph", () => {
,
)
@@ -198,29 +182,14 @@ describe("ForceDirectedGraph", () => {
,
)
const node1 = component.getByTestId("node-1")
expect(node1).toBeTruthy()
- expect(component.queryByTestId("modal")).toBeNull()
-
- fireEvent(node1, "pressIn")
-
- jest.useFakeTimers()
- act(() => {
- jest.advanceTimersByTime(100)
- })
-
- act (() => {
- fireEvent(node1, "pressOut")
- })
-
- await waitFor(() => {
- expect(component.queryByTestId("modal")).toBeNull()
- }, {timeout: 10})
- jest.useRealTimers()
+ expect(mockFunc).not.toHaveBeenCalled()
})
it("pinching zooms the graph", async () => {
@@ -229,6 +198,7 @@ describe("ForceDirectedGraph", () => {
,
)
diff --git a/__test__/screens/Contacts/ContactGraph/ContactGraph.test.tsx b/__test__/screens/Contacts/ContactGraph/ContactGraph.test.tsx
index f3df14c3..ba0b176d 100644
--- a/__test__/screens/Contacts/ContactGraph/ContactGraph.test.tsx
+++ b/__test__/screens/Contacts/ContactGraph/ContactGraph.test.tsx
@@ -1,12 +1,111 @@
import React from "react"
-import { render } from "@testing-library/react-native"
+import { act, fireEvent, render } from "@testing-library/react-native"
import ContactGraph from "../../../../screens/Contacts/ContactGraph/ContactGraph"
describe("ContactGraph", () => {
- it("renders correctly", () => {
- const component = render()
- expect(component).toBeTruthy()
- })
+ const mockFunc = jest.fn()
+
+ beforeEach(() => {
+ mockFunc.mockClear()
+ })
+
+ it("renders the screen", () => {
+ const component = render( mockFunc} />)
+ expect(component).toBeTruthy()
+ })
+
+ it("search bar is reachable", () => {
+ const component = render( mockFunc} />)
+ expect(component).toBeTruthy()
+
+ const searchBar = component.getByPlaceholderText("Search...")
+ expect(searchBar).toBeTruthy()
+
+ act(() => {
+ fireEvent(searchBar, "press")
+ })
+
+ act(() => {
+ fireEvent.changeText(searchBar, "")
+ })
+
+ expect(searchBar.props.value).toBe("")
+
+ act(() => {
+ fireEvent.changeText(searchBar, "0")
+ })
+
+ expect(searchBar.props.value).toBe("0")
+
+ act (() => {
+ fireEvent(searchBar, "submitEditing")
+ })
+ })
+
+ it("clicking a node opens a modal", () => {
+ const component = render( mockFunc} />)
+ expect(component).toBeTruthy()
+
+ const node = component.getByTestId("node-0")
+ expect(node).toBeTruthy()
+
+ act(() => {
+ fireEvent(node, "pressIn")
+ })
+
+ jest.useFakeTimers()
+ act(() => {
+ jest.advanceTimersByTime(50)
+ })
+
+ act (() => {
+ fireEvent(node, "pressOut")
+ jest.advanceTimersByTime(500)
+ })
+
+
+ jest.useRealTimers()
+
+ const modal = component.getByTestId("modal")
+ expect(modal).toBeTruthy()
+ })
+ it("clicking outside the modal closes it", () => {
+ const component = render( mockFunc} />)
+ expect(component).toBeTruthy()
+
+ const node = component.getByTestId("node-0")
+ expect(node).toBeTruthy()
+
+ act(() => {
+ fireEvent(node, "pressIn")
+ })
+
+ jest.useFakeTimers()
+ act(() => {
+ jest.advanceTimersByTime(50)
+ })
+
+ act (() => {
+ fireEvent(node, "pressOut")
+ jest.advanceTimersByTime(500)
+ })
+
+
+ jest.useRealTimers()
+
+ const modal = component.getByTestId("modal")
+ expect(modal).toBeTruthy()
+
+ const modalTouchable = component.getByTestId("modal-touchable")
+ expect(modalTouchable).toBeTruthy()
+
+ act(() => {
+ fireEvent(modalTouchable, "press")
+ })
+
+ expect(component.queryByTestId("modal")).toBeNull()
+ })
+
})
\ No newline at end of file
diff --git a/__test__/screens/Contacts/ExploreScreen.test.tsx b/__test__/screens/Contacts/ExploreScreen.test.tsx
index 9b46eaf3..d4b02ccc 100644
--- a/__test__/screens/Contacts/ExploreScreen.test.tsx
+++ b/__test__/screens/Contacts/ExploreScreen.test.tsx
@@ -1,5 +1,5 @@
import React from "react"
-import { render, fireEvent } from "@testing-library/react-native"
+import { render, fireEvent, act, waitFor } from "@testing-library/react-native"
import ExploreScreen from "../../../screens/Contacts/ExploreScreen"
import { SafeAreaProvider } from "react-native-safe-area-context"
import { black, lightGray } from "../../../assets/colors/colors"
@@ -38,6 +38,17 @@ jest.mock("react-native-safe-area-context", () => {
}
})
+jest.mock("react-native-gesture-handler", () => {
+ return {
+ State: {
+ END: 5,
+ },
+ PanGestureHandler: 'View',
+ PinchGestureHandler: 'View',
+ GestureHandlerRootView: 'View',
+ }
+})
+
beforeAll(() => {
global.alert = jest.fn()
})
@@ -85,6 +96,61 @@ describe("ExploreScreen", () => {
expect(mockNavigation.navigate).toHaveBeenCalledWith("ExternalProfile", {"uid": "1"})
})
+ it ("navigates to profile screen when clicking on contact in graph view", async () => {
+ const { getByText, getByTestId, queryByTestId } = render(
+
+
+
+
+
+ )
+ fireEvent.press(getByText("Graph View"))
+
+ const panHandler = getByTestId("pan-handler")
+ const node1 = getByTestId("node-1")
+
+ expect(node1).toBeTruthy()
+ expect(panHandler).toBeTruthy()
+ expect(panHandler.props.enabled).toBe(true)
+
+ act(() => {
+ fireEvent(node1, "pressIn")
+ })
+
+ jest.useFakeTimers()
+ act(() => {
+ jest.advanceTimersByTime(50)
+ })
+
+ act (() => {
+ fireEvent(node1, "pressOut")
+ jest.advanceTimersByTime(500)
+ })
+
+ await waitFor(() => {
+ const modal = getByTestId("modal")
+ expect(modal).toBeTruthy()
+ expect(modal.props.visible).toBe(true)
+ }, {timeout: 10})
+
+ jest.useRealTimers()
+
+ const modale_image = getByTestId("modal-profile-picture")
+ expect(modale_image).toBeTruthy()
+
+ act(() => {
+ fireEvent(modale_image, "press")
+ })
+
+ await waitFor(() => {
+ expect(queryByTestId("modal")).toBeNull()
+ }, {timeout: 10})
+
+ jest.useRealTimers()
+
+ expect(mockNavigation.navigate).toHaveBeenCalledWith("ExternalProfile", {"uid": "1"})
+ })
+
})
diff --git a/components/Graph/ForceDirectedGraph/ExampleForceDirectedGraph.tsx b/components/Graph/ForceDirectedGraph/ExampleForceDirectedGraph.tsx
deleted file mode 100644
index 0f9688d4..00000000
--- a/components/Graph/ForceDirectedGraph/ExampleForceDirectedGraph.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from "react"
-import Graph from "../Graph"
-import ForceDirectedGraph from "./ForceDirectedGraph"
-
-const ExampleForceDirectedGraph = () => {
- const graph = new Graph(
- ["0", "1", "2", "3", "4", "5", "6"],
- ["0", "2", "3", "3", "3", "4", "5", "6", "6", "6"],
- ["1", "1", "1", "2", "0", "1", "1", "1", "2", "0"],
- [0.5, 0.2, 0.2, 0.5, 0.5, 0.5, 0.2, 0.5, 0.5, 0.5]
- )
- const constrainedNodeId = "1"
- return (
-
- )
-}
-
-export default ExampleForceDirectedGraph
diff --git a/components/Graph/ForceDirectedGraph/ForceDirectedGraph.tsx b/components/Graph/ForceDirectedGraph/ForceDirectedGraph.tsx
index d0a4535a..65eb8d4e 100644
--- a/components/Graph/ForceDirectedGraph/ForceDirectedGraph.tsx
+++ b/components/Graph/ForceDirectedGraph/ForceDirectedGraph.tsx
@@ -2,10 +2,7 @@ import React, { useEffect, useRef, useState } from "react"
import {
ActivityIndicator,
View,
- Dimensions,
- Modal,
- Text,
- TouchableWithoutFeedback,
+ Dimensions
} from "react-native"
import Svg, { Circle, G, Line, Text as SVGText, Image } from "react-native-svg"
@@ -20,6 +17,8 @@ import {
GestureHandlerRootView,
} from "react-native-gesture-handler"
+import { black, peach, transparent } from "../../../assets/colors/colors"
+
import profile_picture_0 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-0.png"
import profile_picture_1 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-1.png"
import profile_picture_2 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-2.png"
@@ -43,10 +42,12 @@ const SHORT_PRESS_DURATION = 100
const NODE_HITBOX_SIZE = 20 // Hitbox size of the nodes
const DEFAULT_NODE_SIZE = 10 // Default size of the nodes
const DEFAULT_NODE_SIZE_INCREMENT = 2 // Increment in the size of the nodes
+const NODE_HIGHLIGHT_RATIO = 1.3
+const NODE_TEXT_OFFSET = 1.5
-const DEFAULT_LINK_COLOR = "black" // Default color of the links
+const DEFAULT_LINK_COLOR = black // Default color of the links
const DEFAULT_CLICKED_NODE_ID = ""
-
+const INITIAL_SCALE = 1 // Initial scale of the graph
const MAX_ITERATIONS = 1000 // Maximum number of iterations for the used algorithn
const WIDTH = Dimensions.get("window").width // Width of the screen
@@ -69,7 +70,9 @@ const TOTAL_FRAMES = FPS * (ANIMATION_DURATION / 1000) // Total number of frames
const ForceDirectedGraph: React.FC<{
graph: Graph
constrainedNodeId: string
-}> = ({ graph, constrainedNodeId }) => {
+ onModalPress: (uid: string) => void
+}> = ({ graph, constrainedNodeId, onModalPress}) => {
+
// States to store the nodes, links, sizes and loading status
const [nodes, setNodes] = useState([])
const [links, setLinks] = useState([])
@@ -81,13 +84,11 @@ const ForceDirectedGraph: React.FC<{
const [clickedNodeID, setClickedNodeID] = useState(
DEFAULT_CLICKED_NODE_ID,
) // Node ID of clicked node
- const [scale, setScale] = useState(1)
- const [lastScale, setLastScale] = useState(1) // Add state to keep track of last scale
+ const [scale, setScale] = useState(INITIAL_SCALE)
+ const [lastScale, setLastScale] = useState(INITIAL_SCALE) // Add state to keep track of last scale
const [gestureEnabled, setGestureEnabled] = useState(true) // Add state to keep track of animation start
- const [modalVisible, setModalVisible] = useState(false)
-
const pressStartRef = useRef(0)
const panRef = useRef(null)
@@ -96,28 +97,35 @@ const ForceDirectedGraph: React.FC<{
// Use effect to update the graph
useEffect(() => {
// Get the initial links, nodes and sizes
+
const initialLinks = graph.getLinks()
- const initialNodes = graph.getNodes()
- const initialSizes = setNodesSizes([...initialLinks])
+ const initialSizes = setNodesSizes(initialLinks)
// Set the links, nodes and sizes
- setLinks([...initialLinks])
- setNodes(
- fruchtermanReingold(
- [...initialNodes],
- initialLinks,
- constrainedNodeId,
- WIDTH,
- HEIGHT,
- MAX_ITERATIONS,
- ),
- )
+ setLinks(initialLinks)
+ if (graph.getInitialized() === false) {
+ setNodes(
+ fruchtermanReingold(
+ graph.getNodes(),
+ initialLinks,
+ constrainedNodeId,
+ WIDTH,
+ HEIGHT,
+ MAX_ITERATIONS,
+ ),
+ )
+ graph.setInitialized(true)
+ }
+ else {
+ setNodes(graph.getNodes())
+ }
setSizes(initialSizes)
setLoad(true)
+
}, [graph, constrainedNodeId])
// If the graph is not loaded, display an activity indicator
if (!load) {
- return
+ return
}
// Handle Dragging
@@ -142,7 +150,6 @@ const ForceDirectedGraph: React.FC<{
y: coordY(node),
})),
)
-
setClickedNodeID(DEFAULT_CLICKED_NODE_ID)
setTotalOffset({ x: 0, y: 0 })
}
@@ -180,7 +187,6 @@ const ForceDirectedGraph: React.FC<{
const nodeZoomIn = (clickedNode: Node) => {
setGestureEnabled(false) // Set animation started to true
- setModalVisible(true)
let currentFrame = 0
@@ -301,6 +307,13 @@ const ForceDirectedGraph: React.FC<{
const CIRCLES = nodes.map((node) => (
+
{
handlePressIn(() => {
pressStartRef.current = Date.now()
@@ -327,6 +340,8 @@ const ForceDirectedGraph: React.FC<{
}
onPressOut={() =>{
handlePressOut(() => {
+ onModalPress(node.id)
+ setClickedNodeID(DEFAULT_CLICKED_NODE_ID)
nodeZoomIn(node)
})
}
@@ -339,7 +354,7 @@ const ForceDirectedGraph: React.FC<{
y={
coordY(node) +
(sizes.get(node.id) ?? DEFAULT_NODE_SIZE) +
- DEFAULT_NODE_SIZE
+ NODE_TEXT_OFFSET * DEFAULT_NODE_SIZE
} // Position below the circle adjust 10 as needed
textAnchor="middle" // Center the text under the circle
>
@@ -350,48 +365,6 @@ const ForceDirectedGraph: React.FC<{
return (
-
- {
- setModalVisible(false)
- setClickedNodeID(DEFAULT_CLICKED_NODE_ID)
- setGestureEnabled(true)
- }}
- testID="modal-touchable"
- >
-
-
-
-
-
- Node ID: {clickedNodeID}
-
-
-
-
-
-
-
{
return link.source !== id && link.target !== id
})
+ this.setInitialized(false)
}
/**
@@ -160,6 +179,14 @@ export default class Graph {
this.links = this.links.filter((link: Link): boolean => {
return link.source !== source || link.target !== target
})
+ this.setInitialized(false)
+ }
+
+
+ getNodeById(id: string): Node | undefined {
+ return this.nodes.find((node: Node): boolean => {
+ return node.id === id
+ })
}
}
diff --git a/components/Graph/NodeModal/NodeModal.tsx b/components/Graph/NodeModal/NodeModal.tsx
new file mode 100644
index 00000000..48d4f806
--- /dev/null
+++ b/components/Graph/NodeModal/NodeModal.tsx
@@ -0,0 +1,78 @@
+import React from "react"
+import { Modal, TouchableWithoutFeedback, View, Text } from "react-native"
+import Svg, { Image } from "react-native-svg"
+import { Node } from "../Graph"
+
+import styles from "./styles"
+
+import profile_picture_0 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-0.png"
+import profile_picture_1 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-1.png"
+import profile_picture_2 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-2.png"
+import profile_picture_3 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-3.png"
+import profile_picture_4 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-4.png"
+import profile_picture_5 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-5.png"
+import profile_picture_6 from "../../../assets/graph-template-profile-pictures/graph-template-profile-picture-6.png"
+
+const PROFILE_PICTURES = [
+ profile_picture_0,
+ profile_picture_1,
+ profile_picture_2,
+ profile_picture_3,
+ profile_picture_4,
+ profile_picture_5,
+ profile_picture_6,
+]
+
+const NodeModal: React.FC<{
+ node: Node
+ visible: boolean
+ onPressOut: () => void
+ onContactPress: (uid: string) => void
+}> = ({ node, visible, onPressOut, onContactPress }) => {
+
+
+ return (
+
+ {
+ onPressOut()
+ }}
+ testID="modal-touchable"
+ >
+
+
+
+
+
+ Node ID: {node.id}
+
+
+
+
+
+
+ )
+}
+
+export default NodeModal
\ No newline at end of file
diff --git a/components/Graph/NodeModal/styles.ts b/components/Graph/NodeModal/styles.ts
new file mode 100644
index 00000000..74e1fd7e
--- /dev/null
+++ b/components/Graph/NodeModal/styles.ts
@@ -0,0 +1,54 @@
+import { StyleSheet } from "react-native"
+import { black, lightPeach, peach } from "../../../assets/colors/colors"
+import { globalStyles } from "../../../assets/global/globalStyles"
+
+const styles = StyleSheet.create({
+ container: {
+ alignItems: "center",
+ flex: 1,
+ justifyContent: "center",
+ },
+ modalContainer: {
+ alignItems: "center",
+ flex: 1,
+ justifyContent: "flex-end",
+ },
+ modalProfileName: {
+ fontFamily: globalStyles.text.fontFamily,
+ fontSize: 20,
+ left: 20,
+ position: "absolute",
+ top: 120,
+ },
+ modalProfilePicture: {
+ alignItems: "center",
+ height: 80,
+ justifyContent: "center",
+ left: 20,
+ position: "absolute",
+ top: 20,
+ width: 80,
+ },
+ modalView: {
+ alignItems: "center",
+ backgroundColor: peach,
+ borderColor: lightPeach,
+ borderRadius: 20,
+ borderWidth: 3,
+ elevation: 5,
+ height: "40%",
+ justifyContent: "center",
+ margin: 20,
+ padding: 35,
+ shadowColor: black,
+ shadowOffset: {
+ width: 0,
+ height: 2,
+ },
+ shadowOpacity: 0.25,
+ shadowRadius: 4,
+ width: "90%",
+ },
+})
+
+export default styles
diff --git a/components/Graph/graphAlgorithms/FruchtermanReingold.tsx b/components/Graph/graphAlgorithms/FruchtermanReingold.tsx
index 819c7905..9eed539b 100644
--- a/components/Graph/graphAlgorithms/FruchtermanReingold.tsx
+++ b/components/Graph/graphAlgorithms/FruchtermanReingold.tsx
@@ -20,14 +20,14 @@ export const fruchtermanReingold = (
iterations: number
) => {
// Maximum distance between nodes
- const k = Math.sqrt((width * height) / nodes.length)
+ const k = Math.sqrt((width * height) / nodes.length)/2
// Randomly initialize node positions
initializePositions(nodes, width, height)
// Initialize temperature and cooling rate
let temperature = width / 10
- const cooling = temperature / (iterations + 1)
+ const cooling = temperature / (iterations)
// Perform iterations
for (let i = 0; i < iterations; i++) {
@@ -155,7 +155,7 @@ const updatePositions = (
const distance = distanceBetween(0, 0, node.dx, node.dy)
// Skip if the node is too close
- if (distance != 0) {
+ if (distance > 0) {
// Calculate ratio of displacement, limited to temperature, to distance
const ratio = Math.min(distance, temperature) / distance
@@ -163,9 +163,6 @@ const updatePositions = (
node.x += node.dx * ratio
node.y += node.dy * ratio
- // Keep node within the graph
- node.x = Math.min(width, Math.max(0, node.x))
- node.y = Math.min(height, Math.max(0, node.y))
}
}
}
diff --git a/screens/Contacts/ContactGraph/ContactGraph.tsx b/screens/Contacts/ContactGraph/ContactGraph.tsx
index 62803ca9..dd8ebdd2 100644
--- a/screens/Contacts/ContactGraph/ContactGraph.tsx
+++ b/screens/Contacts/ContactGraph/ContactGraph.tsx
@@ -1,12 +1,88 @@
-import { View, Text } from "react-native"
+import { View, TextInput, TouchableWithoutFeedback, Keyboard } from "react-native"
import { styles } from "./styles"
+import Graph, { Node } from "../../../components/Graph/Graph"
-const ContactGraph = () => {
+import ForceDirectedGraph from "../../../components/Graph/ForceDirectedGraph/ForceDirectedGraph"
+import { useState } from "react"
+
+import NodeModal from "../../../components/Graph/NodeModal/NodeModal"
+
+import { graph, constrainedNodeId } from "./mockGraph"
+interface ContactGraphProps{
+ onContactPress: (uid : string) => void
+}
+
+const ContactGraph = ({onContactPress} : ContactGraphProps) => {
+
+ const [searchText, setSearchText] = useState("")
+
+ const [clickedNode, setClickedNode] = useState(graph.getNodes()[0])
+
+ const [modalVisible, setModalVisible] = useState(false)
+
+ const onModalPress = (uid: string) => {
+ const node = graph.getNodeById(uid)
+ if (node) {
+ setClickedNode(node)
+ setModalVisible(true)
+ }
+ }
+
+ const onPressOut = () => {
+ setModalVisible(false)
+ }
return (
+
+ Keyboard.dismiss()}>
- Graph view
+ {
+ setSearchText(text)
+ handleSearch(text, graph)
+ }
+ }
+ onSubmitEditing={() => handleQuery(onContactPress)}
+ />
+
+
+
+
+
+
+
)
}
export default ContactGraph
+
+function handleSearch(text: string, graph: Graph): void {
+ if (text === "") {
+ for (const node of graph.getNodes()) {
+ node.selected = false
+ }
+ }
+ else {
+ for (const node of graph.getNodes()) {
+ if (node.id.includes(text) || text.includes(node.id)) {
+ node.selected = true
+ }
+ else {
+ node.selected = false
+ }
+ }
+ }
+}
+
+function handleQuery(callback: (uid: string) => void): void {
+ for (const node of graph.getNodes()) {
+ if (node.selected) {
+ callback(node.id)
+ return
+ }
+ }
+}
+
diff --git a/screens/Contacts/ContactGraph/mockGraph.tsx b/screens/Contacts/ContactGraph/mockGraph.tsx
new file mode 100644
index 00000000..f5417368
--- /dev/null
+++ b/screens/Contacts/ContactGraph/mockGraph.tsx
@@ -0,0 +1,10 @@
+import Graph from "../../../components/Graph/Graph"
+
+export const graph = new Graph(
+ ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
+ ["0", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
+ ["1", "1", "1", "1", "1", "1", "2", "2", "3", "3"],
+ [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
+ )
+
+export const constrainedNodeId = "1"
\ No newline at end of file
diff --git a/screens/Contacts/ContactGraph/styles.ts b/screens/Contacts/ContactGraph/styles.ts
index 53d7637c..a4ade20b 100644
--- a/screens/Contacts/ContactGraph/styles.ts
+++ b/screens/Contacts/ContactGraph/styles.ts
@@ -1,11 +1,29 @@
import { StyleSheet } from "react-native"
+import { lightGray, lightPeach, peach } from "../../../assets/colors/colors"
export const styles = StyleSheet.create({
container: {
- alignItems: "center",
flex: 1,
- justifyContent: "center",
},
-
-})
+ graphContainer: {
+ backgroundColor: lightPeach, // Add background color
+ borderColor: peach, // Add border color
+ borderRadius: 10, // Round the corners
+ borderWidth: 3, // Add border width
+ flex: 1,
+ flexWrap: "wrap",
+ marginBottom: 10,
+ overflow: 'hidden', // Hide overflow content
+ width: "100%",
+ },
+ searchBar: {
+ borderColor: lightGray,
+ borderRadius: 40,
+ borderWidth: 1,
+ height: 60,
+ margin: 10,
+ padding: 20,
+ },
+ })
+
\ No newline at end of file
diff --git a/screens/Contacts/ExploreScreen.tsx b/screens/Contacts/ExploreScreen.tsx
index 21c8af6e..1687b7ee 100644
--- a/screens/Contacts/ExploreScreen.tsx
+++ b/screens/Contacts/ExploreScreen.tsx
@@ -33,7 +33,9 @@ const ExploreScreen = ({navigation} : ContactListScreenProps ) => {
}
{selectedTab === "Graph View" &&
-
+ navigation.navigate("ExternalProfile", {uid: uid})}
+ />
}