From f5dbb4e7326c484f248cd42e0e0b173fe2ede1e3 Mon Sep 17 00:00:00 2001
From: StarNumber12046 <64470722+StarNumber12046@users.noreply.github.com>
Date: Sun, 22 Sep 2024 17:13:32 +0200
Subject: [PATCH] =?UTF-8?q?Added=20gridview=20=F0=9F=8E=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/_layout.tsx | 1 +
app/gridView.tsx | 60 +++++++++++----
app/index.tsx | 164 +++++++++++++++++++++++++----------------
app/onboarding.tsx | 1 +
app/post/[id].tsx | 133 +++++++++++++++++++++++++++++++++
components/MenuBar.tsx | 40 +++++-----
components/ReBeal.tsx | 45 ++++++++---
package.json | 1 +
yarn.lock | 12 +++
9 files changed, 349 insertions(+), 108 deletions(-)
create mode 100644 app/post/[id].tsx
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 7cb6588..1cada86 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -100,6 +100,7 @@ export default function RootLayout() {
+
diff --git a/app/gridView.tsx b/app/gridView.tsx
index a4630ae..3f4930b 100644
--- a/app/gridView.tsx
+++ b/app/gridView.tsx
@@ -1,32 +1,64 @@
import { SmallPost } from "@/components/ReBeal";
import { FriendsPost, FriendsPostPost, getFriendsPosts } from "@/sdk";
-import { useEffect, useState } from "react";
+import { router } from "expo-router";
+import { useEffect, useRef, useState } from "react";
import { FlatList, View, Text, StyleSheet, Dimensions } from "react-native";
+import { useSharedValue } from "react-native-reanimated";
+import { PanGestureHandler } from "react-native-gesture-handler";
+import Animated from "react-native-reanimated";
export default function GridView() {
const screenWidth = Dimensions.get("window").width; // Get the screen width
const itemWidth = screenWidth / 3 - 5; // Calculate item width with some margin
const [friendsPosts, setFriendsPosts] = useState([]);
let last = 0;
+
+ const translateY = useSharedValue(0);
+
+ const debounceTimeoutRef = useRef(null);
+ const debounce = (func: Function, delay: number) => {
+ // Clear any existing timeout
+ if (debounceTimeoutRef.current) {
+ clearTimeout(debounceTimeoutRef.current);
+ }
+
+ // Set a new timeout
+ debounceTimeoutRef.current = setTimeout(() => {
+ func();
+ }, delay);
+ };
+ const onGestureEvent = (event: any) => {
+ if (event.nativeEvent.translationY > 50 && translateY.value === 0) {
+ // Check if the user swipes down and is at the top
+ debounce(() => {
+ router.push("/"); // Navigate to a new screen
+ }, 200);
+ }
+ };
+
useEffect(() => {
getFriendsPosts().then((posts) =>
setFriendsPosts(posts.map((item) => ({ ...item, i: last++ })))
);
}, []);
return (
-
- item.i.toString()}
- renderItem={({ item }) => (
-
- )}
- />
-
+
+
+
+ item.i.toString()}
+ renderItem={({ item }) => (
+
+ )}
+ />
+
+
+
);
}
diff --git a/app/index.tsx b/app/index.tsx
index e958f45..ebbbd76 100644
--- a/app/index.tsx
+++ b/app/index.tsx
@@ -1,4 +1,4 @@
-import React, { useContext, useEffect, useState } from "react";
+import React, { useContext, useEffect, useRef, useState } from "react";
import { IOScrollView, InView } from "react-native-intersection-observer";
import { View, StyleSheet, Text } from "react-native";
import { TopBar } from "@/components/TopBar";
@@ -7,6 +7,13 @@ import { CameraButton } from "@/components/CameraButton";
import { router } from "expo-router";
import AsyncStorage from "@react-native-async-storage/async-storage";
import getHeaders from "happy-headers";
+import { PanGestureHandler } from "react-native-gesture-handler"; // Import PanGestureHandler
+import Animated, {
+ useSharedValue,
+ useAnimatedStyle,
+ withSpring,
+} from "react-native-reanimated";
+
import {
checkToken,
FullUser,
@@ -28,6 +35,11 @@ export default function App() {
const [myPosts, setMyPosts] = useState([]);
const [me, setMe] = useState(null);
const userContext = useContext(ProfileContext);
+ const translateY = useSharedValue(0);
+ const animatedStyle = useAnimatedStyle(() => ({
+ transform: [{ translateY: translateY.value }],
+ }));
+
async function checkAuth() {
if (
!(await AsyncStorage.getItem("authToken")) ||
@@ -63,84 +75,110 @@ export default function App() {
}));
};
+ const debounceTimeoutRef = useRef(null);
+ const debounce = (func: Function, delay: number) => {
+ // Clear any existing timeout
+ if (debounceTimeoutRef.current) {
+ clearTimeout(debounceTimeoutRef.current);
+ }
+
+ // Set a new timeout
+ debounceTimeoutRef.current = setTimeout(() => {
+ func();
+ }, delay);
+ };
+ const onGestureEvent = (event: any) => {
+ if (event.nativeEvent.translationY > 50 && translateY.value === 0) {
+ // Check if the user swipes down and is at the top
+ debounce(() => {
+ router.push("/gridView"); // Navigate to a new screen
+ }, 200);
+ }
+ };
+
return (
-
- {
- getFriendsPosts().then((p) => setFriendsPosts(p));
- getMyPosts().then((p) => setMyPosts(p));
- getMyProfile(userContext).then((p) => setMe(p));
- }}
- />
-
-
- {myPosts.map((value) => (
-
+
+
+ {
+ getFriendsPosts().then((p) => setFriendsPosts(p));
+ getMyPosts().then((p) => setMyPosts(p));
+ getMyProfile(userContext).then((p) => setMe(p));
+ }}
+ />
+
+
-
-
- ))}
-
-
- {friendsPosts.map(
- (value) =>
- value && (
+ {myPosts.map((value) => (
- handleVisibilityChange(value.id, inView)
- }
+ style={{
+ flex: 1,
+ height: 240,
+ marginHorizontal: -10,
+ }}
>
-
- )
- )}
-
+ ))}
+
+
+ {friendsPosts.map(
+ (value) =>
+ value && (
+
+ handleVisibilityChange(value.id, inView)
+ }
+ >
+
+
+ )
+ )}
+
+
+
+
-
-
-
+
+
);
}
diff --git a/app/onboarding.tsx b/app/onboarding.tsx
index 155ace2..f857abe 100644
--- a/app/onboarding.tsx
+++ b/app/onboarding.tsx
@@ -25,6 +25,7 @@ function handleRegistrationError(errorMessage: string) {
// Register background handler
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log(remoteMessage);
+ if (remoteMessage.notification) return; // Ignore notifications
if (remoteMessage.data?.type == "moment") {
console.log("moments");
PushNotification.localNotification({
diff --git a/app/post/[id].tsx b/app/post/[id].tsx
new file mode 100644
index 0000000..ffd5a77
--- /dev/null
+++ b/app/post/[id].tsx
@@ -0,0 +1,133 @@
+import { MenuBar } from "@/components/MenuBar";
+import { FriendsPost, FriendsPostPost, User } from "@/sdk";
+import { useRoute } from "@react-navigation/native";
+import { View, Text, Image, Dimensions, TouchableOpacity } from "react-native";
+import { Buffer } from "buffer";
+import { useEffect, useState } from "react";
+import { FontAwesome, MaterialIcons } from "@expo/vector-icons";
+interface Params {
+ id: string;
+}
+
+function formatLateSeconds(lateInSeconds: number) {
+ if (lateInSeconds === 0) return null;
+ if (lateInSeconds < 60) return `${lateInSeconds} seconds late`;
+ const minutes = Math.floor(lateInSeconds / 60);
+ if (minutes < 60) return `${minutes} minutes late`;
+ const hours = Math.floor(minutes / 60);
+ return `${hours} hours late`;
+}
+
+export default function Post() {
+ const params = useRoute().params as Params | undefined;
+ if (!params) return null;
+ const postData: FriendsPostPost & { user: User } = JSON.parse(
+ Buffer.from(params.id, "base64").toString()
+ );
+
+ const [bigImage, setBigImage] = useState<"primary" | "secondary">("primary");
+
+ const title = (
+
+
+ {postData.user.username}
+
+
+ {
+ new Date(postData.postedAt as unknown as number)
+ .toTimeString()
+ .split(" ")[0]
+ }
+ {postData.lateInSeconds &&
+ " - " + formatLateSeconds(postData.lateInSeconds)}
+
+
+ );
+ return (
+
+
+
+
+
+
+ {
+ console.log("Switching images");
+ setBigImage(bigImage === "primary" ? "secondary" : "primary");
+ }}
+ >
+
+
+
+
+ {" "}
+ {postData.retakeCounter}{" "}
+ {postData.retakeCounter === 1 ? "retake" : "retakes"}
+
+
+
+ );
+}
diff --git a/components/MenuBar.tsx b/components/MenuBar.tsx
index cf12e50..98f99fb 100644
--- a/components/MenuBar.tsx
+++ b/components/MenuBar.tsx
@@ -1,23 +1,20 @@
import { AntDesign } from "@expo/vector-icons";
-import { router } from "expo-router";
+import { router, useRouter } from "expo-router";
+import React from "react";
import { View, Text, Pressable, StyleSheet } from "react-native";
export function MenuBar({
arrowLocation,
title,
}: {
arrowLocation: "left" | "right";
- title?: string;
+ title?: string | React.ReactNode;
}) {
+ const router = useRouter();
+
return (
{
- router.back();
- }
- : () => {}
- }
+ onPress={arrowLocation === "left" ? () => router.back() : undefined}
>
-
- {title ?? ReBeal.}
-
+
+
+ {!title && ReBeal.}
+ {title && typeof title === "string" && (
+ {title}
+ )}
+ {title && typeof title !== "string" && title}
+
+
{
- router.navigate("/");
- }
- : () => {}
+ arrowLocation === "right" ? () => router.navigate("/") : undefined
}
>
@@ -66,6 +63,11 @@ const styles = StyleSheet.create({
paddingHorizontal: 20,
backgroundColor: "#00000000",
},
+ textContainer: {
+ flex: 1, // Make the title's container take up available space
+ alignItems: "center", // Center the title within the container
+ },
+
cameraButton: {
backgroundColor: "#00000000",
width: 75,
diff --git a/components/ReBeal.tsx b/components/ReBeal.tsx
index 251c8ef..b2eff13 100644
--- a/components/ReBeal.tsx
+++ b/components/ReBeal.tsx
@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import * as Haptics from "expo-haptics";
-
+import * as Buffer from "buffer";
import {
View,
Image,
@@ -167,7 +167,15 @@ export function SmallPost({
}
return (
-
+ router.push(
+ ("/post/" +
+ Buffer.Buffer.from(JSON.stringify(post)).toString(
+ "base64"
+ )) as Href
+ )
+ }
style={[
styles.smallPostContainer,
{ height: width / primaryAspectRatio },
@@ -215,7 +223,7 @@ export function SmallPost({
>
{user.username}
-
+
);
}
@@ -235,6 +243,7 @@ export function ReBeal({
visible,
blurred,
userId,
+ postData,
}: {
primaryUrl: string;
secondaryUrl: string;
@@ -251,6 +260,7 @@ export function ReBeal({
visible: boolean;
blurred: boolean;
userId: string;
+ postData: FriendsPostPost & { user: User };
}) {
console.log(blurred);
const [bigImage, setBigImage] = useState<"primary" | "secondary">("primary");
@@ -312,15 +322,26 @@ export function ReBeal({
}}
/>
-
+
+ router.push(
+ ("/post/" +
+ Buffer.Buffer.from(JSON.stringify(postData)).toString(
+ "base64"
+ )) as Href
+ )
+ }
+ >
+
+
diff --git a/package.json b/package.json
index 54c1669..2e41ce6 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
"firebase-admin": "^12.5.0",
"happy-headers": "^1.5.0",
"libphonenumber-js": "^1.11.7",
+ "pusher-js": "^8.4.0-rc2",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.74.5",
diff --git a/yarn.lock b/yarn.lock
index abc6e34..d00ab83 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8186,6 +8186,13 @@ pure-rand@^6.0.0:
resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2"
integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==
+pusher-js@^8.4.0-rc2:
+ version "8.4.0-rc2"
+ resolved "https://registry.yarnpkg.com/pusher-js/-/pusher-js-8.4.0-rc2.tgz#44f33bfe5bc89f741d82601125d6095bde28261b"
+ integrity sha512-d87GjOEEl9QgO5BWmViSqW0LOzPvybvX6WA9zLUstNdB57jVJuR27zHkRnrav2a3+zAMlHbP2Og8wug+rG8T+g==
+ dependencies:
+ tweetnacl "^1.0.3"
+
qrcode-terminal@0.11.0:
version "0.11.0"
resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz#ffc6c28a2fc0bfb47052b47e23f4f446a5fbdb9e"
@@ -9527,6 +9534,11 @@ turbo-stream@2.4.0:
resolved "https://registry.yarnpkg.com/turbo-stream/-/turbo-stream-2.4.0.tgz#1e4fca6725e90fa14ac4adb782f2d3759a5695f0"
integrity sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==
+tweetnacl@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
+ integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
+
type-detect@4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"