From 1ed6752ebc3d64f578a2d326d8bd83dcb90afd3c Mon Sep 17 00:00:00 2001 From: kalashshah <202051096@iiitvadodara.ac.in> Date: Fri, 1 Dec 2023 16:39:11 +0530 Subject: [PATCH] feat: support new markdown in notifs and update feed/spam fns --- src/components/labels/StylishLabel.js | 136 ++++- src/components/loaders/EPNSActivity.js | 8 +- src/components/ui/FeedItem.js | 465 ---------------- src/components/ui/FeedItemWrapper.js | 341 ------------ src/components/ui/FeedsDisplayer.js | 457 ---------------- src/components/ui/HomeFeed.js | 81 ++- src/components/ui/NotificationItem.tsx | 411 ++++++++++++++ src/components/ui/SpamFeed.js | 186 ++++--- .../ui/testFeed/FeedItemComponents.js | 513 ------------------ .../ui/testFeed/FeedItemWrapperComponent.js | 343 ------------ .../ui/testFeed/FeedsDisplayerComponent.js | 208 ------- src/helpers/MediaHelper.ts | 87 +++ src/helpers/useDecrypt.ts | 65 +++ src/jsons/SampleFeed.js | 244 --------- src/navigation/screens/SampleFeedScreen.js | 95 ---- .../chats/helpers/userChatLoaderHelper.ts | 10 +- 16 files changed, 837 insertions(+), 2813 deletions(-) delete mode 100644 src/components/ui/FeedItem.js delete mode 100644 src/components/ui/FeedItemWrapper.js delete mode 100644 src/components/ui/FeedsDisplayer.js create mode 100644 src/components/ui/NotificationItem.tsx delete mode 100644 src/components/ui/testFeed/FeedItemComponents.js delete mode 100644 src/components/ui/testFeed/FeedItemWrapperComponent.js delete mode 100644 src/components/ui/testFeed/FeedsDisplayerComponent.js create mode 100644 src/helpers/MediaHelper.ts create mode 100644 src/helpers/useDecrypt.ts delete mode 100644 src/jsons/SampleFeed.js delete mode 100644 src/navigation/screens/SampleFeedScreen.js diff --git a/src/components/labels/StylishLabel.js b/src/components/labels/StylishLabel.js index 3dd085ee2..22680bc4f 100644 --- a/src/components/labels/StylishLabel.js +++ b/src/components/labels/StylishLabel.js @@ -80,6 +80,97 @@ export default class CalendarEvents extends Component { Linking.openURL(matchingString); } + newLineStyles() { + return '\n'; + } + + renderTextStyles(matchingString) { + const pattern = + /(.*?)<\/span>/i; + const match = matchingString.match(pattern); + + if (match) { + const colorName = match[1].toLowerCase(); + let color; + switch (colorName) { + case 'primary': + color = GLOBALS.COLORS.PRIMARY; + break; + case 'secondary': + color = GLOBALS.COLORS.GRADIENT_SECONDARY; + break; + case 'white': + color = GLOBALS.COLORS.WHITE; + break; + // can add more custom color names if needed, couldn't find the tertiary color + default: + color = colorName; + } + let textContent = match[2]; + return {textContent}; + } + + return matchingString; + } + + renderLinkWithColor(matchingString) { + const pattern = + /(.*?)<\/PUSHText>/i; + const linkPattern = /\[([^\]]+)]\((https?:\/\/[^)]+)/; + const match = matchingString.match(pattern); + const markdownLinkPattern = matchingString.match(linkPattern); + + const tryLink = url => { + Linking.canOpenURL(url).then(supported => { + if (supported) Linking.openURL(url); + else console.log("Don't know how to open URI: " + url); + }); + }; + + if (match) { + const colorName = match[1].toLowerCase(); + let color; + // Map custom color names to specific values + switch (colorName) { + case 'primary': + color = GLOBALS.COLORS.PRIMARY; + break; + case 'secondary': + color = GLOBALS.COLORS.GRADIENT_SECONDARY; + break; + case 'tertiary': + color = GLOBALS.COLORS.GRADIENT_THIRD; + break; + case 'white': + color = GLOBALS.COLORS.WHITE; + break; + // Add more custom color names if needed + default: + color = colorName; + } + + const link = match[2]; + let textContent = match[3]; + return ( + tryLink(link)}> + {textContent} + + ); + } else if (markdownLinkPattern) { + const linkText = markdownLinkPattern[1]; + const linkUrl = markdownLinkPattern[2]; + return ( + tryLink(linkUrl)} + style={{color: GLOBALS.COLORS.PINK, flex: 0}}> + {linkText} + + ); + } + + return matchingString; + } + // RENDER render() { const {style, title, fontSize, textStyle} = this.props; @@ -94,6 +185,11 @@ export default class CalendarEvents extends Component { style: [styles.link, styles.underline], onPress: this.handleEmailPress, }, + { + pattern: /\[([^\]]+)]\((https?:\/\/[^)]+)\)/g, + style: {}, + renderText: this.renderLinkWithColor, + }, { pattern: /\[(u):([^\]]+)\]/i, // url style: [styles.primary, styles.bold, styles.italics, styles.underline], @@ -129,6 +225,12 @@ export default class CalendarEvents extends Component { onPress: this.handleUrlPress, renderText: this.renderThreeStyles, }, + { + pattern: + /(.*?)<\/span>/gi, + style: {}, // we can add aditional styles here if needed + renderText: this.renderTextStyles, + }, { pattern: /\[(d):([^\]]+)\]/i, // default or primary gradient color style: [styles.primary, styles.bold], @@ -149,20 +251,43 @@ export default class CalendarEvents extends Component { style: [styles.error, styles.bold], renderText: this.renderStyles, }, + { + pattern: /\[(bi):([^\]]+)\]/i, // bolditalics + style: [styles.bold, styles.italics], + renderText: this.renderStyles, + }, + { + pattern: /\*\*\*(.*?)\*\*\*/g, // bolditalics ***text*** + style: { + ...styles.bold, + ...styles.italics, + }, + renderText: matchingString => + matchingString.replace(/\*\*\*(.*?)\*\*\*/g, '$1'), + }, { pattern: /\[(b):([^\]]+)\]/i, // bold style: styles.bold, renderText: this.renderStyles, }, + { + pattern: /\*\*(.*?)\*\*/g, // bold **text** + style: styles.bold, + renderText: matchingString => + matchingString.replace(/\*\*(.*?)\*\*/g, '$1'), + }, { pattern: /\[(i):([^\]]+)\]/i, // italics style: styles.italics, renderText: this.renderStyles, }, { - pattern: /\[(bi):([^\]]+)\]/i, // bolditalics - style: [styles.bold, styles.italics], - renderText: this.renderStyles, + pattern: /\*(.*?)\*/g, // italic *some text* + style: { + ...styles.italics, + }, + renderText: matchingString => + matchingString.replace(/\*(.*?)\*/g, '$1'), }, { pattern: /\[(w):([^\]]+)\]/i, // white @@ -194,6 +319,11 @@ export default class CalendarEvents extends Component { style: [styles.link, styles.underline], onPress: this.handelUrlPress, }, + { + pattern: /\\n/g, + style: {}, + renderText: this.newLineStyles, + }, ]; if (Platform.OS === 'ios') { diff --git a/src/components/loaders/EPNSActivity.js b/src/components/loaders/EPNSActivity.js index d4498533f..ce99b1bde 100644 --- a/src/components/loaders/EPNSActivity.js +++ b/src/components/loaders/EPNSActivity.js @@ -4,7 +4,7 @@ import React from 'react'; import {ActivityIndicator, Platform, StyleSheet, View} from 'react-native'; import GLOBALS from 'src/Globals'; -const EPNSActivity = ({style, size, color}) => { +const EPNSActivity = ({style, size, color = GLOBALS.COLORS.GRADIENT_THIRD}) => { return ( { size === 'small' ? styles.small : styles.big, ]}> {Platform.OS == 'android' || color ? ( - + ) : ( { - const item = this.props.item; - - let sub = !item['asub'] || item['asub'] === '' ? null : item['asub']; - let msg = !item['amsg'] || item['amsg'] === '' ? null : item['amsg']; - let cta = !item['acta'] || item['acta'] === '' ? null : item['acta']; - let img = !item['aimg'] || item['aimg'] === '' ? null : item['aimg']; - - if (item['type'] == 1 || item['type'] == 3) { - // all clear, plain message types - let showTimestamp = false; - const matches = msg.match(/\[timestamp:(.*?)\]/); - if (matches) { - showTimestamp = matches[1]; - msg = msg.replace(/ *\[timestamp:[^)]*\] */g, ''); - } - - this.setState({ - sub: sub, - msg: msg, - cta: cta, - img: img, - timestamp: showTimestamp, - - type: item['type'], - - loading: false, - }); - } - - if (item['type'] == 2 || item['type'] == -2) { - const privateKey = this.props.privateKey; - - if (privateKey && privateKey !== GLOBALS.CONSTANTS.NULL_EXCEPTION) { - // Private key present, else display action banner as it's a wallet sign in - // decrypt the message - const secret = await CryptoHelper.decryptWithECIES( - item['secret'], - privateKey, - ); - // console.log("SECR:" + secret); - - if (sub) { - sub = CryptoHelper.decryptWithAES(sub, secret); - } - - if (msg) { - msg = CryptoHelper.decryptWithAES(msg, secret); - } - - if (cta) { - cta = CryptoHelper.decryptWithAES(cta, secret); - } - - if (img) { - img = CryptoHelper.decryptWithAES(img, secret); - } - } - - let showTimestamp = false; - const matches = msg.match(/\[timestamp:(.*?)\]/); - if (matches) { - showTimestamp = matches[1]; - msg = msg.replace(/ *\[timestamp:[^)]*\] */g, ''); - } - - this.setState({ - sub: sub, - msg: msg, - cta: cta, - img: img, - timestamp: showTimestamp, - - type: item['type'], - - loading: false, - }); - } - }; - - // For on Press - onPress = (url, showToast) => { - if (this.validURL(url) || 1) { - // Bypassing the check so that custom app domains can be opened - Linking.canOpenURL(url).then(supported => { - if (supported) { - Linking.openURL(url); - } else { - showToast( - 'Device Not Supported', - 'ios-link', - ToasterOptions.TYPE.GRADIENT_PRIMARY, - ); - } - }); - } else { - showToast( - 'Link not valid', - 'ios-link', - ToasterOptions.TYPE.GRADIENT_PRIMARY, - ); - } - }; - - // to check valid url - validURL = str => { - var pattern = new RegExp( - '^(https?:\\/\\/)?' + // protocol - '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name - '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address - '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path - '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string - '(\\#[-a-z\\d_]*)?$', - 'i', - ); // fragment locator - return !!pattern.test(str); - }; - - // RENDER - render() { - const {style, item, showToast, onImagePreview, privateKey} = this.props; - - //console.log(item); - - // Do stuff with contants like internal bot, app meta info, etc - let internalBot = false; - if (item['appbot'] == 1) { - internalBot = true; - } - - let iconURL = item['icon']; - if (internalBot) { - iconURL = require('assets/ui/epnsbot.png'); - } - - // Also add secret icon if message type is 2 - let addSecretIcon = false; - if (item['type'] == 2 || item['type'] == -2) { - addSecretIcon = true; - } - - // CTA can be determined for the view since even encrypted, it will have some string - let ctaBorderEnabled = true; - let cta = item['acta']; - - if (!cta || cta === '') { - ctaBorderEnabled = false; - } - - let ctaEnabled = false; - if (this.state.cta) { - ctaEnabled = true; - } - - // Finally mark if the device is a tablet or a phone - let contentInnerStyle = {}; - let contentImgStyle = {}; - let contentMsgImgStyle = {}; - let contentVidStyle = {}; - let contentMsgVidStyle = {}; - - let contentBodyStyle = {}; - let containMode = 'contain'; - if (Utilities.instance.getDeviceType() == Device.DeviceType.TABLET) { - // Change the style to better suit tablet - - contentInnerStyle = { - flexDirection: 'row', - alignItems: 'center', - }; - - contentImgStyle = { - width: '25%', - aspectRatio: 1, - }; - - contentMsgImgStyle = { - margin: 20, - marginRight: 5, - borderRadius: 10, - borderWidth: 0, - }; - - contentBodyStyle = { - flex: 1, - }; - - containMode = 'cover'; - } - - return ( - this.onPress(this.state.cta, showToast)} - disabled={!ctaEnabled}> - {ctaBorderEnabled ? ( - - ) : ( - - )} - - - - this.onPress(item['url'], showToast)} - disabled={!item['url'] || item['url'] === '' ? true : false}> - - - {item['app']} - - - - {addSecretIcon == false ? null : ( - - - - )} - - - - {this.state.loading ? ( - - ) : ( - - {!this.state.img ? null : DownloadHelper.isMediaSupportedVideo( - this.state.img, - ) ? ( - - - - ) : ( - - { - onImagePreview(fileURL); - }} - /> - - )} - - - {!this.state.sub ? null : ( - {this.state.sub} - )} - - - - {!this.state.timestamp ? null : ( - - - {moment - .utc(parseInt(this.state.timestamp) * 1000) - .local() - .format('DD MMM YYYY | hh:mm A')} - - - )} - - - )} - - - - ); - } -} - -// Styling -const styles = StyleSheet.create({ - container: { - width: '100%', - marginVertical: 15, - }, - cover: { - position: 'absolute', - ...StyleSheet.absoluteFill, - justifyContent: 'center', - flex: 1, - borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS, - }, - coverPlain: { - backgroundColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - inner: { - margin: 1, - overflow: 'hidden', - borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS, - }, - header: { - width: '100%', - paddingVertical: 7, - paddingHorizontal: 10, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - borderBottomWidth: 1, - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - appInfo: { - flex: 1, - alignItems: 'center', - backgroundColor: 'red', - }, - appLink: { - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center', - }, - appicon: { - flex: 0, - justifyContent: 'center', - alignItems: 'center', - borderRadius: 6, - height: 24, - aspectRatio: 1, - marginRight: 5, - overflow: 'hidden', - backgroundColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - apptext: { - marginRight: 10, - marginLeft: 5, - fontSize: 12, - color: GLOBALS.COLORS.MID_BLACK_TRANS, - fontWeight: '300', - }, - appsecret: { - width: 16, - height: 16, - borderRadius: 16, - }, - content: { - backgroundColor: GLOBALS.COLORS.WHITE, - }, - contentLoader: { - margin: 20, - }, - contentVid: { - width: '100%', - }, - msgVid: { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - borderBottomWidth: 1, - }, - contentImg: { - width: '100%', - aspectRatio: 2, - }, - msgImg: { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - borderBottomWidth: 1, - resizeMode: 'contain', - }, - contentBody: { - paddingHorizontal: 15, - }, - msgSub: { - fontSize: 16, - fontWeight: '300', - color: GLOBALS.COLORS.MID_BLACK_TRANS, - paddingVertical: 10, - }, - msg: { - paddingTop: 5, - paddingBottom: 20, - }, - timestampOuter: { - display: 'flex', - justifyContent: 'center', - alignSelf: 'flex-end', - paddingVertical: 5, - paddingHorizontal: 12, - marginRight: -20, - borderTopLeftRadius: 5, - borderTopWidth: 1, - borderLeftWidth: 1, - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - overflow: 'hidden', - - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - }, - timestamp: { - fontWeight: '300', - fontSize: 12, - - color: GLOBALS.COLORS.MID_BLACK_TRANS, - }, -}); diff --git a/src/components/ui/FeedItemWrapper.js b/src/components/ui/FeedItemWrapper.js deleted file mode 100644 index 937d5f705..000000000 --- a/src/components/ui/FeedItemWrapper.js +++ /dev/null @@ -1,341 +0,0 @@ -import React, {Component} from 'react'; -import { - ActivityIndicator, - Animated, - Easing, - Image, - StyleSheet, - Text, - TouchableWithoutFeedback, - View, -} from 'react-native'; -import Swipeable from 'react-native-gesture-handler/Swipeable'; -import GLOBALS from 'src/Globals'; -import {ToasterOptions} from 'src/components/indicators/Toaster'; -import EPNSActivity from 'src/components/loaders/EPNSActivity'; -import FeedItem from 'src/components/ui/FeedItem'; -import FeedDBHelper from 'src/helpers/FeedDBHelper'; - -export default class FeedItemWrapper extends Component { - // CONSTRUCTOR - constructor(props) { - super(props); - - this.state = { - deleting: false, - scale: new Animated.Value(100), - height: null, - adjustedH: 0, - collapsedH: null, - initialized: false, - - collapsing: false, - undo: false, - }; - } - - // COMPONENT MOUNTED - componentDidMount() {} - - // COMPONENT UPDATED - componentDidUpdate(prevProps) {} - - // LAYOUT CHANGE - findDimensions = layout => { - const {height} = layout; - - if (this.state.adjustedH < height && this.state.initialized == false) { - this.setState( - { - adjustedH: height, - height: new Animated.Value(0), - collapsedH: new Animated.Value(0), - initialized: true, - }, - () => { - Animated.timing(this.state.height, { - toValue: height, - easing: Easing.easeInOut, - duration: 250, - useNativeDriver: false, // No support for height: ; - }).start(); - }, - ); - } - }; - - // Functions - onSwipeableRightWillOpen = () => { - this.setState({ - deleting: true, - }); - }; - - onSwipeableRightOpened = async (item, nid, itemArchivedFunc, showToast) => { - let deleteObj = {}; - - const db = FeedDBHelper.getDB(); - - FeedDBHelper.hideFeedItem(db, item['nid']) - .then(() => { - this.animateHeightCollapse(nid, itemArchivedFunc); - }) - .catch(err => { - // Perform Event Edited Callback - this.refs.SwipeRight.close(); - - // Show Toast - this.props.showToast( - 'Error Archiving Notification', - '', - ToasterOptions.TYPE.GRADIENT_PRIMARY, - ); - // console.log(err); - }); - }; - - onSwipeableClose = () => { - if (this.state.undo == true) { - this.setState({ - undo: false, - collapsing: false, - deleting: false, - }); - } - }; - - // Animated Height Collapse - animateHeightCollapse = (nid, itemArchivedFunc) => { - this.setState( - { - collapsing: true, - }, - () => { - Animated.timing(this.state.height, { - toValue: 0, - easing: Easing.easeInOut, - duration: 250, - // useNativeDriver: true, // No support for height - }).start(() => { - // Perform Event Edited Callback - if (itemArchivedFunc) { - itemArchivedFunc(nid); - } - }); - }, - ); - }; - - // To uncollapse - uncollapseHeight = () => { - this.setState( - { - undo: true, - }, - () => { - Animated.timing(this.state.height, { - toValue: this.state.adjustedH, - easing: Easing.easeInOut, - duration: 250, - // useNativeDriver: true, // No support for height - }).start(() => { - this.refs.SwipeRight.close(); - }); - }, - ); - }; - - // Render Right Sliding Action - renderRightActions = (progress, dragX) => { - const scaleIcon = dragX.interpolate({ - inputRange: [-200, 0], - outputRange: [1, 0.4], - extrapolate: 'clamp', - }); - // - // const transXIcon = dragX.interpolate({ - // inputRange: [0, 50, 100, 101], - // outputRange: [5, 0, 0, 1], - // }); - - let scale = 0; - - if (this.state.height) { - scale = this.state.height.interpolate({ - inputRange: [0, this.state.adjustedH], - outputRange: [0, 1], - extrapolate: 'clamp', - }); - } - - return ( - - {this.state.deleting ? ( - - - - ) : ( - - - - )} - - ); - }; - - // RENDER - render() { - const { - style, - item, - nid, - itemArchived, - showToast, - onImagePreview, - privateKey, - } = this.props; - - let scale = 0; - let translateY = 0; - let fade = 0; - let height = undefined; - - if (item['hidden'] == 1) { - height = 0; - fade = 0; - } - - if (this.state.height) { - scale = this.state.height.interpolate({ - inputRange: [0, this.state.adjustedH], - outputRange: [0.6, 1], - extrapolate: 'clamp', - }); - - translateY = this.state.height.interpolate({ - inputRange: [0.9, this.state.adjustedH], - outputRange: [-this.state.adjustedH * 0.75, 0], - extrapolate: 'clamp', - }); - - fade = this.state.height.interpolate({ - inputRange: [0, this.state.adjustedH / 2, this.state.adjustedH], - outputRange: [0, 0.1, 1], - extrapolate: 'clamp', - }); - } - - if (this.state.collapsing) { - height = this.state.height; - } - - return ( - - this.onSwipeableRightOpened(item, nid, itemArchived, showToast) - } - onSwipeableClose={this.onSwipeableClose}> - { - this.findDimensions(event.nativeEvent.layout); - }}> - - - - ); - } -} - -const styles = StyleSheet.create({ - swipeContainer: {}, - container: { - marginHorizontal: 20, - alignItems: 'center', - shadowColor: GLOBALS.COLORS.BLACK, - shadowOffset: { - width: 0, - height: 4, - }, - shadowOpacity: 0.1, - shadowRadius: 6, - - elevation: 4, - }, - primaySegment: { - flex: 1, - }, - actionView: { - flex: 1, - width: '100%', - justifyContent: 'center', - }, - actionContent: { - flex: 1, - alignSelf: 'flex-end', - justifyContent: 'center', - marginRight: 30, - }, - actionImage: { - width: 30, - resizeMode: 'contain', - }, - actionContentAfter: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - }, - actionActivity: {}, - actionText: { - color: GLOBALS.COLORS.WHITE, - fontSize: 10, - fontWeight: 'bold', - textAlign: 'center', - }, -}); diff --git a/src/components/ui/FeedsDisplayer.js b/src/components/ui/FeedsDisplayer.js deleted file mode 100644 index ef49d2f65..000000000 --- a/src/components/ui/FeedsDisplayer.js +++ /dev/null @@ -1,457 +0,0 @@ -import {Asset} from 'expo-asset'; -import React, {Component} from 'react'; -import { - FlatList, - Image, - RefreshControl, - StyleSheet, - Text, - View, -} from 'react-native'; -import ImageView from 'react-native-image-viewing'; -import SafeAreaView from 'react-native-safe-area-view'; -import GLOBALS from 'src/Globals'; -import {ToasterOptions} from 'src/components/indicators/Toaster'; -import StylishLabel from 'src/components/labels/StylishLabel'; -import EPNSActivity from 'src/components/loaders/EPNSActivity'; -import FeedItemWrapper from 'src/components/ui/FeedItemWrapper'; -import ImagePreviewFooter from 'src/components/ui/ImagePreviewFooter'; -import FeedDBHelper from 'src/helpers/FeedDBHelper'; -import MetaStorage from 'src/singletons/MetaStorage'; - -export default class FeedsDisplayer extends Component { - // CONSTRUCTOR - constructor(props) { - super(props); - - this.state = { - items: [], - - forwardPointer: 0, - forwardNid: -1, - backwardPointer: 0, - backwardNid: -1, - visibleItemCount: 0, - feedEnded: false, - feedQueried: false, - - feedIsRefreshing: false, - - loadedImages: [], - renderGallery: false, - startFromIndex: 0, - - lastHiddenItemNid: -1, - }; - - this._db = null; - this.itemRefs = []; - } - - // COMPONENT MOUNTED - async componentDidMount() { - // Connect to Feed DB Helper - this._db = FeedDBHelper.getDB(); - } - - async omponentWillUnmount() { - this._db = null; - } - - // FUNCTIONS - // to reset the feed and refresh - resetFeedState = () => { - this.setState( - { - items: [], - forwardPointer: 0, - forwardNid: -1, - backwardPointer: 0, - backwardNid: -1, - visibleItemCount: 0, - feedEnded: false, - feedQueried: false, - - feedIsRefreshing: false, - }, - () => { - this.itemRefs = []; - - this.triggerGetItemsFromDB(); - }, - ); - }; - - // trigger getting feed items - triggerGetItemsFromDB = async isHistorical => { - await this.setState({ - feedIsRefreshing: true, - }); - - const result = await this.getItemsFromDB(isHistorical); - return result; - }; - - // To pull more feeds and store them in the feed items - getItemsFromDB = async isHistorical => { - // Wait for some time - await this.performTimeConsumingTask(); - - let fromPointer = !isHistorical - ? this.state.forwardPointer - : this.state.backwardPointer; - - let limit = GLOBALS.CONSTANTS.FEED_ITEMS_TO_PULL; - - // console.log("getting Items: " + fromPointer + "| Limit: " + limit); - - const newBadge = await MetaStorage.instance.getBadgeCount(); - const prevBadge = await MetaStorage.instance.getPreviousBadgeCount(); - const diff = newBadge - prevBadge; - - if (diff > limit) { - limit = diff; - } - - const fetcheditems = await FeedDBHelper.getFeeds( - this._db, - fromPointer, - limit, - isHistorical, - ); - let storedFeed = this.state.items; - - let visibleItemCount = this.state.visibleItemCount; - let totalCount = 0; - let forwardNid = this.state.forwardNid; - let backwardNid = this.state.backwardNid; - - const fNid = this.state.forwardNid; - const bNid = this.state.backwardNid; - const feedQueried = this.state.feedQueried; - - fetcheditems.forEach(function (item, index) { - let itemValid = true; - - if (isHistorical) { - // Find a way for backward nid to not start from 0, it loads, should work since - // data is populated with forward nid first - if (bNid >= item['nid'] || bNid == -1) { - storedFeed = [item, ...storedFeed]; - } else { - itemValid = false; - } - } else { - if (fNid < item['nid'] || fNid == -1) { - storedFeed = feedQueried - ? [item, ...storedFeed] - : [...storedFeed, item]; - } else { - itemValid = false; - } - } - - if (totalCount == 0 && itemValid) { - forwardNid = item['nid']; - } - backwardNid = item['nid']; - - if (item['hidden'] != 1) { - visibleItemCount = visibleItemCount + 1; - } - - if (itemValid) { - totalCount = totalCount + 1; - } - }); - - const newForwardPointer = 0; // Since this is reverse, it will not affect the forward pointer - //const newForwardPointer = !isHistorical ? this.state.forwardPointer + totalCount : this.state.forwardPointer; - - const newBackwardPointer = this.state.backwardPointer + totalCount; - // console.log("ForwardPointer: " + newForwardPointer); - // console.log("Forward NID: " + forwardNid); - // console.log("BackwardPointer: " + newBackwardPointer); - // console.log("Backward NID: " + backwardNid); - // console.log("limit: " + limit); - // console.log("Fetched Items: " + fetcheditems); - // console.log("is Historical: " + isHistorical); - // console.log("Visible Count: " + visibleItemCount); - - this.setState({ - items: storedFeed, - visibleItemCount: visibleItemCount, - feedIsRefreshing: false, - feedQueried: true, - feedEnded: fetcheditems ? false : true, - - forwardPointer: newForwardPointer, - forwardNid: forwardNid, - - backwardPointer: newBackwardPointer, - backwardNid: backwardNid, - }); - - // Feeds pulled after logic - if (!isHistorical) { - await MetaStorage.instance.setCurrentAndPreviousBadgeCount(0, 0); - - // Check and move feed to top as well - this.refs.feedScroll.scrollToOffset({animated: true, offset: 0}); - } else { - } - - // Show Toast - if (totalCount == 0) { - // No New Items - this.showToast( - 'No New Notifications', - '', - ToasterOptions.TYPE.GRADIENT_PRIMARY, - ); - } else { - this.showToast( - 'New Notifications Loaded!', - '', - ToasterOptions.TYPE.GRADIENT_PRIMARY, - ); - } - - // Do Feed Refresh callback if it exists - if (this.props.onFeedRefreshed) { - this.props.onFeedRefreshed(); - } - - return true; - }; - - onEndReached = () => { - // console.log("Refreshing"); - - if (!this.state.feedEnded) { - if (!this.state.feedIsRefreshing) { - this.triggerGetItemsFromDB(true); - } - } - - // This is for flat list - // onEndReached={this.onEndReached} - // onEndReachedThreshold={0.5} - }; - - // Perform some task to wait - performTimeConsumingTask = async () => { - return new Promise(resolve => - setTimeout(() => { - resolve('result'); - }, 500), - ); - }; - - // Archive an item - archiveItem = nid => { - this.setState( - { - visibleItemCount: this.state.visibleItemCount - 1, - lastHiddenItemNid: nid, - // items: this.state.items.filter(i => i["nid"] !== nid) // don't remove so it's better after unarchive - }, - () => { - this.showToast( - 'Item Archived, Tap to Undo', - '', - ToasterOptions.TYPE.GRADIENT_PRIMARY, - () => { - this.unarchiveItemSequential(nid); - }, - ToasterOptions.DELAY.LONG, - ); - }, - ); - }; - - // Unarchive an item - unarchiveItemSequential = nid => { - // To trick the tap callback of toast - this.unarchiveItem(nid); - }; - - unarchiveItem = async nid => { - await FeedDBHelper.unhideFeedItem(this._db, nid); - - // No Need to adjust item as items are there but invisible, just adjust visible item count - this.setState({ - visibleItemCount: this.state.visibleItemCount + 1, - }); - - // get ref of that item and expand it - const itemRef = this.getRefForFeedItem(nid); - this.itemRefs[itemRef].uncollapseHeight(); - }; - - // To get ref for feed items - getRefForFeedItem = nid => { - return 'feed' + nid; - }; - - // For showing toast - showToast = (msg, icon, type, tapCB, screenTime) => { - if (this.props.showToast) { - this.props.showToast(msg, icon, type, tapCB, screenTime); - } - }; - - // Show Image Preview - showImagePreview = async fileURL => { - let validPaths = []; - let fileIndex = -1; - - // Add Image - // Download the file if not done already - await Asset.loadAsync(fileURL); - - // Push to valid path - validPaths.push({ - uri: Asset.fromModule(fileURL).uri, - id: fileURL, - }); - - fileIndex = validPaths.length - 1; - - // console.log("LOADED IMAGES:"); - // console.log(validPaths); - - this.setState({ - loadedImages: validPaths, - renderGallery: true, - startFromIndex: fileIndex, - }); - }; - - // Render Footer - renderFooter = () => { - return ; - }; - - // RENDER - render() { - const {style, onFeedRefreshed, showToast, privateKey} = this.props; - - return ( - - - { - this.triggerGetItemsFromDB(); - }} - /> - } - data={this.state.visibleItemCount > 0 ? this.state.items : []} - extraData={this.state} - keyExtractor={item => item['nid'].toString()} - contentContainerStyle={styles.feedScrollContent} - renderItem={({item}) => ( - - (this.itemRefs = { - ...this.itemRefs, - [this.getRefForFeedItem(item['nid'])]: ref, - }) - } - item={item} - nid={item['nid']} - showToast={showToast} - itemArchived={nid => { - this.archiveItem(nid); - }} - onImagePreview={fileURL => this.showImagePreview(fileURL)} - privateKey={privateKey} - /> - )} - ListEmptyComponent={ - this.state.feedQueried == false ? ( - - - - ) : ( - - - - - ) - } - /> - - - { - this.setState({ - renderGallery: false, - }); - }} - FooterComponent={({imageIndex}) => ( - - )} - /> - - ); - } -} - -// Styling -const styles = StyleSheet.create({ - container: { - flex: 1, - width: '100%', - justifyContent: 'center', - alignItems: 'center', - }, - feedScrollContainer: { - width: '100%', - flex: 1, - marginTop: 10, - }, - feedScrollContent: { - flexGrow: 1, - }, - infodisplay: { - flexGrow: 1, - justifyContent: 'center', - alignItems: 'center', - paddingHorizontal: 20, - paddingVertical: 20, - }, - infoIcon: { - height: 48, - resizeMode: 'contain', - margin: 10, - }, - infoText: { - marginVertical: 10, - }, - loading: {}, - noPendingFeeds: {}, - feed: { - width: '100%', - }, -}); diff --git a/src/components/ui/HomeFeed.js b/src/components/ui/HomeFeed.js index 16f98b15a..3da4289ee 100644 --- a/src/components/ui/HomeFeed.js +++ b/src/components/ui/HomeFeed.js @@ -1,4 +1,4 @@ -import {Asset} from 'expo-asset'; +import {PushApi} from '@kalashshah/react-native-sdk/src'; import React, {useEffect, useRef, useState} from 'react'; import { FlatList, @@ -14,12 +14,12 @@ import {ToasterOptions} from 'src/components/indicators/Toaster'; import StylishLabel from 'src/components/labels/StylishLabel'; import EPNSActivity from 'src/components/loaders/EPNSActivity'; import ImagePreviewFooter from 'src/components/ui/ImagePreviewFooter'; -import FeedItemComponent from 'src/components/ui/testFeed/FeedItemComponents.js'; -import ENV_CONFIG from 'src/env.config'; +import envConfig from 'src/env.config'; import AppBadgeHelper from 'src/helpers/AppBadgeHelper'; -import {getCAIPAddress} from 'src/helpers/CAIPHelper'; import {selectCurrentUser, selectUsers} from 'src/redux/authSlice'; +import NotificationItem from './NotificationItem'; + export default function InboxFeed(props) { const users = useSelector(selectUsers); const currentUser = useSelector(selectCurrentUser); @@ -72,50 +72,31 @@ export default function InboxFeed(props) { ); }; - const showImagePreview = async fileURL => { - let validPaths = []; - let fileIndex = -1; - - // Add Image - // Download the file if not done already - await Asset.loadAsync(fileURL); - - // Push to valid path - validPaths.push({ - uri: Asset.fromModule(fileURL).uri, - id: fileURL, - }); - - fileIndex = validPaths.length - 1; - - setLoadedImages(validPaths); - setRenderGallery(true); - setStartFromIndex(fileIndex); - }; - const fetchFeed = async (rewrite, refresh = false) => { if (!endReached || rewrite === true) { if (!loading) { setloading(true); - const apiURL = `${ENV_CONFIG.EPNS_SERVER}/v1/users/${getCAIPAddress( - wallet, - )}/feeds?page=${refresh ? 1 : page}&limit=10&spam=false`; - - const resJson = await fetch(apiURL).then(response => response.json()); - - if (resJson.itemcount !== 0 && resJson.feeds !== []) { - const oldMsg = feed.length > 0 ? feed[0].epoch : ''; - const newMsg = resJson.feeds[0].epoch; + const feeds = await PushApi.user.getFeeds({ + user: wallet, + env: envConfig.ENV, + limit: 10, + spam: false, + page: refresh ? 1 : page, + }); + + if (feeds && feeds.length > 0) { + const oldMsg = feed.length > 0 ? feed[0].sid : ''; + const newMsg = feeds[0].sid; const isMsgNew = oldMsg !== newMsg; // clear the notifs if present AppBadgeHelper.setAppBadgeCount(0); if (rewrite) { - setFeed([...resJson.feeds]); + setFeed([...feeds]); setEndReached(false); } else { - setFeed(prev => [...prev, ...resJson.feeds]); + setFeed(prev => [...prev, ...feeds]); } if (!refresh) { @@ -152,18 +133,28 @@ export default function InboxFeed(props) { item.payload_id.toString()} + keyExtractor={item => item.sid.toString()} initialNumToRender={10} style={{flex: 1}} showsVerticalScrollIndicator={false} - renderItem={({item}) => ( - showImagePreview(fileURL)} - privateKey={props.privateKey} - /> - )} + renderItem={({item}) => { + return ( + + ); + }} onEndReached={async () => (!endReached ? fetchFeed(false) : null)} refreshControl={ Promise; + isSubscribedFn?: () => Promise; + theme?: string | undefined; + chainName: chainNameType; + isSecret?: boolean; + decryptFn?: () => Promise<{ + title: string; + body: string; + cta: string; + image: string; + }>; +}; + +const NotificationItem: React.FC = ({ + notificationTitle, + notificationBody, + cta, + app, + icon, + image, + url, + isSpam, + isSubscribedFn, + subscribeFn, + theme, + chainName, + isSecret, + decryptFn, +}) => { + const {notificationBody: parsedBody, timeStamp} = extractTimeStamp( + notificationBody || '', + ); + + const { + notifTitle, + notifBody, + notifCta, + notifImage, + setDecryptedValues, + isSecretRevealed, + } = useDecrypt({notificationTitle, parsedBody, cta, image}, isSecret); + + const isCtaURLValid = MediaHelper.validURL(notifCta); + const isChannelURLValid = MediaHelper.validURL(url); + + const [subscribeLoading, setSubscribeLoading] = useState(false); + const [isSubscribed, setIsSubscribed] = useState(true); + + const showMetaInfo = isSecret || timeStamp; + + const gotToCTA = () => { + if (!isCtaURLValid || !notifCta) return; + Linking.canOpenURL(notifCta).then(supported => { + if (supported) { + Linking.openURL(notifCta!); + } + }); + }; + + const goToURL = () => { + if (!isChannelURLValid || !url) return; + Linking.canOpenURL(url).then(supported => { + if (supported) { + Linking.openURL(url!); + } + }); + }; + + const onSubscribe = async () => { + if (!subscribeFn) return; + try { + setSubscribeLoading(true); + await subscribeFn(); + setIsSubscribed(true); + } finally { + setSubscribeLoading(false); + } + }; + + const onDecrypt = async () => { + if (decryptFn) { + try { + const decryptedPayload = await decryptFn(); + if (decryptedPayload) { + setDecryptedValues(decryptedPayload); + } + } catch (e) { + console.error(e); + } + } + }; + + const onImagePreview = async (fileURL: string) => { + await Asset.loadAsync(fileURL); + }; + + useEffect(() => { + if (!isSpam || !isSubscribedFn) return; + + isSubscribedFn().then((res: unknown) => { + setIsSubscribed(Boolean(res)); + }); + }, [isSubscribedFn, isSpam]); + + if (isSubscribed && isSpam) return null; + + const ctaBorderEnabled = cta && cta !== '' ? true : false; + + return ( + + {ctaBorderEnabled ? ( + + ) : ( + + )} + + + + + + + {app} + + + + + + + + {!notifImage ? null : DownloadHelper.isMediaSupportedVideo( + notifImage, + ) ? ( + + + + ) : ( + + { + onImagePreview(notifImage); + }} + /> + + )} + + + {!notifTitle ? null : ( + {notifTitle} + )} + + + + {!timeStamp ? null : ( + + + {convertTimeStamp(timeStamp)} + + + )} + + + + + + ); +}; + +// Define default props +NotificationItem.defaultProps = { + notificationTitle: '', + notificationBody: '', + cta: '', + app: '', + image: '', + url: '', + isSpam: false, + theme: 'light', +}; + +// Define StyleSheet +const styles = StyleSheet.create({ + container: { + // width: "100%", + marginVertical: 15, + marginHorizontal: 20, + }, + cover: { + // position: 'absolute', + ...StyleSheet.absoluteFillObject, + justifyContent: 'center', + flex: 1, + borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS, + }, + coverPlain: { + backgroundColor: GLOBALS.COLORS.SLIGHT_GRAY, + }, + inner: { + margin: 1, + overflow: 'hidden', + borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS, + }, + header: { + width: '100%', + paddingVertical: 7, + paddingHorizontal: 10, + backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + borderBottomWidth: 1, + borderColor: GLOBALS.COLORS.SLIGHT_GRAY, + }, + appInfo: { + flex: 1, + alignItems: 'center', + backgroundColor: 'red', + }, + appLink: { + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + }, + appicon: { + flex: 0, + justifyContent: 'center', + alignItems: 'center', + borderRadius: 6, + height: 24, + aspectRatio: 1, + marginRight: 5, + overflow: 'hidden', + backgroundColor: GLOBALS.COLORS.SLIGHT_GRAY, + }, + apptext: { + marginRight: 10, + marginLeft: 5, + fontSize: 12, + color: GLOBALS.COLORS.MID_BLACK_TRANS, + fontWeight: '300', + }, + appsecret: { + width: 16, + height: 16, + borderRadius: 16, + }, + content: { + backgroundColor: GLOBALS.COLORS.WHITE, + }, + contentLoader: { + margin: 20, + }, + contentVid: { + width: '100%', + }, + msgVid: { + borderColor: GLOBALS.COLORS.SLIGHT_GRAY, + backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, + borderBottomWidth: 1, + }, + contentImg: { + width: '100%', + aspectRatio: 2, + }, + msgImg: { + borderColor: GLOBALS.COLORS.SLIGHT_GRAY, + backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, + borderBottomWidth: 1, + resizeMode: 'contain', + }, + contentBody: { + paddingHorizontal: 15, + }, + msgSub: { + fontSize: 16, + fontWeight: '300', + color: GLOBALS.COLORS.MID_BLACK_TRANS, + paddingVertical: 10, + }, + msg: { + paddingTop: 5, + paddingBottom: 20, + }, + timestampOuter: { + display: 'flex', + justifyContent: 'center', + alignSelf: 'flex-end', + paddingVertical: 5, + paddingHorizontal: 12, + marginRight: -20, + borderTopLeftRadius: 5, + borderTopWidth: 1, + borderLeftWidth: 1, + borderColor: GLOBALS.COLORS.SLIGHT_GRAY, + overflow: 'hidden', + + backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, + }, + timestamp: { + fontWeight: '300', + fontSize: 12, + + color: GLOBALS.COLORS.MID_BLACK_TRANS, + }, + link: { + textDecorationLine: 'none', + color: GLOBALS.COLORS.PINK, + }, +}); + +export default NotificationItem; diff --git a/src/components/ui/SpamFeed.js b/src/components/ui/SpamFeed.js index 0e6c39d8e..7e64e4349 100644 --- a/src/components/ui/SpamFeed.js +++ b/src/components/ui/SpamFeed.js @@ -1,3 +1,4 @@ +import {PushApi} from '@kalashshah/react-native-sdk/src'; import {Asset} from 'expo-asset'; import React, {useEffect, useRef, useState} from 'react'; import { @@ -13,11 +14,11 @@ import {useSelector} from 'react-redux'; import StylishLabel from 'src/components/labels/StylishLabel'; import EPNSActivity from 'src/components/loaders/EPNSActivity'; import ImagePreviewFooter from 'src/components/ui/ImagePreviewFooter'; -import FeedItemComponent from 'src/components/ui/testFeed/FeedItemComponents.js'; import ENV_CONFIG from 'src/env.config'; -import {getCAIPAddress} from 'src/helpers/CAIPHelper'; import {selectCurrentUser, selectUsers} from 'src/redux/authSlice'; +import NotificationItem from './NotificationItem'; + export default function SpamFeed(props) { const users = useSelector(selectUsers); const currentUser = useSelector(selectCurrentUser); @@ -85,19 +86,21 @@ export default function SpamFeed(props) { if (!endReached || rewrite === true) { if (!loading) { setloading(true); - const apiURL = `${ENV_CONFIG.EPNS_SERVER}/v1/users/${getCAIPAddress( - wallet, - )}/feeds?page=${page}&limit=10&spam=true`; - - const resJson = await fetch(apiURL).then(response => response.json()); - - if (resJson.itemcount !== 0 && resJson.feeds !== []) { + const feeds = await PushApi.user.getFeeds({ + user: wallet, + env: ENV_CONFIG.ENV, + limit: 10, + page: page, + spam: true, + }); + + if (feeds && feeds.length > 0) { // clear the notifs if present if (rewrite) { - setFeed([...resJson.feeds]); + setFeed([...feeds]); setEndReached(false); } else { - setFeed(prev => [...prev, ...resJson.feeds]); + setFeed(prev => [...prev, ...feeds]); } setPage(prev => prev + 1); setEndReached(true); @@ -109,84 +112,91 @@ export default function SpamFeed(props) { }; return ( - <> - - - item.payload_id.toString()} - initialNumToRender={10} - style={{flex: 1}} - showsVerticalScrollIndicator={false} - renderItem={({item}) => ( - showImagePreview(fileURL)} - privateKey={props.privateKey} - /> - )} - onEndReached={async () => (!endReached ? fetchFeed(false) : null)} - refreshControl={ - { - setInitialized(false); - }} + + + item.sid.toString()} + initialNumToRender={10} + style={{flex: 1}} + showsVerticalScrollIndicator={false} + renderItem={({item}) => { + return ( + - } - ListEmptyComponent={ - refreshing ? ( - - - - ) : ( - - - - - ) - } - ListFooterComponent={() => { - return loading ? ( - - - - ) : null; - }} - /> - - { - setRenderGallery(false); - }} - FooterComponent={({imageIndex}) => ( - - )} - /> - - - + ); + }} + onEndReached={async () => (!endReached ? fetchFeed(false) : null)} + refreshControl={ + { + setInitialized(false); + }} + /> + } + ListEmptyComponent={ + refreshing ? ( + + + + ) : ( + + + + + ) + } + ListFooterComponent={() => { + return loading ? ( + + + + ) : null; + }} + /> + { + setRenderGallery(false); + }} + FooterComponent={({imageIndex}) => ( + + )} + /> + + ); } diff --git a/src/components/ui/testFeed/FeedItemComponents.js b/src/components/ui/testFeed/FeedItemComponents.js deleted file mode 100644 index 217771dd8..000000000 --- a/src/components/ui/testFeed/FeedItemComponents.js +++ /dev/null @@ -1,513 +0,0 @@ -import * as Device from 'expo-device'; -import {LinearGradient} from 'expo-linear-gradient'; -import moment from 'moment'; -import React, {useEffect, useState} from 'react'; -import { - Image, - Linking, - StyleSheet, - Text, - ToastAndroid, - TouchableOpacity, - View, -} from 'react-native'; -import SafeAreaView from 'react-native-safe-area-view'; -import GLOBALS from 'src/Globals'; -import {ToasterOptions} from 'src/components/indicators/Toaster'; -import StylishLabel from 'src/components/labels/StylishLabel'; -import EPNSActivity from 'src/components/loaders/EPNSActivity'; -import VideoDownloadWithIndicator from 'src/components/loaders/VideoDownloadWithIndicator'; -import CryptoHelper from 'src/helpers/CryptoHelper'; -import DownloadHelper from 'src/helpers/DownloadHelper'; -import Utilities from 'src/singletons/Utilities'; - -import ImageDownloadWithIndicator from '../../loaders/ImageDownloadWithIndicator'; - -const FeedItem = props => { - // // CONSTRUCTOR - // constructor(props) { - // super(props); - - // COMPONENT MOUNTED - - useEffect(() => { - // console.log("CALLING"); - compileMessage(); - // console.log("PROPS", props); - }, []); - - const {style, onImagePreview} = props; - - const item = props.item.payload.data; - - // console.log("item--->", props.item.payload.data.icon); - - const [loading, setloading] = useState(false); - const [sub, setSub] = useState(null); - const [msg, setMsg] = useState(null); - const [cta, setCta] = useState(null); - const [img, setImg] = useState(null); - const [timestamp, setTimestamp] = useState(false); - const [type, setType] = useState('1'); - - const [loadingFeed, setLoadingFeed] = useState(props.loading); - - // this.state = { - // loading: true, - // sub: null, - // msg: null, - // cta: null, - // img: null, - // timestamp: false, - // type: 1, - // } - - // } - - const onPress = url => { - if (validURL(url) || 1) { - // console.log("OPENING URL ", url); - // Bypassing the check so that custom app domains can be opened - Linking.canOpenURL(url).then(supported => { - if (supported) { - Linking.openURL(url); - } else { - // showToast("Device Not Supported", "ios-link", ToasterOptions.TYPE.GRADIENT_PRIMARY) - } - }); - } else { - // showToast("Link not valid", "ios-link", ToasterOptions.TYPE.GRADIENT_PRIMARY) - } - }; - - // to check valid url - const validURL = str => { - var pattern = new RegExp( - '^(https?:\\/\\/)?' + // protocol - '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name - '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address - '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path - '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string - '(\\#[-a-z\\d_]*)?$', - 'i', - ); // fragment locator - return !!pattern.test(str); - }; - - // FUNCTIONS - const compileMessage = async () => { - // console.log("CALLED", props.item.payload.data.type); - let _sub = - !props.item.payload.data.asub || props.item.payload.data.asub === '' - ? null - : props.item.payload.data.asub; - let msg1 = - !props.item.payload.data.amsg || props.item.payload.data.amsg === '' - ? null - : props.item.payload.data.amsg; - let _cta = - !props.item.payload.data.acta || props.item.payload.data.acta === '' - ? null - : props.item.payload.data.acta; - let _img = - !props.item.payload.data.aimg || props.item.payload.data.aimg === '' - ? null - : props.item.payload.data.aimg; - - // console.log(typeOf props.item.type); - if ( - props.item.payload.data.type == '1' || - props.item.payload.data.type == '3' - ) { - // all clear, plain message types - - let showTimestamp = false; - const matches = props.item.payload.data.amsg.match(/\[timestamp:(.*?)\]/); - if (matches) { - showTimestamp = matches[1]; - msg1 = msg1.replace(/ *\[timestamp:[^)]*\] */g, ''); - } - setTimestamp(showTimestamp); - setloading(false); - setSub(_sub); - setMsg(msg1); - setCta(_cta); - setImg(_img); - setType(props.item.payload.data.type); - } - - // if ( - // props.item.payload.data.type == 2 || - // props.item.payload.data.type == -2 - // ) { - // const privateKey = props.privateKey; - - // if (privateKey && privateKey !== GLOBALS.CONSTANTS.NULL_EXCEPTION) { - // // Private key present, else display action banner as it's a wallet sign in - // // decrypt the message - // const secret = await CryptoHelper.decryptWithECIES( - // props.item.payload.data.secret, - // privateKey - // ); - // // console.log("SECR:" + secret); - - // if (_sub) { - // _sub = await CryptoHelper.decryptWithAES(_sub, secret); - // } - - // if (msg1) { - // msg1 = await CryptoHelper.decryptWithAES(msg1, secret); - // } - - // if (_cta) { - // _cta = await CryptoHelper.decryptWithAES(_cta, secret); - // } - - // if (_img) { - // _img = await CryptoHelper.decryptWithAES(_img, secret); - // } - // } - - // let showTimestamp = false; - // const matches = msg1.match(/\[timestamp:(.*?)\]/); - // if (matches) { - // showTimestamp = matches[1]; - // msg1 = msg1.replace(/ *\[timestamp:[^)]*\] */g, ""); - // } - - // // this.setState({ - // // sub: sub, - // // msg: msg, - // // cta: cta, - // // img: img, - // // timestamp: showTimestamp, - - // // type: item["type"], - - // // loading: false, - // // }); - // setTimestamp(showTimestamp); - // setloading(false); - // setSub(_sub); - // setMsg(msg1); - // setCta(_cta); - // setImg(_img); - // setType(props.item.payload.data.type); - // } - }; - - // For on Press - - // RENDER - // render() { - // const { - // style, - // item, - // showToast, - // onImagePreview, - // privateKey, - // } = this.props; - - //console.log(item); - - // Do stuff with contants like internal bot, app meta info, etc - let internalBot = false; - - if (props.item.payload.data.appbot == 1) { - internalBot = true; - } - - let iconURL = item.icon; - if (internalBot == 1) { - iconURL = require('assets/ui/epnsbot.png'); - } - - // Also add secret icon if message type is 2 - let addSecretIcon = false; - if (props.item.payload.data.type == 2 || props.item.payload.data.type == -2) { - addSecretIcon = true; - } - - // CTA can be determined for the view since even encrypted, it will have some string - let ctaBorderEnabled = true; - let _cta = item.acta; - - if (!_cta || _cta === '') { - ctaBorderEnabled = false; - } - - let ctaEnabled = false; - if (_cta) { - ctaEnabled = true; - } - - // Finally mark if the device is a tablet or a phone - let contentInnerStyle = {}; - let contentImgStyle = {}; - let contentMsgImgStyle = {}; - let contentVidStyle = {}; - let contentMsgVidStyle = {}; - - let contentBodyStyle = {}; - let containMode = 'contain'; - if (Utilities.instance.getDeviceType() == Device.DeviceType.TABLET) { - // Change the style to better suit tablet - - contentInnerStyle = { - flexDirection: 'row', - alignItems: 'center', - }; - - contentImgStyle = { - width: '25%', - aspectRatio: 1, - }; - - contentMsgImgStyle = { - margin: 20, - marginRight: 5, - borderRadius: 10, - borderWidth: 0, - }; - - contentBodyStyle = { - flex: 1, - }; - - containMode = 'cover'; - } - - return ( - onPress(cta)} - disabled={!ctaEnabled}> - {ctaBorderEnabled ? ( - - ) : ( - - )} - - - - onPress(item.url)} - disabled={!item.url || item.url === '' ? true : false}> - {/* */} - - - {item.app} - - - - {addSecretIcon == false ? null : ( - - - - )} - - - - {loading == true ? ( - - ) : ( - - {!img ? null : DownloadHelper.isMediaSupportedVideo(img) ? ( - - - - ) : ( - - { - onImagePreview(fileURL); - }} - /> - - )} - - - {!sub ? null : {sub}} - - - - {!timestamp ? null : ( - - - {moment - .utc(parseInt(timestamp) * 1000) - .local() - .format('DD MMM YYYY | hh:mm A')}{' '} - - - )} - - - )} - - - - ); - // } -}; - -export default FeedItem; - -// Styling -const styles = StyleSheet.create({ - container: { - // width: "100%", - marginVertical: 15, - marginHorizontal: 20, - }, - cover: { - position: 'absolute', - ...StyleSheet.absoluteFill, - justifyContent: 'center', - flex: 1, - borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS, - }, - coverPlain: { - backgroundColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - inner: { - margin: 1, - overflow: 'hidden', - borderRadius: GLOBALS.ADJUSTMENTS.FEED_ITEM_RADIUS, - }, - header: { - width: '100%', - paddingVertical: 7, - paddingHorizontal: 10, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - borderBottomWidth: 1, - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - appInfo: { - flex: 1, - alignItems: 'center', - backgroundColor: 'red', - }, - appLink: { - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center', - }, - appicon: { - flex: 0, - justifyContent: 'center', - alignItems: 'center', - borderRadius: 6, - height: 24, - aspectRatio: 1, - marginRight: 5, - overflow: 'hidden', - backgroundColor: GLOBALS.COLORS.SLIGHT_GRAY, - }, - apptext: { - marginRight: 10, - marginLeft: 5, - fontSize: 12, - color: GLOBALS.COLORS.MID_BLACK_TRANS, - fontWeight: '300', - }, - appsecret: { - width: 16, - height: 16, - borderRadius: 16, - }, - content: { - backgroundColor: GLOBALS.COLORS.WHITE, - }, - contentLoader: { - margin: 20, - }, - contentVid: { - width: '100%', - }, - msgVid: { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - borderBottomWidth: 1, - }, - contentImg: { - width: '100%', - aspectRatio: 2, - }, - msgImg: { - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - borderBottomWidth: 1, - resizeMode: 'contain', - }, - contentBody: { - paddingHorizontal: 15, - }, - msgSub: { - fontSize: 16, - fontWeight: '300', - color: GLOBALS.COLORS.MID_BLACK_TRANS, - paddingVertical: 10, - }, - msg: { - paddingTop: 5, - paddingBottom: 20, - }, - timestampOuter: { - display: 'flex', - justifyContent: 'center', - alignSelf: 'flex-end', - paddingVertical: 5, - paddingHorizontal: 12, - marginRight: -20, - borderTopLeftRadius: 5, - borderTopWidth: 1, - borderLeftWidth: 1, - borderColor: GLOBALS.COLORS.SLIGHT_GRAY, - overflow: 'hidden', - - backgroundColor: GLOBALS.COLORS.SLIGHTER_GRAY, - }, - timestamp: { - fontWeight: '300', - fontSize: 12, - - color: GLOBALS.COLORS.MID_BLACK_TRANS, - }, -}); diff --git a/src/components/ui/testFeed/FeedItemWrapperComponent.js b/src/components/ui/testFeed/FeedItemWrapperComponent.js deleted file mode 100644 index 731ceb2d1..000000000 --- a/src/components/ui/testFeed/FeedItemWrapperComponent.js +++ /dev/null @@ -1,343 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import { - ActivityIndicator, - Animated, - Easing, - Image, - StyleSheet, - Text, - TouchableWithoutFeedback, - View, -} from 'react-native'; -import Swipeable from 'react-native-gesture-handler/Swipeable'; -import GLOBALS from 'src/Globals'; -import {ToasterOptions} from 'src/components/indicators/Toaster'; -import EPNSActivity from 'src/components/loaders/EPNSActivity'; -import FeedDBHelper from 'src/helpers/FeedDBHelper'; - -import FeedItem from './FeedItemComponents'; - -const FeedItemWrapper = props => { - // // CONSTRUCTOR - // constructor(props) { - // super(props); - - // this.state = { - // deleting: false, - // scale: new Animated.Value(100), - // height: null, - // adjustedH: 0, - // collapsedH: null, - // initialized: false, - - // collapsing: false, - // undo: false, - // } - // } - - // // COMPONENT MOUNTED - // componentDidMount() { - - // } - - // // COMPONENT UPDATED - // componentDidUpdate(prevProps) { - // } - - // // LAYOUT CHANGE - // findDimensions = (layout) => { - // const {height} = layout; - - // if (this.state.adjustedH < height && this.state.initialized == false) { - // this.setState({ - // adjustedH: height, - // height: new Animated.Value(0), - // collapsedH: new Animated.Value(0), - // initialized: true, - // }, () => { - // Animated.timing(this.state.height, { - // toValue: height, - // easing: Easing.easeInOut, - // duration: 250, - // // useNativeDriver: true, // No support for height - // }).start(); - // }); - // } - // } - - // // Functions - // onSwipeableRightWillOpen = () => { - // this.setState({ - // deleting: true - // }); - // } - - // onSwipeableRightOpened = async (item, nid, itemArchivedFunc, showToast) => { - // let deleteObj = {}; - - // const db = FeedDBHelper.getDB(); - - // FeedDBHelper.hideFeedItem(db, item["nid"]).then(() => { - // this.animateHeightCollapse(nid, itemArchivedFunc); - // }).catch(err => { - // // Perform Event Edited Callback - // this.refs.SwipeRight.close(); - - // // Show Toast - // this.props.showToast("Error Archiving Notification", '', ToasterOptions.TYPE.GRADIENT_PRIMARY); - // // console.log(err); - // }); - // } - - // onSwipeableClose = () => { - // if (this.state.undo == true) { - // this.setState({ - // undo: false, - // collapsing: false, - // deleting: false, - // }) - // } - // } - - // // Animated Height Collapse - // animateHeightCollapse = (nid, itemArchivedFunc) => { - // this.setState({ - // collapsing: true, - // }, () => { - // Animated.timing(this.state.height, { - // toValue: 0, - // easing: Easing.easeInOut, - // duration: 250, - // // useNativeDriver: true, // No support for height - // }).start(() => { - // // Perform Event Edited Callback - // if (itemArchivedFunc) { - // itemArchivedFunc(nid); - // } - // }); - // }) - // } - - // // To uncollapse - // uncollapseHeight = () => { - // this.setState({ - // undo: true, - // }, () => { - // Animated.timing(this.state.height, { - // toValue: this.state.adjustedH, - // easing: Easing.easeInOut, - // duration: 250, - // // useNativeDriver: true, // No support for height - // }).start(() => { - // this.refs.SwipeRight.close(); - // }); - // }) - // } - - // Render Right Sliding Action - // renderRightActions = (progress, dragX) => { - // const scaleIcon = dragX.interpolate({ - // inputRange: [-200, 0], - // outputRange: [1, 0.4], - // extrapolate: 'clamp', - // }); - // // - // // const transXIcon = dragX.interpolate({ - // // inputRange: [0, 50, 100, 101], - // // outputRange: [5, 0, 0, 1], - // // }); - - // let scale = 0; - - // if (this.state.height) { - // scale = this.state.height.interpolate({ - // inputRange: [0, this.state.adjustedH], - // outputRange: [0, 1], - // extrapolate: 'clamp' - // }); - // } - - // return ( - // - // { - // this.state.deleting - // ? - // - // - // : - // - // - // } - // - // ); - // }; - - // RENDER - // render() { - // const { - // style, - // item, - // nid, - // itemArchived, - // showToast, - // onImagePreview, - // privateKey, - // } = this.props; - - // let scale = 0; - // let translateY = 0; - // let fade = 0; - // let height = undefined; - - // if (item["hidden"] == 1) { - // height = 0; - // fade = 0; - // } - - // if (this.state.height) { - // scale = this.state.height.interpolate({ - // inputRange: [0, this.state.adjustedH], - // outputRange: [0.6, 1], - // extrapolate: 'clamp' - // }); - - // translateY = this.state.height.interpolate({ - // inputRange: [0.9, this.state.adjustedH], - // outputRange: [-this.state.adjustedH * 0.75, 0], - // extrapolate: 'clamp' - // }); - - // fade = this.state.height.interpolate({ - // inputRange: [0, this.state.adjustedH/2, this.state.adjustedH], - // outputRange: [0, 0.1, 1], - // extrapolate: 'clamp' - // }); - // } - - // if (this.state.collapsing) { - // height = this.state.height; - // } - - return ( - // this.onSwipeableRightOpened( - // item, - // nid, - // itemArchived, - // showToast - // )} - // onSwipeableClose={this.onSwipeableClose} - // > - // { this.findDimensions(event.nativeEvent.layout) }} - // > - - // - // - ); - // } -}; - -export default FeedItemWrapper; - -const styles = StyleSheet.create({ - swipeContainer: {}, - container: { - marginHorizontal: 20, - alignItems: 'center', - shadowColor: GLOBALS.COLORS.BLACK, - shadowOffset: { - width: 0, - height: 4, - }, - shadowOpacity: 0.1, - shadowRadius: 6, - - elevation: 4, - }, - primaySegment: { - flex: 1, - }, - actionView: { - flex: 1, - width: '100%', - justifyContent: 'center', - }, - actionContent: { - flex: 1, - alignSelf: 'flex-end', - justifyContent: 'center', - marginRight: 30, - }, - actionImage: { - width: 30, - resizeMode: 'contain', - }, - actionContentAfter: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - }, - actionActivity: {}, - actionText: { - color: GLOBALS.COLORS.WHITE, - fontSize: 10, - fontWeight: 'bold', - textAlign: 'center', - }, -}); diff --git a/src/components/ui/testFeed/FeedsDisplayerComponent.js b/src/components/ui/testFeed/FeedsDisplayerComponent.js deleted file mode 100644 index fdf8c4253..000000000 --- a/src/components/ui/testFeed/FeedsDisplayerComponent.js +++ /dev/null @@ -1,208 +0,0 @@ -import {Asset} from 'expo-asset'; -import React from 'react'; -import { - FlatList, - Image, - RefreshControl, - StyleSheet, - Text, - View, -} from 'react-native'; -import ImageView from 'react-native-image-viewing'; -import SafeAreaView from 'react-native-safe-area-view'; -import GLOBALS from 'src/Globals'; -import {Toaster, ToasterOptions} from 'src/components/indicators/Toaster'; -import StylishLabel from 'src/components/labels/StylishLabel'; -import EPNSActivity from 'src/components/loaders/EPNSActivity'; -import FeedItemWrapper from 'src/components/ui/FeedItemWrapper'; -import ImagePreviewFooter from 'src/components/ui/ImagePreviewFooter'; -import FeedDBHelper from 'src/helpers/FeedDBHelper'; -import MetaStorage from 'src/singletons/MetaStorage'; - -const FeedsDisplayerComponent = props => { - useEffect(() => { - this.showToast( - 'Messages Unarchived! Restarting...', - '', - ToasterOptions.TYPE.GRADIENT_PRIMARY, - ); - }, []); - - showToast = (msg, icon, type, tapCB, screenTime) => { - refs.Toaster.showToast(msg, icon, type, tapCB, screenTime); - }; - - // To pull more feeds and store them in the feed items - - // // Show Toast - // if (totalCount == 0) { - // // No New Items - // this.showToast("No New Notifications", "", ToasterOptions.TYPE.GRADIENT_PRIMARY); - // } - // else { - // this.showToast("New Notifications Loaded!", "", ToasterOptions.TYPE.GRADIENT_PRIMARY); - - // } - - // onEndReached = () => { - // console.log("Refreshing"); - - // if(!this.state.feedEnded){ - // if (!this.state.feedIsRefreshing) { - // this.triggerGetItemsFromDB(true); - // } - // } - - // // This is for flat list - // // onEndReached={this.onEndReached} - // // onEndReachedThreshold={0.5} - // } - - // // To get ref for feed items - // getRefForFeedItem = (nid) => { - // return 'feed' + nid; - // } - - // For showing toast - // const showToast = (msg, icon, type, tapCB, screenTime) => { - // if (props.showToast) { - // props.showToast(msg, icon, type, tapCB, screenTime); - // } - // }; - - // Render Footer - renderFooter = () => { - return ; - }; - - // RENDER - - const { - style, - onFeedRefreshed, - // showToast - privateKey, - } = this.props; - - render( - - - { - this.triggerGetItemsFromDB(); - }} - /> - } - data={feeds != [] ? feeds : []} - // extraData={this.state} - keyExtractor={item => item.payload_id} - contentContainerStyle={styles.feedScrollContent} - onEndReachedThreshold={100} - renderItem={({item}) => ( - - // (this.itemRefs = { - // ...this.itemRefs, - // [this.getRefForFeedItem(item["nid"])]: ref, - // }) - // } - loading={props.loading} - item={item} - // nid={item["nid"]} - // showToast={showToast} - // itemArchived={(nid) => { - // this.archiveItem(nid); - // }} - // onImagePreview={(fileURL) => this.showImagePreview(fileURL)} - // privateKey={privateKey} - /> - )} - // ListEmptyComponent={ - // this.state.feedQueried == false ? ( - // - // - // - // ) : ( - // - // - // - // - // ) - // } - /> - - - - {/* { - this.setState({ - renderGallery: false, - }); - }} - FooterComponent={({ imageIndex }) => ( - - )} - /> */} - , - ); -}; - -export default FeedsDisplayerComponent; - -// Styling -const styles = StyleSheet.create({ - container: { - flex: 1, - width: '100%', - justifyContent: 'center', - alignItems: 'center', - }, - feedScrollContainer: { - width: '100%', - flex: 1, - marginTop: 10, - }, - feedScrollContent: { - flexGrow: 1, - }, - infodisplay: { - flexGrow: 1, - justifyContent: 'center', - alignItems: 'center', - paddingHorizontal: 20, - paddingVertical: 20, - }, - infoIcon: { - height: 48, - resizeMode: 'contain', - margin: 10, - }, - infoText: { - marginVertical: 10, - }, - loading: {}, - noPendingFeeds: {}, - feed: { - width: '100%', - }, -}); diff --git a/src/helpers/MediaHelper.ts b/src/helpers/MediaHelper.ts new file mode 100644 index 000000000..6140ff97c --- /dev/null +++ b/src/helpers/MediaHelper.ts @@ -0,0 +1,87 @@ +export const MediaHelper = { + // validate a CTA + validURL: function (str: string | undefined) { + if (!str) return false; + const pattern = new RegExp( + '^(https?:\\/\\/)?' + // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string + '(\\S*)?$', + 'i', + ); // fragment locator + return !!pattern.test(str); + }, + // To get Save File Name + getSaveFileName: function (fileURL: string, useTempLocation: string) { + // Remove all http, https protocols first + fileURL = fileURL.replace(/(^\w+:|^)\/\//, ''); + + // /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi + // Remove all special characters + fileURL = fileURL.replace(/[`~!@#$%^&*()_|+\-=?;:'",<>\{\}\[\]\\\/]/gi, ''); + + // Remove all but 250 characters + if (fileURL.length > 250) { + fileURL = fileURL.substr(-250); + } + + if (useTempLocation) { + return fileURL + '.temp'; + } else { + return fileURL; + } + }, + // Determine if media is supported video + isMediaSupportedVideo: function (fileURL: string | undefined) { + if (!fileURL) return; + // check if media external embed first + const mediaURL = MediaHelper.isMediaExternalEmbed(fileURL); + if (mediaURL) { + return mediaURL; + } else { + // check if mp4 extension + if (fileURL.split('.').pop() === 'mp4') { + return true; + } + } + + // if all else fail + return false; + }, + // check if media is external embed, like youtube, soundcloud, etc + isMediaExternalEmbed: function (fileURL: string) { + return MediaHelper.isMediaYoutube(fileURL); + }, + // Determine if youtube + isMediaYoutube: function (fileURL: string) { + if (fileURL !== undefined || fileURL !== '') { + const regExp = + /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/; + const match = fileURL.match(regExp); + if (match && match[2].length === 11) { + // embed url + const embedURL = + 'https://www.youtube.com/embed/' + + match[2] + + '?autoplay=0&enablejsapi=1'; + return embedURL; + } + } + return ''; + }, + // Get youtube id + getYoutubeID: function (fileURL: string) { + if (fileURL !== undefined || fileURL !== '') { + const regExp = + /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/; + const match = fileURL.match(regExp); + if (match && match[2].length === 11) { + return match[2]; + } + } + + return ''; + }, +}; diff --git a/src/helpers/useDecrypt.ts b/src/helpers/useDecrypt.ts new file mode 100644 index 000000000..c90b718d7 --- /dev/null +++ b/src/helpers/useDecrypt.ts @@ -0,0 +1,65 @@ +import * as React from 'react'; + +export type DecryptNotifAttibutesType = { + notifTitle: string; + notifBody: string; + notifCta: string; + notifImage: string; + isSecretRevealed: boolean; +}; + +function useDecrypt( + initialValues: { + notificationTitle?: string; + parsedBody?: string; + cta?: string; + image?: string; + }, + isSecret?: boolean, +) { + const [notifAttributes, setNotifAttributes] = + React.useState({ + notifTitle: initialValues.notificationTitle || '', + notifBody: initialValues.parsedBody || '', + notifCta: initialValues.cta || '', + notifImage: initialValues.image || '', + isSecretRevealed: false, // avoids extra render + }); + + const hideSecretAttributes = isSecret + ? notifAttributes?.isSecretRevealed + ? false + : true + : false; + + const setDecryptedValues = ({ + title, + body, + cta, + image, + }: { + title?: string; + body: string; + cta?: string; + image?: string; + }) => { + setNotifAttributes({ + notifTitle: title || '', + notifBody: body || '', + notifCta: cta || '', + notifImage: image || '', + isSecretRevealed: true, + }); + }; + + return { + notifTitle: notifAttributes.notifTitle, + notifBody: notifAttributes.notifBody, + notifCta: hideSecretAttributes ? '' : notifAttributes.notifCta, + notifImage: hideSecretAttributes ? '' : notifAttributes.notifImage, + isSecretRevealed: notifAttributes.isSecretRevealed, + setDecryptedValues, + }; +} + +export default useDecrypt; diff --git a/src/jsons/SampleFeed.js b/src/jsons/SampleFeed.js deleted file mode 100644 index 58cd6c180..000000000 --- a/src/jsons/SampleFeed.js +++ /dev/null @@ -1,244 +0,0 @@ -const sampleFeed = [ - { - payload_id: 1, - channel: '0x0b5E9fa12C4C1946fA2f14b7271cC60541508f23', - // epoch: "2021-07-01T11:44:27.000Z", - payload: { - apns: { - payload: { - aps: { - category: 'withappicon', - 'mutable-content': 1, - 'content-available': 1, - }, - }, - fcm_options: { - image: - 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - }, - }, - data: { - app: 'App Bot', - sid: '22710', - url: 'https://epns.io/', - acta: '', - aimg: '', - amsg: '[b:Greetings] fellow users! Welcome aboard!\n\nI am your personalized [d:App Bot] whose sole purpose is to guide you about the app.', - asub: 'Welcome to Push (EPNS)', - icon: 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - type: '1', - // epoch: "1625139867", - appbot: '1', - hidden: '0', - secret: '', - }, - android: { - notification: { - icon: '@drawable/ic_stat_name', - color: '#e20880', - image: - 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - default_vibrate_timings: true, - }, - }, - notification: { - body: '\nHourly Movement: 0.33%\nDaily Movement: 4.66%\nWeekly Movement: 14.91%', - title: 'ETH Tracker - ETH at $2,216.38', - }, - }, - }, - { - payload_id: 2, - channel: '0x0b5E9fa12C4C1946fA2f14b7271cC60541508f23', - // epoch: "2021-07-01T11:44:27.000Z", - payload: { - apns: { - payload: { - aps: { - category: 'withappicon', - 'mutable-content': 1, - 'content-available': 1, - }, - }, - fcm_options: { - image: - 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - }, - }, - data: { - app: 'App Bot', - sid: '22710', - url: 'https://push.org/', - acta: '', - aimg: '', - amsg: '[d:Channels] represent your favorite [b:dApps] or [b:Smart Contracts]. You will often get notifications from different channels.\n\nThe [b:top section] of the message contains information about these channels.\n\n[b:Clicking on it] takes you to their [b:website].', - asub: 'About Channels', - icon: 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - type: '1', - // epoch: "1625139867", - appbot: '1', - hidden: '0', - secret: '', - }, - android: { - notification: { - icon: '@drawable/ic_stat_name', - color: '#e20880', - image: - 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - default_vibrate_timings: true, - }, - }, - notification: { - body: '\nHourly Movement: 0.33%\nDaily Movement: 4.66%\nWeekly Movement: 14.91%', - title: 'ETH Tracker - ETH at $2,216.38', - }, - }, - }, - { - payload_id: 3, - channel: '0x0b5E9fa12C4C1946fA2f14b7271cC60541508f23', - // epoch: "2021-07-01T11:44:27.000Z", - payload: { - apns: { - payload: { - aps: { - category: 'withappicon', - 'mutable-content': 1, - 'content-available': 1, - }, - }, - fcm_options: { - image: - 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - }, - }, - data: { - app: 'App Bot', - sid: '22710', - url: 'https://epns.io/', - acta: '', - aimg: 'https://backend-staging.epns.io/assets/epnsappbellturorial.jpg', - amsg: 'The [d:Bell] on the [b:top right] keeps track of any incoming messages and will inform you about it.\n\nClicking on the [b:bell] will update your feed [i:(Alternatively, pull feed down to refresh)]', - asub: 'Ring the Bell', - icon: 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - type: '1', - // epoch: "1625139867", - appbot: '1', - hidden: '0', - secret: '', - }, - android: { - notification: { - icon: '@drawable/ic_stat_name', - color: '#e20880', - image: - 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - default_vibrate_timings: true, - }, - }, - notification: { - body: '\nHourly Movement: 0.33%\nDaily Movement: 4.66%\nWeekly Movement: 14.91%', - title: 'ETH Tracker - ETH at $2,216.38', - }, - }, - }, - { - payload_id: 4, - channel: '0x0b5E9fa12C4C1946fA2f14b7271cC60541508f23', - // epoch: "2021-07-01T11:44:27.000Z", - payload: { - apns: { - payload: { - aps: { - category: 'withappicon', - 'mutable-content': 1, - 'content-available': 1, - }, - }, - fcm_options: { - image: - 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - }, - }, - data: { - app: 'App Bot', - sid: '22710', - url: 'https://push.org/', - acta: 'https://push.org', - aimg: '', - amsg: 'Notifications are [b:never boring] in Push (EPNS).\n\nThe messages with [b:blueish outlines] are links that the [b:dApp] has provided you. \n\n[d:Tapping the message opens it.]', - asub: 'Nofications Types', - icon: 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - type: '1', - // epoch: "1625139867", - appbot: '1', - hidden: '0', - secret: '', - }, - android: { - notification: { - icon: '@drawable/ic_stat_name', - color: '#e20880', - image: - 'https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg', - default_vibrate_timings: true, - }, - }, - notification: { - body: '\nHourly Movement: 0.33%\nDaily Movement: 4.66%\nWeekly Movement: 14.91%', - title: 'ETH Tracker - ETH at $2,216.38', - }, - }, - }, - // { - // payload_id: 5, - // channel: "0x0b5E9fa12C4C1946fA2f14b7271cC60541508f23", - // // epoch: "2021-07-01T11:44:27.000Z", - // payload: { - // apns: { - // payload: { - // aps: { - // category: "withappicon", - // "mutable-content": 1, - // "content-available": 1, - // }, - // }, - // fcm_options: { - // image: - // "https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg", - // }, - // }, - // data: { - // app: "App Bot", - // sid: "22710", - // url: "https://epns.io/", - // acta: "", - // aimg: "", - // amsg: "The [d:coolest type] of messages are [t:secrets]. They are indicated by the [bi:shush gradient] on the top left of the message box.\n\nThey are always [d:encrypted] and [b:only you] can see them.", - // asub: "Secrets... shhh!!!", - // icon: "https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg", - // type: "-2", - // // epoch: "1625139867", - // appbot: "1", - // hidden: "0", - // secret: "", - // }, - // android: { - // notification: { - // icon: "@drawable/ic_stat_name", - // color: "#e20880", - // image: - // "https://backend-prod.epns.io/cache/bafkreibzn4s6nfa4jwyuswkojxclec5nhvj3e4ac5cvamzc2ajznh7t77a.jpg", - // default_vibrate_timings: true, - // }, - // }, - // notification: { - // body: "\nHourly Movement: 0.33%\nDaily Movement: 4.66%\nWeekly Movement: 14.91%", - // title: "ETH Tracker - ETH at $2,216.38", - // }, - // }, - // }, -]; - -export default sampleFeed; diff --git a/src/navigation/screens/SampleFeedScreen.js b/src/navigation/screens/SampleFeedScreen.js deleted file mode 100644 index 75f62406c..000000000 --- a/src/navigation/screens/SampleFeedScreen.js +++ /dev/null @@ -1,95 +0,0 @@ -import {Asset} from 'expo-asset'; -import React, {useState} from 'react'; -import {FlatList, StatusBar, StyleSheet} from 'react-native'; -import ImageView from 'react-native-image-viewing'; -import SafeAreaView from 'react-native-safe-area-view'; -import GLOBALS from 'src/Globals'; -import ImagePreviewFooter from 'src/components/ui/ImagePreviewFooter'; -import FeedItemComponent from 'src/components/ui/testFeed/FeedItemComponents.js'; -import sampleFeed from 'src/jsons/SampleFeed'; - -const SampleFeedScreen = ({style}) => { - const showImagePreview = async fileURL => { - let validPaths = []; - let fileIndex = -1; - - // Add Image - // Download the file if not done already - await Asset.loadAsync(fileURL); - - // Push to valid path - validPaths.push({ - uri: Asset.fromModule(fileURL).uri, - id: fileURL, - }); - - fileIndex = validPaths.length - 1; - - // console.log("LOADED IMAGES:"); - // console.log(validPaths); - - setLoadedImages(validPaths); - setRenderGallery(true); - setStartFromIndex(fileIndex); - }; - - const [loadedImages, setLoadedImages] = useState([]); - const [renderGallery, setRenderGallery] = useState(false); - const [startFromIndex, setStartFromIndex] = useState(0); - return ( - - - - item.payload_id.toString()} - initialNumToRender={10} - style={{flex: 1}} - renderItem={({item}) => ( - showImagePreview(fileURL)} - /> - )} - /> - - { - setRenderGallery(false); - }} - FooterComponent={({imageIndex}) => ( - - )} - /> - - ); -}; - -// Styling -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: GLOBALS.COLORS.WHITE, - }, - textStyle: { - fontSize: 45, - }, - subHeaderStyle: { - fontSize: 20, - }, -}); - -export default SampleFeedScreen; diff --git a/src/navigation/screens/chats/helpers/userChatLoaderHelper.ts b/src/navigation/screens/chats/helpers/userChatLoaderHelper.ts index 6e6f2ca9f..032b4f8ba 100644 --- a/src/navigation/screens/chats/helpers/userChatLoaderHelper.ts +++ b/src/navigation/screens/chats/helpers/userChatLoaderHelper.ts @@ -1,10 +1,10 @@ -import * as PushNodeClient from 'src/apis'; +import * as PushSdk from '@kalashshah/react-native-sdk/src'; import {ChatFeedCache} from './useChatLoader'; export const checkIfItemInCache = ( cache: ChatFeedCache, - feeds: PushNodeClient.Feeds[], + feeds: PushSdk.PushApi.IFeeds[], ) => { let isInCache = true; for (let i = 0; i < feeds.length; i++) { @@ -21,10 +21,10 @@ export const checkIfItemInCache = ( export const filterChatAndRequestFeeds = ( userAddress: string, - feeds: PushNodeClient.Feeds[], + feeds: PushSdk.PushApi.IFeeds[], ) => { - const chatFeeds: PushNodeClient.Feeds[] = []; - const requestFeeds: PushNodeClient.Feeds[] = []; + const chatFeeds: PushSdk.PushApi.IFeeds[] = []; + const requestFeeds: PushSdk.PushApi.IFeeds[] = []; feeds.forEach(element => { if (element.intent?.includes(userAddress)) {