├── assets ├── icon.png ├── splash.png ├── favicon.png ├── adaptive-icon.png ├── screenshots │ ├── image1.png │ └── image2.png └── fonts │ ├── Poppins-Regular.ttf │ └── Poppins-SemiBold.ttf ├── README.md ├── src ├── lib │ ├── instagramPostParser.ts │ └── clipboard.ts ├── utils │ ├── flashMessage.ts │ └── notification.ts ├── components │ ├── info.tsx │ ├── header.tsx │ ├── menu.tsx │ ├── imageViewer.tsx │ └── card.tsx └── screens │ ├── post.tsx │ └── profile.tsx ├── tsconfig.json ├── .expo-shared └── assets.json ├── .gitignore ├── babel.config.js ├── app.json ├── package.json └── App.tsx /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devyuji/isave-app/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devyuji/isave-app/HEAD/assets/splash.png -------------------------------------------------------------------------------- /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devyuji/isave-app/HEAD/assets/favicon.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository is deprecated! see this [one](https://github.com/devyuji/isave_flutter) 2 | -------------------------------------------------------------------------------- /assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devyuji/isave-app/HEAD/assets/adaptive-icon.png -------------------------------------------------------------------------------- /assets/screenshots/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devyuji/isave-app/HEAD/assets/screenshots/image1.png -------------------------------------------------------------------------------- /assets/screenshots/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devyuji/isave-app/HEAD/assets/screenshots/image2.png -------------------------------------------------------------------------------- /assets/fonts/Poppins-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devyuji/isave-app/HEAD/assets/fonts/Poppins-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/Poppins-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devyuji/isave-app/HEAD/assets/fonts/Poppins-SemiBold.ttf -------------------------------------------------------------------------------- /src/lib/instagramPostParser.ts: -------------------------------------------------------------------------------- 1 | export const instagramUrlParser = (url: string) => { 2 | return url.split("/")[4]; 3 | }; 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo/tsconfig.base", 3 | "compilerOptions": { 4 | "strict": true, 5 | "allowJs": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.expo-shared/assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, 3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true 4 | } 5 | -------------------------------------------------------------------------------- /src/lib/clipboard.ts: -------------------------------------------------------------------------------- 1 | import * as Clipboard from "expo-clipboard"; 2 | 3 | export const getClipboardData = async () => { 4 | const res = await Clipboard.getStringAsync(); 5 | return res; 6 | }; 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .expo/ 3 | npm-debug.* 4 | *.jks 5 | *.p8 6 | *.p12 7 | *.key 8 | *.mobileprovision 9 | *.orig.* 10 | web-build/ 11 | 12 | # macOS 13 | .DS_Store 14 | 15 | yarn-error.log 16 | -------------------------------------------------------------------------------- /src/utils/flashMessage.ts: -------------------------------------------------------------------------------- 1 | import { ToastAndroid } from "react-native"; 2 | 3 | export const flashMessage = (msg: string) => { 4 | ToastAndroid.showWithGravity(msg, ToastAndroid.SHORT, ToastAndroid.CENTER); 5 | }; 6 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: ["babel-preset-expo"], 5 | plugins: ["react-native-reanimated/plugin"], 6 | env: { 7 | production: { 8 | plugins: ["react-native-paper/babel"], 9 | }, 10 | }, 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /src/utils/notification.ts: -------------------------------------------------------------------------------- 1 | import { showMessage } from "react-native-flash-message"; 2 | 3 | export const successMessage = (msg: string) => { 4 | showMessage({ 5 | message: msg, 6 | backgroundColor: "#000", 7 | color: "#fff", 8 | }); 9 | }; 10 | 11 | export const errorMessage = (msg: string) => { 12 | showMessage({ 13 | message: msg, 14 | type: "danger", 15 | }); 16 | }; 17 | -------------------------------------------------------------------------------- /src/components/info.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { View, Text } from "react-native"; 3 | 4 | interface InfoProps { 5 | text: string; 6 | } 7 | 8 | const Info: FC = ({ text }) => { 9 | return ( 10 | 11 | 19 | {text} 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default Info; 26 | -------------------------------------------------------------------------------- /src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { StyleSheet } from "react-native"; 3 | import { Appbar } from "react-native-paper"; 4 | 5 | import Menu from "../components/menu"; 6 | 7 | const Header: FC = () => { 8 | return ( 9 | 10 | 11 | 12 | 13 | ); 14 | }; 15 | 16 | const styles = StyleSheet.create({ 17 | header: { 18 | backgroundColor: "#fff", 19 | elevation: 0, 20 | }, 21 | }); 22 | 23 | export default Header; 24 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "isave", 4 | "slug": "isave", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "primaryColor": "#ffffff", 8 | "scheme": "isave", 9 | "icon": "./assets/icon.png", 10 | "splash": { 11 | "image": "./assets/splash.png", 12 | "resizeMode": "contain", 13 | "backgroundColor": "#ffffff" 14 | }, 15 | "githubUrl": "https://github.com/devyuji/isave-app", 16 | "updates": { 17 | "fallbackToCacheTimeout": 0 18 | }, 19 | "assetBundlePatterns": ["**/*"], 20 | "ios": { 21 | "supportsTablet": true 22 | }, 23 | "android": { 24 | "adaptiveIcon": { 25 | "foregroundImage": "./assets/adaptive-icon.png", 26 | "backgroundColor": "#FFFFFF" 27 | }, 28 | "package": "com.isave.app", 29 | "versionCode": 1 30 | }, 31 | "web": { 32 | "favicon": "./assets/favicon.png" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/components/menu.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, useState } from "react"; 2 | import { Linking } from "react-native"; 3 | import { IconButton, Menu } from "react-native-paper"; 4 | 5 | const HeaderMenu: FC = () => { 6 | const [visible, setVisible] = useState(false); 7 | 8 | const openMenu = () => setVisible(true); 9 | 10 | const closeMenu = () => setVisible(false); 11 | 12 | const openBrowser = (url: string) => { 13 | Linking.openURL(url); 14 | }; 15 | 16 | return ( 17 | } 21 | statusBarHeight={30} 22 | > 23 | openBrowser("https://isave.cc")} 25 | icon="web" 26 | title="Website" 27 | /> 28 | openBrowser("https://github.com/devyuji/isave-app")} 30 | icon="github" 31 | title="Github" 32 | /> 33 | openBrowser("https://instagram.com/devyuji")} 35 | icon="instagram" 36 | title="Instagram" 37 | /> 38 | 39 | ); 40 | }; 41 | 42 | export default HeaderMenu; 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "scripts": { 4 | "start": "expo start", 5 | "android": "expo start --android", 6 | "ios": "expo start --ios", 7 | "web": "expo start --web", 8 | "eject": "expo eject" 9 | }, 10 | "dependencies": { 11 | "@react-native-community/masked-view": "0.1.10", 12 | "@react-navigation/material-top-tabs": "^5.3.15", 13 | "@react-navigation/native": "^5.9.4", 14 | "axios": "^0.21.1", 15 | "expo": "^42.0.0", 16 | "expo-clipboard": "~1.1.0", 17 | "expo-media-library": "~12.1.2", 18 | "expo-status-bar": "~1.0.4", 19 | "react": "16.13.1", 20 | "react-dom": "16.13.1", 21 | "react-native": "https://github.com/expo/react-native/archive/sdk-42.0.0.tar.gz", 22 | "react-native-flash-message": "^0.1.23", 23 | "react-native-gesture-handler": "~1.10.2", 24 | "react-native-paper": "^4.7.2", 25 | "react-native-reanimated": "~2.2.0", 26 | "react-native-safe-area-context": "3.2.0", 27 | "react-native-screens": "~3.4.0", 28 | "react-native-tab-view": "^2.16.0", 29 | "react-native-web": "~0.13.12" 30 | }, 31 | "devDependencies": { 32 | "@babel/core": "~7.9.0", 33 | "@types/react": "~16.9.35", 34 | "@types/react-native": "~0.63.2", 35 | "typescript": "~4.0.0" 36 | }, 37 | "private": true 38 | } 39 | -------------------------------------------------------------------------------- /src/components/imageViewer.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { 3 | Dimensions, 4 | Image, 5 | Modal, 6 | StyleSheet, 7 | View, 8 | Pressable, 9 | } from "react-native"; 10 | import { AntDesign } from "@expo/vector-icons"; 11 | 12 | interface ImageViewerProps { 13 | visible: boolean; 14 | onDismiss: () => void; 15 | imageUrl: string; 16 | } 17 | 18 | const { height } = Dimensions.get("screen"); 19 | 20 | const ImageViewer: FC = ({ 21 | visible, 22 | onDismiss, 23 | imageUrl, 24 | }) => { 25 | return ( 26 | 32 | 33 | 34 | 35 | 36 | 41 | 42 | 43 | ); 44 | }; 45 | 46 | const styles = StyleSheet.create({ 47 | container: { 48 | flex: 1, 49 | alignItems: "center", 50 | justifyContent: "center", 51 | backgroundColor: "#000", 52 | }, 53 | close: { 54 | position: "absolute", 55 | top: 30, 56 | right: 10, 57 | zIndex: 1000, 58 | }, 59 | image: { 60 | width: "100%", 61 | height, 62 | }, 63 | }); 64 | 65 | export default ImageViewer; 66 | -------------------------------------------------------------------------------- /App.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { DefaultTheme, Provider as PaperProvider } from "react-native-paper"; 3 | import { useFonts } from "expo-font"; 4 | import { NavigationContainer } from "@react-navigation/native"; 5 | import { createMaterialTopTabNavigator } from "@react-navigation/material-top-tabs"; 6 | import FlashMessage from "react-native-flash-message"; 7 | 8 | // screens 9 | import Post from "./src/screens/post"; 10 | import Profile from "./src/screens/profile"; 11 | import Header from "./src/components/header"; 12 | import axios from "axios"; 13 | 14 | const Tab = createMaterialTopTabNavigator(); 15 | 16 | const App: FC = () => { 17 | axios.defaults.baseURL = "http://localhost:5001"; 18 | 19 | const [fontLoaded] = useFonts({ 20 | regular: require("./assets/fonts/Poppins-Regular.ttf"), 21 | semi_bold: require("./assets/fonts/Poppins-SemiBold.ttf"), 22 | }); 23 | 24 | const theme = { 25 | ...DefaultTheme, 26 | roundness: 5, 27 | colors: { 28 | ...DefaultTheme.colors, 29 | primary: "#000000", 30 | accent: "#f1c40f", 31 | }, 32 | }; 33 | 34 | if (!fontLoaded) { 35 | return null; 36 | } 37 | 38 | return ( 39 | 40 |
41 | 42 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | ); 71 | }; 72 | 73 | export default App; 74 | -------------------------------------------------------------------------------- /src/screens/post.tsx: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import React, { FC, useState } from "react"; 3 | import { 4 | ScrollView, 5 | StyleSheet, 6 | View, 7 | TextInput, 8 | Pressable, 9 | } from "react-native"; 10 | import { Button } from "react-native-paper"; 11 | import { Feather } from "@expo/vector-icons"; 12 | 13 | // components 14 | import Card from "../components/card"; 15 | import Info from "../components/info"; 16 | 17 | // utils 18 | import { errorMessage } from "../utils/notification"; 19 | 20 | // lib 21 | import { getClipboardData } from "../lib/clipboard"; 22 | import { instagramUrlParser } from "../lib/instagramPostParser"; 23 | 24 | const Post: FC = () => { 25 | const [text, setText] = useState(""); 26 | const [prevText, setPrevText] = useState(""); 27 | const [DATA, setData] = useState(); 28 | const [loading, setLoading] = useState(false); 29 | const [showClearInputBtn, setShowClearInputBtn] = useState(false); 30 | 31 | const similarUrlCheck = (): boolean => { 32 | if (text === prevText) { 33 | return false; 34 | } 35 | 36 | return true; 37 | }; 38 | 39 | const urlChecker = (): boolean => { 40 | const p = new RegExp("(https?://(?:www.)?instagram.com/p/([^/?#&]+)).*"); 41 | const tv = new RegExp("(https?://(?:www.)?instagram.com/tv/([^/?#&]+)).*"); 42 | const reel = new RegExp( 43 | "(https?://(?:www.)?instagram.com/reel/([^/?#&]+)).*" 44 | ); 45 | 46 | if (text.match(p) || text.match(tv) || text.match(reel)) return true; 47 | 48 | return false; 49 | }; 50 | 51 | const fetchApi = async () => { 52 | if (text && urlChecker() && similarUrlCheck()) { 53 | const id = instagramUrlParser(text); 54 | setLoading(true); 55 | try { 56 | const { data } = await axios.post("/post", { 57 | id, 58 | }); 59 | setPrevText(text); 60 | setData(data); 61 | } catch (err) { 62 | setPrevText(""); 63 | errorMessage("Something went wrong try again"); 64 | } 65 | setLoading(false); 66 | } 67 | }; 68 | 69 | const input = (text: string) => { 70 | setText(text); 71 | 72 | if (text.length > 0) setShowClearInputBtn(true); 73 | else setShowClearInputBtn(false); 74 | }; 75 | 76 | const setClipboard = async () => { 77 | const res = await getClipboardData(); 78 | setText(res); 79 | setShowClearInputBtn(true); 80 | }; 81 | 82 | return ( 83 | 84 | 85 | 86 | 95 | {showClearInputBtn ? ( 96 | { 98 | setText(""); 99 | setShowClearInputBtn(false); 100 | }} 101 | style={{ marginLeft: 5 }} 102 | > 103 | 104 | 105 | ) : ( 106 | 107 | 108 | 109 | )} 110 | 111 | 120 | 121 | 122 | 123 | {DATA ? : } 124 | 125 | 126 | ); 127 | }; 128 | 129 | const styles = StyleSheet.create({ 130 | container: { 131 | flex: 1, 132 | backgroundColor: "#fff", 133 | }, 134 | inputOptions: { 135 | paddingHorizontal: 20, 136 | marginTop: 20, 137 | }, 138 | inputContainer: { 139 | flex: 1, 140 | flexDirection: "row", 141 | alignItems: "center", 142 | borderColor: "#000", 143 | borderWidth: 2, 144 | borderRadius: 5, 145 | padding: 15, 146 | overflow: "hidden", 147 | }, 148 | input: { 149 | flex: 1, 150 | fontSize: 14, 151 | fontFamily: "regular", 152 | }, 153 | btn: { 154 | marginTop: 10, 155 | elevation: 0, 156 | }, 157 | btnText: { 158 | color: "white", 159 | textTransform: "uppercase", 160 | letterSpacing: 2, 161 | fontFamily: "semi_bold", 162 | }, 163 | cardContainer: { 164 | marginTop: 20, 165 | marginHorizontal: 20, 166 | }, 167 | }); 168 | 169 | export default Post; 170 | -------------------------------------------------------------------------------- /src/components/card.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { Image, StyleSheet, View } from "react-native"; 3 | import { Button, Surface } from "react-native-paper"; 4 | import * as FileSystem from "expo-file-system"; 5 | import * as MediaLibrary from "expo-media-library"; 6 | 7 | // icons 8 | import { Feather } from "@expo/vector-icons"; 9 | 10 | // utils 11 | import { successMessage } from "../utils/notification"; 12 | 13 | interface CardProps { 14 | data: any; 15 | } 16 | 17 | interface CardImageProps { 18 | image: string; 19 | } 20 | 21 | interface CardVideoProps { 22 | video_img: string; 23 | video_url: string; 24 | } 25 | 26 | const randomNumber = (): number => { 27 | const date = new Date(); 28 | return date.getTime(); 29 | }; 30 | 31 | const downloadImage = async (url: string) => { 32 | let mediaPermission = await MediaLibrary.requestPermissionsAsync(); 33 | mediaPermission = await MediaLibrary.getPermissionsAsync(); 34 | 35 | if (mediaPermission.status === "granted") { 36 | const fileName = "isave-" + randomNumber() + ".jpg"; 37 | FileSystem.downloadAsync(url, FileSystem.documentDirectory + fileName) 38 | .then(async ({ uri }) => { 39 | await MediaLibrary.saveToLibraryAsync(uri); 40 | successMessage("Image saved to gallery"); 41 | await FileSystem.deleteAsync(uri); 42 | }) 43 | .catch((error) => { 44 | console.error(error); 45 | }); 46 | } else { 47 | alert("Required permission in order to download"); 48 | } 49 | }; 50 | 51 | const downloadVideo = async (url: string) => { 52 | let mediaPermission = await MediaLibrary.requestPermissionsAsync(); 53 | mediaPermission = await MediaLibrary.getPermissionsAsync(); 54 | 55 | if (mediaPermission.status === "granted") { 56 | const fileName = "isave-" + randomNumber() + ".mp4"; 57 | FileSystem.downloadAsync(url, FileSystem.documentDirectory + fileName) 58 | .then(async ({ uri }) => { 59 | await MediaLibrary.saveToLibraryAsync(uri); 60 | successMessage("Video saved to gallery"); 61 | await FileSystem.deleteAsync(uri); 62 | }) 63 | .catch((error) => { 64 | console.error(error); 65 | }); 66 | } else { 67 | alert("Required permission in order to download"); 68 | } 69 | }; 70 | 71 | const Card: FC = ({ data }) => { 72 | if (data.type === "image") { 73 | return ; 74 | } else if (data.type === "video") { 75 | return ; 76 | } else if (data.type === "slide") { 77 | return data.links.map((d: any, index: number) => 78 | d.type === "image" ? ( 79 | 80 | ) : ( 81 | 82 | ) 83 | ); 84 | } 85 | 86 | return null; 87 | }; 88 | 89 | const CardImage: FC = ({ image }) => { 90 | return ( 91 | 92 | 93 | 94 | 95 | 96 | 103 | 104 | 112 | 113 | ); 114 | }; 115 | 116 | const CardVideo: FC = ({ video_img, video_url }) => { 117 | return ( 118 | 119 | 120 | 121 | 122 | 123 | 124 | 131 | 132 | 139 | 140 | 141 | ); 142 | }; 143 | 144 | const styles = StyleSheet.create({ 145 | surface: { 146 | elevation: 3, 147 | padding: 8, 148 | borderRadius: 10, 149 | marginBottom: 20, 150 | width: "100%", 151 | backgroundColor: "#fff", 152 | }, 153 | logo: { 154 | marginLeft: "auto", 155 | }, 156 | imageContainer: { 157 | marginVertical: 5, 158 | }, 159 | image: { 160 | flex: 1, 161 | height: 300, 162 | }, 163 | }); 164 | 165 | export default Card; 166 | -------------------------------------------------------------------------------- /src/screens/profile.tsx: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import React, { FC, useState } from "react"; 3 | import { 4 | StyleSheet, 5 | View, 6 | Text, 7 | ScrollView, 8 | Pressable, 9 | Dimensions, 10 | TextInput, 11 | } from "react-native"; 12 | import { Avatar, Button, Surface } from "react-native-paper"; 13 | import * as FileSystem from "expo-file-system"; 14 | import * as MediaLibrary from "expo-media-library"; 15 | import { StatusBar } from "expo-status-bar"; 16 | import { Feather } from "@expo/vector-icons"; 17 | 18 | // components 19 | import Info from "../components/info"; 20 | import ImageViewer from "../components/imageViewer"; 21 | 22 | // utils 23 | import { errorMessage, successMessage } from "../utils/notification"; 24 | 25 | // lib 26 | import { getClipboardData } from "../lib/clipboard"; 27 | 28 | const randomNumber = (): number => { 29 | const date = new Date(); 30 | return date.getTime(); 31 | }; 32 | 33 | const downloadImage = async (url: string) => { 34 | let mediaPermission = await MediaLibrary.requestPermissionsAsync(); 35 | mediaPermission = await MediaLibrary.getPermissionsAsync(); 36 | 37 | if (mediaPermission.status === "granted") { 38 | const fileName = "isave-profile-" + randomNumber() + ".jpg"; 39 | FileSystem.downloadAsync(url, FileSystem.documentDirectory + fileName) 40 | .then(async ({ uri }) => { 41 | await MediaLibrary.saveToLibraryAsync(uri); 42 | successMessage("Profile image saved to gallery"); 43 | await FileSystem.deleteAsync(uri); 44 | }) 45 | .catch((error) => { 46 | console.error(error); 47 | }); 48 | } else { 49 | alert("Required permission in order to download"); 50 | } 51 | }; 52 | 53 | interface DATAProps { 54 | profile_image: string; 55 | followers: string; 56 | following: string; 57 | name: string; 58 | username: string; 59 | } 60 | 61 | const { width } = Dimensions.get("screen"); 62 | 63 | const Profile: FC = () => { 64 | const [text, setText] = useState(""); 65 | const [prevText, setPrevText] = useState(""); 66 | const [DATA, setData] = useState(); 67 | const [loading, setLoading] = useState(false); 68 | const [imageVisible, setImageVisible] = useState(false); 69 | const [showClearInputBtn, setShowClearInputBtn] = useState(false); 70 | 71 | const similarUsernameCheck = (): boolean => { 72 | if (text === prevText) { 73 | return false; 74 | } 75 | 76 | return true; 77 | }; 78 | 79 | const isUrl = (): string => { 80 | const profile_url = new RegExp( 81 | "(https?://(?:www.)?instagram.com/([^/?#&]+)).*" 82 | ); 83 | 84 | if (text.match(profile_url)) { 85 | const s = text.split("/")[3]; 86 | return s.split("?")[0]; 87 | } 88 | 89 | return text; 90 | }; 91 | 92 | const fetchApi = async () => { 93 | if (text && similarUsernameCheck()) { 94 | setLoading(true); 95 | try { 96 | const send = isUrl(); 97 | const { data } = await axios.post("/profile", { 98 | username: send, 99 | }); 100 | setPrevText(text); 101 | setData(data); 102 | } catch (err) { 103 | setPrevText(""); 104 | errorMessage("No user found!"); 105 | } 106 | setLoading(false); 107 | } 108 | }; 109 | 110 | const closeImage = () => { 111 | setImageVisible(false); 112 | }; 113 | 114 | const openImage = () => { 115 | setImageVisible(true); 116 | }; 117 | 118 | const input = (text: string) => { 119 | setText(text); 120 | 121 | if (text.length > 0) setShowClearInputBtn(true); 122 | else setShowClearInputBtn(false); 123 | }; 124 | 125 | const setClipboard = async () => { 126 | const res = await getClipboardData(); 127 | setText(res); 128 | setShowClearInputBtn(true); 129 | }; 130 | 131 | return ( 132 | <> 133 | 134 | 135 | 136 | 145 | {showClearInputBtn ? ( 146 | { 148 | setText(""); 149 | setShowClearInputBtn(false); 150 | }} 151 | style={{ marginLeft: 5 }} 152 | > 153 | 154 | 155 | ) : ( 156 | 157 | 158 | 159 | )} 160 | 161 | 170 | 171 | {DATA ? ( 172 | <> 173 | 174 | 175 | 182 | 183 | 187 | 188 | 189 | 190 | {DATA.username} 191 | 192 | 193 | Name :{" "} 194 | {DATA.name 195 | ? DATA.name.length > 20 196 | ? DATA.name.slice(0, 20) + "..." 197 | : DATA.name 198 | : "N/A"} 199 | 200 | 201 | Followers : {DATA.followers} 202 | 203 | 204 | Following : {DATA.following} 205 | 206 | 207 | 208 | 216 | 217 | 218 | 223 | 224 | ) : ( 225 | 226 | )} 227 | 228 |