Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev-asf-parent' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Asherda committed Dec 9, 2024
2 parents 4d5cd9a + bce34e0 commit 73bbec9
Show file tree
Hide file tree
Showing 19 changed files with 1,504 additions and 92 deletions.
40 changes: 30 additions & 10 deletions ios/verusMobile/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,36 @@
</dict>
</dict>
</dict>
<key>NSCameraUsageDescription</key>
<string>Verus Mobile needs access to the camera to scan QR codes, and to allow you to add images to your locally encrypted personal profile</string>
<key>NSFaceIDUsageDescription</key>
<string>Enabling Face ID allows you quick and secure access to your account.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Verus Mobile needs access to the camera to scan QR codes</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>The user can save QR code invoices to their photo library.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>The user can use the photo library to add images to their locally encrypted personal profile</string>
<key>NSAppleMusicUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>NSCalendarsUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>NSCameraUsageDescription</key>
<string>Verus Mobile needs access to the camera to scan QR codes, and to allow you to add images to your locally encrypted personal profile</string>
<key>NSContactsUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>NSFaceIDUsageDescription</key>
<string>Enabling Face ID allows you quick and secure access to your account.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Verus Mobile needs access to the camera to scan QR codes</string>
<key>NSMotionUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>The user can save QR code invoices to their photo library.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>The user can use the photo library to add images to their locally encrypted personal profile</string>
<key>NSSiriUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>The app does not request this permission or utilize this functionality but it is included in our info.plist since our app utilizes the react-native-permissions library, which references this permission in its code.</string>
<key>UIAppFonts</key>
<array>
<string>AntDesign.ttf</string>
Expand Down
2 changes: 1 addition & 1 deletion src/components/BarcodeReader/BarcodeReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const BarcodeReader = props => {
}}
device={device}
codeScanner={codeScanner}
isActive={appStateVisible === 'active'}
isActive={appStateVisible === 'active' && !props.cameraDisabled}
{...cameraProps}
/>
<View style={{
Expand Down
207 changes: 207 additions & 0 deletions src/components/ConvertCardModal/ConvertCardModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import React, { useState, useEffect, useRef } from "react";
import { Platform, SafeAreaView, View } from "react-native";
import { Text, Portal, Button, IconButton } from "react-native-paper";
import Colors from "../../globals/colors";
import SemiModal from "../SemiModal";
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import { NavigationContainer } from "@react-navigation/native";
import { createStackNavigator } from "@react-navigation/stack";
import AnimatedActivityIndicatorBox from "../AnimatedActivityIndicatorBox";

import { useSelector } from "react-redux";
import { CONVERT_CARD_MODAL_MODES } from "../../utils/constants/convert";
import SearchableList from "../SearchableList";

const TopTabs = createMaterialTopTabNavigator();
const Root = createStackNavigator();

const ConvertCardModal = ({
onClose,
visible,
setVisible,
totalBalances,
mode,
networks,
converters,
currencies,
addresses,
onSelectNetwork,
onSelectAddress,
onSelectCurrency,
onSelectConverter,
loading
}) => {
const [preventExit, setPreventExit] = useState(false);
const [modalHeight, setModalHeight] = useState(600); // Adjust as needed

const activeCoinsForUser = useSelector(state => state.coins.activeCoinsForUser);
const [modalTitle, setModalTitle] = useState("Title");

useEffect(() => {
// Handle side effects here if necessary
}, []);

const cancel = () => {
if (!preventExit) {
setVisible(false);
if (onClose) {
onClose();
}
}
};

const showHelpModal = () => {
// Implement your help modal logic here
};

return (
<Portal>
<NavigationContainer>
<SemiModal
animationType="slide"
transparent={true}
visible={visible}
onRequestClose={cancel}
contentContainerStyle={{
height: modalHeight,
flex: 0,
backgroundColor: "white",
}}
>
{loading ? <AnimatedActivityIndicatorBox /> :
<SafeAreaView style={{ flex: 1 }}>
<Root.Navigator
screenOptions={{
header: () => (
<View style={{
flexDirection: 'row',
alignItems: "center",
justifyContent: "space-between",
backgroundColor: Colors.secondaryColor
}}>
<IconButton icon="close" size={16} iconColor={Colors.verusDarkGray} />
<Text style={{ marginBottom: 16, fontSize: 16, textAlign: "center" }}>
{modalTitle}
</Text>
</View>
),
headerStyle: {
height: 52,
},
}}
>
<Root.Screen name="ModalInner">
{() => (
<TopTabs.Navigator
initialRouteName="SelectCurrency"
backBehavior="none"
tabBarPosition="bottom"
screenOptions={{
swipeEnabled: false,
tabBarPressColor: "transparent",
tabBarPressOpacity: 1,
tabBarLabelStyle: {
fontSize: 12,
},
lazy: true,
lazyPlaceholder: () => <AnimatedActivityIndicatorBox />,
}}
>
<TopTabs.Screen
name="SelectCurrency"
options={{
tabBarLabel: 'Currency',
}}
listeners={{
tabPress: e => {
e.preventDefault();
},
}}
>
{tabProps => (
<SearchableList
{...tabProps}
items={currencies}
setModalTitle={setModalTitle}
onSelect={onSelectCurrency}
nextScreen="SelectNetwork"
/>
)}
</TopTabs.Screen>
<TopTabs.Screen
name="SelectNetwork"
options={{
tabBarLabel: 'Network',
}}
listeners={{
tabPress: e => {
e.preventDefault();
},
}}
>
{tabProps => (
<SearchableList
{...tabProps}
items={networks}
setModalTitle={setModalTitle}
onSelect={onSelectNetwork}
nextScreen={mode === CONVERT_CARD_MODAL_MODES.SEND ? "SelectAddress" : "SelectConverter"}
/>
)}
</TopTabs.Screen>
{mode === CONVERT_CARD_MODAL_MODES.RECEIVE && (
<TopTabs.Screen
name="SelectConverter"
options={{
tabBarLabel: 'Via',
}}
listeners={{
tabPress: e => {
e.preventDefault();
},
}}
>
{tabProps => (
<SearchableList
{...tabProps}
items={converters}
setModalTitle={setModalTitle}
onSelect={onSelectConverter}
nextScreen="SelectAddress"
/>
)}
</TopTabs.Screen>
)}
<TopTabs.Screen
name="SelectAddress"
options={{
tabBarLabel: mode === CONVERT_CARD_MODAL_MODES.SEND ? 'Source' : 'Dest',
}}
listeners={{
tabPress: e => {
e.preventDefault();
},
}}
>
{tabProps => (
<SearchableList
{...tabProps}
items={addresses}
setModalTitle={setModalTitle}
onSelect={onSelectAddress}
/>
)}
</TopTabs.Screen>
</TopTabs.Navigator>
)}
</Root.Screen>
</Root.Navigator>
</SafeAreaView>
}
</SemiModal>
</NavigationContainer>
</Portal>
);
};

export default ConvertCardModal;
115 changes: 115 additions & 0 deletions src/components/SearchableList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { useMemo, useState } from 'react';
import { View, TextInput, FlatList } from 'react-native';
import { List, Text } from 'react-native-paper';
import { RenderCircleCoinLogo } from '../utils/CoinData/Graphics';
import Colors from '../globals/colors';
import { useNavigation } from '@react-navigation/native';

const SearchableList = (props) => {
const [searchQuery, setSearchQuery] = useState('');
const items = props.items ? props.items : [];

const navigation = useNavigation();

// Filter the data based on the search query
const filteredData = useMemo(() => {
return items.filter(item =>
(
item.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
item.description.toLowerCase().includes(searchQuery.toLowerCase())
)
);
}, [searchQuery, items]);

const handleSelect = (key) => {
if (props.onSelect) props.onSelect(key);
if (props.nextScreen) navigation.navigate(props.nextScreen)
}

// Render each item in the FlatList
const renderItem = ({ item }) => (
<List.Item
title={item.title}
titleStyle={{
fontWeight: "600"
}}
description={item.description}
descriptionStyle={{
color: Colors.lightGrey
}}
onPress={() => handleSelect(item.key)}
left={() => (
<View
style={{
alignItems: "center",
justifyContent: "center",
}}
>
{RenderCircleCoinLogo(item.logo)}
</View>
)}
right={props =>
<View
{...props}
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-end",
justifyContent: "center"
}}>
{item.rightTitle && (
<Text style={{ fontWeight: "600" }}>
{item.rightTitle}
</Text>
)}
{item.rightDescription && (
<Text style={{ color: Colors.lightGrey }}>
{item.rightDescription}
</Text>
)}
</View>
}
/>
);

return (
<View style={{
flex: 1,
backgroundColor: Colors.secondaryColor,
paddingHorizontal: 10,
}}>
<TextInput
style={{
height: 40,
marginVertical: 10,
paddingHorizontal: 15,
marginHorizontal: 8,
borderRadius: 8,
backgroundColor: '#f0f0f0',
color: '#000',
}}
placeholder="Search..."
placeholderTextColor="#888"
value={searchQuery}
onChangeText={text => setSearchQuery(text)}
/>
<FlatList
data={filteredData}
keyExtractor={item => item.key}
renderItem={renderItem}
ListEmptyComponent={
<View style={{
marginTop: 50,
alignItems: 'center',
}}>
<Text style={{
fontSize: 18
}}>No items found</Text>
</View>
}
/>
</View>
);
};

export default SearchableList;
Loading

0 comments on commit 73bbec9

Please sign in to comment.