diff --git a/app.json b/app.json index e6787c3..03faf2f 100644 --- a/app.json +++ b/app.json @@ -34,7 +34,7 @@ "infoPlist": { "NSFaceIDUsageDescription": "Requires FaceID To protect your CGPA Info" }, - "supportsTablet": false, + "supportsTablet": true, "bundleIdentifier": "com.sunnydhama.jiitcompanion", "buildNumber": "1.1.0", "googleServicesFile": "./firebase/GoogleService-Info.plist", diff --git a/assets/lottieFiles/heart.json b/assets/lottieFiles/heart.json new file mode 100644 index 0000000..9a5dc8b --- /dev/null +++ b/assets/lottieFiles/heart.json @@ -0,0 +1 @@ +{"v":"4.6.6","fr":25,"ip":0,"op":22,"w":148,"h":148,"nm":"2.0 A-首页-inline播放","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"形状图层 1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[74,74,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[25,25,100]}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0"],"t":2,"s":[0,0],"e":[29,29]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"n":["0p667_1_0p333_0","0p667_1_0p333_0"],"t":7,"s":[29,29],"e":[0,0]},{"t":16}]},"p":{"a":1,"k":[{"i":{"x":0.52,"y":1},"o":{"x":0.6,"y":0},"n":"0p52_1_0p6_0","t":1,"s":[0,0],"e":[0,189],"to":[0,31.5],"ti":[0,-40]},{"i":{"x":0.38,"y":1},"o":{"x":0.333,"y":0},"n":"0p38_1_0p333_0","t":6,"s":[0,189],"e":[0,240],"to":[0,40],"ti":[0,-8.5]},{"t":15}]},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"fl","c":{"a":0,"k":[1,0.1921569,0.2666667,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"rp","c":{"a":0,"k":8,"ix":1},"o":{"a":0,"k":0,"ix":2},"m":1,"ix":3,"tr":{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":45,"ix":4},"so":{"a":0,"k":100,"ix":5},"eo":{"a":0,"k":100,"ix":6},"nm":"变换"},"nm":"中继器 1","mn":"ADBE Vector Filter - Repeater"}],"ip":0,"op":250,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"Explosion Vol.1 08 / 1","cl":"1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[74,74,0]},"a":{"a":0,"k":[-120.395,32.605,0]},"s":{"a":1,"k":[{"i":{"x":[0,0,0.667],"y":[1.002,1.002,0.667]},"o":{"x":[1,1,0.333],"y":[0,0,0.333]},"n":["0_1p002_1_0","0_1p002_1_0","0p667_0p667_0p333_0p333"],"t":2,"s":[0,0,100],"e":[24,24,100]},{"t":14}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[367.211,367.211]},"p":{"a":0,"k":[0,0]},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse"},{"ty":"st","c":{"a":0,"k":[1,0.1921569,0.2666667,1]},"o":{"a":0,"k":100},"w":{"a":1,"k":[{"i":{"x":[0.297],"y":[1]},"o":{"x":[0.588],"y":[0]},"n":["0p297_1_0p588_0"],"t":2,"s":[240],"e":[0]},{"t":14}]},"lc":1,"lj":1,"ml":4,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[-120.395,32.605],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"Ellipse 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":30,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"“喜欢”轮廓","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0,"x":"var $bm_rt;\n$bm_rt = transform.rotation;"},"p":{"a":0,"k":[74,74,0],"x":"var $bm_rt;\n$bm_rt = transform.position;"},"a":{"a":0,"k":[25,22.5,0]},"s":{"a":1,"k":[{"i":{"x":[0.48,0.48,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.167],"y":[0.115,0.115,0.167]},"n":["0p48_1_0p333_0p115","0p48_1_0p333_0p115","0p667_0p667_0p167_0p167"],"t":0,"s":[100,100,100],"e":[60,60,100]},{"i":{"x":[0.516,0.516,0.667],"y":[1,1,0.667]},"o":{"x":[0.264,0.264,0.333],"y":[0,0,0.333]},"n":["0p516_1_0p264_0","0p516_1_0p264_0","0p667_0p667_0p333_0p333"],"t":2,"s":[60,60,100],"e":[130,130,100]},{"i":{"x":[0.605,0.605,0.667],"y":[1.005,1.005,0.667]},"o":{"x":[0.373,0.373,0.333],"y":[0,0,0.333]},"n":["0p605_1p005_0p373_0","0p605_1p005_0p373_0","0p667_0p667_0p333_0p333"],"t":7,"s":[130,130,100],"e":[100,100,100]},{"i":{"x":[0.663,0.663,0.833],"y":[0.978,0.978,0.833]},"o":{"x":[0.32,0.32,0.167],"y":[0,0,0.167]},"n":["0p663_0p978_0p32_0","0p663_0p978_0p32_0","0p833_0p833_0p167_0p167"],"t":11,"s":[100,100,100],"e":[105,105,100]},{"i":{"x":[0.64,0.64,0.833],"y":[0.973,0.973,0.833]},"o":{"x":[0.29,0.29,0.167],"y":[0.002,0.002,0.167]},"n":["0p64_0p973_0p29_0p002","0p64_0p973_0p29_0p002","0p833_0p833_0p167_0p167"],"t":14,"s":[105,105,100],"e":[100,100,100]},{"t":19}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.401,0],[2.068,-3.674],[4.874,0],[0,-6.245],[-0.912,-0.537],[-0.234,0],[-0.209,0.124],[0,14.79]],"o":[[-4.875,0],[-2.067,-3.674],[-7.402,0],[0,14.79],[0.209,0.124],[0.234,0],[0.912,-0.537],[0,-6.245]],"v":[[11.176,-20.5],[0,-14.302],[-11.175,-20.5],[-23,-7.795],[-0.676,20.315],[0,20.5],[0.676,20.315],[23,-7.795]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[1,0.1921569,0.2666667,1]},"o":{"a":0,"k":100},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"st","c":{"a":0,"k":[0.9843137,0.1921569,0.2666667,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":3.6},"lc":2,"lj":2,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[25,22.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":250,"st":0,"bm":0,"sr":1}]} \ No newline at end of file diff --git a/components/Card/index.js b/components/Card/index.js index 32dd636..b18096a 100644 --- a/components/Card/index.js +++ b/components/Card/index.js @@ -1,11 +1,21 @@ -import React, { useEffect, useState } from "react"; -import { StyleSheet, Text, View, Image, TouchableOpacity } from "react-native"; +import React, { useEffect, useState, useRef } from "react"; +import { + StyleSheet, + Text, + View, + Image, + TouchableOpacity, + TouchableWithoutFeedback, + Vibration, +} from "react-native"; import { Ionicons, EvilIcons } from "@expo/vector-icons"; import axios from "axios"; +import LottieView from "lottie-react-native"; import { Mixins, Typography } from "../../styles"; import { useTheme, useUser } from "../../contexts"; import { JIIT_SOCIAL_BASE_API } from "../../api/constants"; +import heartLottie from "../../assets/lottieFiles/heart.json"; export const Card = ({ item, navigation }) => { const { @@ -17,6 +27,10 @@ export const Card = ({ item, navigation }) => { const [likesLength, setlikesLength] = useState(0); const [isLiked, setisLiked] = useState(false); + const [lastPress, setLastPress] = useState(0); + const [heartDisplay, setHeartDisplay] = useState("none"); + + const heartRef = useRef(null); useEffect(() => { const _likesLength = item?.likes?.length || 0; @@ -44,16 +58,38 @@ export const Card = ({ item, navigation }) => { const increaseView = async () => { try { await axios.get(`${JIIT_SOCIAL_BASE_API}/post/${item?._id}/view`); + heartRef.current.play(); } catch (err) { console.log("view failed"); console.log(err); } }; - const decreaseLike = async () => {}; - console.log(item?.author); + const decreaseLike = async () => { + heartRef.current.play(); + }; + + const handleDoubleTap = () => { + let currentTime = new Date().getTime(); + let delta = currentTime - lastPress; + setLastPress(currentTime); + Vibration.vibrate(100); + + //if not double tap + if (delta > 300) return; + + increaseLike(); + + //heart animation + setHeartDisplay("flex"); + heartRef.current.play(); + setTimeout(() => { + setHeartDisplay("none"); + }, 1000); + }; + return ( - <> + { - + + + + + + + + + {isLiked ? ( - + + + ) : ( { + navigation.navigate("comments", { + comments: item?.comments, + _id: item?._id, + }) + } /> - {likesLength ? ( - - Liked by {item?.likes[0]?.enrollment_number || user?.enrollmentNumber}{" "} - and {likesLength - 1} others - - ) : ( - - {likesLength} likes - - )} + + + navigation.navigate("likes", { + likes: item?.likes, + _id: item?._id, + }) + } + > + + {likesLength ? ( + + Liked by{" "} + {item?.likes[0]?.enrollment_number || user?.enrollmentNumber} and{" "} + {likesLength - 1} others + + ) : ( + + {likesLength} likes + + )} + + + {item?.comments[0] && ( {item?.comments[0]?.author?.enrollment_number} )} - navigation.navigate("comments", { comments: item?.comments, @@ -120,12 +196,13 @@ export const Card = ({ item, navigation }) => { > view all {item?.comments?.length} comments - - + + ); }; const styles = StyleSheet.create({ + container: {}, image: { resizeMode: "contain", height: Mixins.WINDOW_WIDTH, @@ -171,4 +248,19 @@ const styles = StyleSheet.create({ fontFamily: Typography.FONT_FAMILY_REGULAR, ...Mixins.padding(10, 10, 40, 10), }, + heartLottie: { + width: Mixins.scaleSize(200), + height: Mixins.scaleSize(200), + }, + lottieView: { + position: "absolute", + backgroundColor: "transparent", + zIndex: 10, + alignItems: "center", + justifyContent: "center", + top: 0, + left: 0, + right: 0, + bottom: 0, + }, }); diff --git a/navigation/JIITSocialScreenStack.js b/navigation/JIITSocialScreenStack.js index e953698..3564810 100644 --- a/navigation/JIITSocialScreenStack.js +++ b/navigation/JIITSocialScreenStack.js @@ -7,6 +7,7 @@ import { Ionicons } from "@expo/vector-icons"; import { JIITSocial } from "../screens/App/JIITSocial"; import { AddPost } from "../screens/App/JIITSocial/AddPost"; import Comment from "../screens/App/JIITSocial/Comment"; +import Likes from "../screens/App/JIITSocial/Likes"; const JIITSocialStack = createStackNavigator(); @@ -77,6 +78,11 @@ function JIITSocialScreenStack({ navigation }) { name="comments" component={Comment} /> + ); } diff --git a/package.json b/package.json index 6d952c7..78f7ebd 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "expo-web-browser": "~8.2.1", "firebase": "^7.15.0", "install": "^0.13.0", + "lottie-react-native": "~2.6.1", "moment": "^2.26.0", "react": "~16.9.0", "react-dom": "~16.9.0", diff --git a/screens/App/Attendance/Attendance.js b/screens/App/Attendance/Attendance.js index 3605931..5d65fbb 100644 --- a/screens/App/Attendance/Attendance.js +++ b/screens/App/Attendance/Attendance.js @@ -4,6 +4,7 @@ import { StyleSheet, RefreshControl, StatusBar, + Vibration, } from "react-native"; import * as Analytics from "expo-firebase-analytics"; @@ -23,6 +24,7 @@ const Attendance = () => { useEffect(() => { Analytics.logEvent("attendance_screen_view"); + Vibration.vibrate(100); }, []); if (!classes?.length) return <> ; diff --git a/screens/App/JIITSocial/AddPost.js b/screens/App/JIITSocial/AddPost.js index a619895..a30ea0a 100644 --- a/screens/App/JIITSocial/AddPost.js +++ b/screens/App/JIITSocial/AddPost.js @@ -14,6 +14,7 @@ import { TextInput, TouchableOpacity, View, + Vibration, } from "react-native"; import { ScrollView } from "react-native-gesture-handler"; import { addPostToDB } from "../../../api/requests"; @@ -60,6 +61,7 @@ export const AddPost = ({ navigation }) => { if (!result.cancelled) { setDisabled(false); setImage("data:image/jpeg;base64," + result.base64); + Vibration.vibrate(100); } }; @@ -71,6 +73,8 @@ export const AddPost = ({ navigation }) => { ref.current.alertWithType("success", "Image uploaded successfully", ""); if (res.message == "error") ref.current.alertWithType("error", "Image upload error", ""); + + Vibration.vibrate(100); setisLoading(false); navigation.goBack(); }; diff --git a/screens/App/JIITSocial/Comment.js b/screens/App/JIITSocial/Comment.js index 16441af..a260dec 100644 --- a/screens/App/JIITSocial/Comment.js +++ b/screens/App/JIITSocial/Comment.js @@ -9,6 +9,7 @@ import { Button, Image, ActivityIndicator, + Vibration, } from "react-native"; import axios from "axios"; @@ -67,6 +68,7 @@ const Comment = ({ item, navigation, route }) => { }; let newCommentsArray = [...commentsArray, newComment]; setcommentsArray(newCommentsArray); + Vibration.vibrate(100); setloading(false); } catch (err) { console.log("adding comment error"); diff --git a/screens/App/JIITSocial/JIITSocial.js b/screens/App/JIITSocial/JIITSocial.js index 59a3c48..36287a7 100644 --- a/screens/App/JIITSocial/JIITSocial.js +++ b/screens/App/JIITSocial/JIITSocial.js @@ -1,22 +1,34 @@ +import Axios from "axios"; import React, { useEffect, useState } from "react"; import { - StyleSheet, - View, + ActivityIndicator, FlatList, RefreshControl, - ActivityIndicator, + StyleSheet, + View, + Vibration, } from "react-native"; - +import { useFocusEffect } from "@react-navigation/native"; +import { JIIT_SOCIAL_BASE_API } from "../../../api/constants"; import { Card } from "../../../components"; import { useTheme } from "../../../contexts"; -import Axios from "axios"; -import { JIIT_SOCIAL_BASE_API } from "../../../api/constants"; const JIITSocial = ({ navigation }) => { const [loading, setLoading] = useState(false); const [data, setData] = useState(null); const [refreshing, setrefreshing] = useState(); + // onFocus refresh hook + useEffect(() => { + const unsubscribe = navigation.addListener("focus", () => { + // The screen is focused + getPosts(); + }); + + // Return the function to unsubscribe from the event so it gets removed on unmount + return unsubscribe; + }, [navigation]); + const { theme: { colors: { text }, @@ -29,6 +41,7 @@ const JIITSocial = ({ navigation }) => { let res = await Axios.get(`${JIIT_SOCIAL_BASE_API}/posts`); let posts = res?.data?.posts?.reverse(); setData(posts); + Vibration.vibrate(100); setrefreshing(false); } catch (err) { setData([]); @@ -42,6 +55,7 @@ const JIITSocial = ({ navigation }) => { (async () => { setLoading(true); await getPosts(); + Vibration.vibrate(100); setLoading(false); })(); }, []); diff --git a/screens/App/JIITSocial/Likes.js b/screens/App/JIITSocial/Likes.js new file mode 100644 index 0000000..e5e1c48 --- /dev/null +++ b/screens/App/JIITSocial/Likes.js @@ -0,0 +1,58 @@ +import React, { useEffect, useState } from "react"; +import { Image, StyleSheet, Text, View } from "react-native"; +import { ScrollView } from "react-native-gesture-handler"; +import { useTheme } from "../../../contexts"; +import { Mixins, Typography } from "../../../styles"; + +const Likes = ({ route }) => { + const { + theme: { + colors: { text }, + }, + } = useTheme(); + + const [likesArray, setlikesArray] = useState([]); + + const { _id, likes } = route.params; + useEffect(() => { + setlikesArray(likes); + }, []); + + return ( + + {likesArray?.map((item, key) => ( + + + + + {item?.enrollment_number} + + + + ))} + + ); +}; +export default Likes; + +const styles = StyleSheet.create({ + avatar: { + height: Mixins.scaleSize(30), + width: Mixins.scaleSize(30), + borderRadius: Mixins.scaleSize(15), + resizeMode: "cover", + marginRight: Mixins.scaleSize(20), + }, + + commentContainer: { + flexDirection: "row", + alignItems: "center", + ...Mixins.padding(10, 10, 10, 10), + }, + commentText: { + flex: 8, + }, +}); diff --git a/screens/App/TimeTable/TimeTable.js b/screens/App/TimeTable/TimeTable.js index 1e076f8..375b198 100644 --- a/screens/App/TimeTable/TimeTable.js +++ b/screens/App/TimeTable/TimeTable.js @@ -1,19 +1,18 @@ +import * as Analytics from "expo-firebase-analytics"; +import moment from "moment"; import React, { useEffect } from "react"; import { ActivityIndicator, + Platform, ScrollView, + StatusBar, StyleSheet, - Platform, + Vibration, } from "react-native"; import Carousel from "react-native-snap-carousel"; -import * as Analytics from "expo-firebase-analytics"; - import { TimeTableDayContainer } from "../../../components"; -import { useTheme, useUser, useDropDown } from "../../../contexts"; +import { useDropDown, useTheme, useUser } from "../../../contexts"; import { Mixins, Typography } from "../../../styles"; -import moment from "moment"; -import { StatusBar } from "react-native"; -import DropdownAlert from "react-native-dropdownalert"; const dayInNumber = parseInt(moment().format("d")); @@ -31,6 +30,7 @@ const TimeTable = () => { useEffect(() => { Analytics.logEvent("timetable_page_view"); + Vibration.vibrate(100); }, []); if (!timeTable?.length) return ; diff --git a/yarn.lock b/yarn.lock index b459d70..1ac719d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4462,6 +4462,11 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +dedent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.6.0.tgz#0e6da8f0ce52838ef5cec5c8f9396b0c1b64a3cb" + integrity sha1-Dm2o8M5Sg471zsXI+TlrDBtko8s= + deep-assign@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-3.0.0.tgz#c8e4c4d401cba25550a2f0f486a2e75bc5f219a2" @@ -6936,6 +6941,21 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4 dependencies: js-tokens "^3.0.0 || ^4.0.0" +lottie-ios@2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/lottie-ios/-/lottie-ios-2.5.0.tgz#55c808e785d4a6933b0c10b395530b17098b05de" + integrity sha1-VcgI54XUppM7DBCzlVMLFwmLBd4= + +lottie-react-native@~2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/lottie-react-native/-/lottie-react-native-2.6.1.tgz#330d24fa6aac5928ea63f8e181b9b7d930a1a119" + integrity sha512-Z+6lARvWWhB8n8OSmW7/aHkV71ftsmO7hYXFt0D+REy/G40mpkQt1H7Cdy1HqY4cKAp7EYDWVxhu5+fkdD6o4g== + dependencies: + invariant "^2.2.2" + lottie-ios "2.5.0" + prop-types "^15.5.10" + react-native-safe-module "^1.1.0" + lower-case@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" @@ -8952,6 +8972,13 @@ react-native-safe-area-context@0.7.3: resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-0.7.3.tgz#ad6bd4abbabe195332c53810e4ce5851eb21aa2a" integrity sha512-9Uqu1vlXPi+2cKW/CW6OnHxA76mWC4kF3wvlqzq4DY8hn37AeiXtLFs2WkxH4yXQRrnJdP6ivc65Lz+MqwRZAA== +react-native-safe-module@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/react-native-safe-module/-/react-native-safe-module-1.2.0.tgz#a23824ca24edc2901913694a76646475113d570d" + integrity sha1-ojgkyiTtwpAZE2lKdmRkdRE9Vw0= + dependencies: + dedent "^0.6.0" + react-native-screens@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.2.0.tgz#cc4cdf17426fdda97ad93a5e812a1899390f1978"