react-native-safe-area-context#SafeAreaView JavaScript Examples
The following examples show how to use
react-native-safe-area-context#SafeAreaView.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.js From musicont with MIT License | 6 votes |
Index = ({ songs }) => {
const [assets] = useAssets([require('../../assets/icons/hamburger.png'), require('../../assets/icons/search.png')]);
const [drawer, setDrawer] = useState(false);
return (
<Drawer active={drawer} current="recent" onItemPressed={() => setDrawer(false)}>
<SafeAreaView style={styles.container}>
<Header
options={{
left: {
children: drawer ? <Icon name="x" color="#C4C4C4" /> : <Image source={require('../../assets/icons/hamburger.png')} resizeMode="contain" />,
onPress: () => setDrawer(!drawer),
},
middle: {
show: true,
text: 'Recently Played',
},
right: {
show: false,
},
}}
/>
<View style={styles.sections}>
{songs && songs.length > 0 ? (
<Section.MusicList audios={songs} indicator={false} useIndex={true} />
) : (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 24, fontWeight: 'bold', color: 'rgba(0, 0, 0, .3)' }}>No recent yet!</Text>
</View>
)}
</View>
</SafeAreaView>
</Drawer>
);
}
Example #2
Source File: HomeScreen.js From WhatsApp-Clone with MIT License | 6 votes |
HomeScreen = ({children, style, navigation, ...rest}) => {
useEffect(() => {
registerStateChangeListener();
sendPageLoadStatus()
return () => {
// Clean up the subscription
unRgisterStateChangeListener()
};
}, []);
function registerStateChangeListener() {
AppState.addEventListener('change', handleAppStateChange);
}
function unRgisterStateChangeListener() {
AppState.removeEventListener('change', handleAppStateChange);
}
return (
<SafeAreaView style={DEFAULT_STYLES.container}>
<View style={DEFAULT_STYLES.container}>
{/* <Header hasTabs style={styles.headerStyle}> */}
<HomeHeader navigation={navigation} />
{/* </Header> */}
<TabView navigation={navigation} />
</View>
</SafeAreaView>
);
}
Example #3
Source File: index.js From MediBuddy with MIT License | 6 votes |
Footer = () => (
<SafeAreaView>
<Divider />
<View style={styles.footer}>
<View style={{ flex: 1 }}>
<Button
style={styles.btn}
labelStyle={styles.cancel}
mode="text"
onPress={() => console.log('Pressed')}>
Cancel
</Button>
</View>
<View style={{ flex: 1 }}>
<Button
style={styles.btn}
labelStyle={styles.ok}
mode="text"
onPress={() => console.log('Pressed')}>
Reschedule
</Button>
</View>
</View>
</SafeAreaView>
)
Example #4
Source File: Leaderboard.js From redis-examples with MIT License | 6 votes |
render() {
const {navigate} = this.props.navigation;
this.height = Math.round(Dimensions.get('screen').height);
this.width = Math.round(Dimensions.get('screen').width);
return (
<SafeAreaView
style={{
width: this.width,
height: this.height,
flex: 1,
alignItems: 'center'
}}>
<StatusBar
backgroundColor="#f4511e"/>
<View
style={{
height:this.height,
width: this.width
}}>
<FlatList
style={{
flex: 1,
flexDirection: 'column',
}}
renderItem={() => this.renderPlayerItems()}
data={[{bos: 'boş', key: 'key'}]}
refreshing={true}></FlatList>
</View>
</SafeAreaView>
);
}
Example #5
Source File: App.js From redis-examples with MIT License | 6 votes |
render(){
this.height = Math.round(Dimensions.get('screen').height);
this.width = Math.round(Dimensions.get('screen').width);
return (
<SafeAreaView style={{
width: this.width,
height: this.height,
flex: 1,
alignItems: 'center'}}>
<StatusBar
backgroundColor="#f4511e"/>
</SafeAreaView>
);
}
Example #6
Source File: SignModal.js From reddit-clone with MIT License | 6 votes |
SignModal = ({ navigation }) => {
const { colors } = useTheme()
return (
<TouchableWithoutFeedback onPress={() => navigation.goBack()}>
<View as={SafeAreaView} style={styles.container}>
<StatusBar hidden />
<View
style={[styles.modal, { backgroundColor: colors.background }]}
onStartShouldSetResponder={() => true}
>
<View style={styles.buttonContainer}>
<Button
bgColor={colors.signUpButton}
title="Sign Up"
onPress={() => navigation.navigate('SignUp')}
>
<PlusCircle color={colors.white} />
</Button>
<Button
bgColor={colors.signInButton}
title="Sign In"
onPress={() => navigation.navigate('SignIn')}
>
<LogIn color={colors.white} />
</Button>
</View>
</View>
</View>
</TouchableWithoutFeedback>
)
}
Example #7
Source File: index.js From musicont with MIT License | 6 votes |
Index = ({ songs }) => {
const [assets] = useAssets([require('../../assets/icons/hamburger.png'), require('../../assets/icons/search.png')]);
const [drawer, setDrawer] = useState(false);
return (
<Drawer active={drawer} current="songs" onItemPressed={() => setDrawer(false)}>
<SafeAreaView style={styles.container}>
<Header
options={{
left: {
children: drawer ? <Icon name="x" color="#C4C4C4" /> : <Image source={require('../../assets/icons/hamburger.png')} resizeMode="contain" />,
onPress: () => setDrawer(!drawer),
},
middle: {
show: true,
text: 'All Songs',
},
right: {
show: false,
},
}}
/>
<View style={styles.sections}>
<Section.MusicList audios={songs} indicator={false} />
</View>
</SafeAreaView>
</Drawer>
);
}
Example #8
Source File: index.js From musicont with MIT License | 6 votes |
Index = () => {
const [assets] = useAssets([require('../../assets/icons/hamburger.png'), require('../../assets/icons/search.png')]);
const [drawer, setDrawer] = useState(false);
return (
<Drawer active={drawer} current="home" onItemPressed={() => setDrawer(false)}>
<SafeAreaView style={styles.container}>
<Header
options={{
left: {
children: drawer ? <Icon name="x" color="#C4C4C4" /> : <Image source={require('../../assets/icons/hamburger.png')} resizeMode="contain" />,
onPress: () => setDrawer(!drawer),
},
}}
/>
<View style={styles.sections}>
<Section.Explore />
<Section.Recent style={{ marginTop: 30 }} />
<Section.Playlist style={{ marginTop: 30 }} />
</View>
<Footer />
</SafeAreaView>
</Drawer>
);
}
Example #9
Source File: index.js From musicont with MIT License | 6 votes |
Index = ({ songs }) => {
const [assets] = useAssets([require('../../assets/icons/hamburger.png'), require('../../assets/icons/search.png')]);
const [drawer, setDrawer] = useState(false);
return (
<Drawer active={drawer} current="favourite" onItemPressed={() => setDrawer(false)}>
<SafeAreaView style={styles.container}>
<Header
options={{
left: {
children: drawer ? <Icon name="x" color="#C4C4C4" /> : <Image source={require('../../assets/icons/hamburger.png')} resizeMode="contain" />,
onPress: () => setDrawer(!drawer),
},
middle: {
show: true,
text: 'My Favourites',
},
right: {
show: false,
},
}}
/>
<View style={styles.sections}>
{songs && songs.length > 0 ? (
<Section.MusicList audios={songs} indicator={false} useIndex={true} />
) : (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 24, fontWeight: 'bold', color: 'rgba(0, 0, 0, .3)' }}>No favourite yet!</Text>
</View>
)}
</View>
</SafeAreaView>
</Drawer>
);
}
Example #10
Source File: ProfileScreen.js From hero with MIT License | 6 votes |
ProfileScreen = () => {
return (
<SafeAreaView style={styles.appContainer}>
<StatusBar
translucent
backgroundColor="transparent"
barStyle="dark-content"
/>
<View style={styles.header}>
<Text style={styles.appTitle}>profile</Text>
</View>
<View style={styles.footer}>
<Text style={styles.p}>Designed by Gino Lee Swanepoel</Text>
<Text style={styles.p}>in React Native</Text>
</View>
</SafeAreaView>
);
}
Example #11
Source File: Subscribe.js From actual with MIT License | 6 votes |
export function Subscribe({ route, navigation, getUserData, createBudget }) {
let { email, userId, key } = route.params || {};
let textStyle = [
styles.text,
{ fontSize: 17, lineHeight: 25, color: 'white' }
];
return (
<SafeAreaView style={{ flex: 1 }}>
<KeyboardAvoidingView>
{/* <StatusBar barStyle="light-content" /> */}
<Header navigation={navigation} buttons={['back']} />
<Stack justify="center" style={{ flex: 1, padding: 20 }} spacing={8}>
<View>
<Text style={textStyle}>
You{"'"}re almost there. You need to subscribe to gain access to
Actual. No charges will be made for 1 month.
</Text>
</View>
<View style={{ alignItems: 'center' }}>
<Text style={[textStyle, { fontWeight: '700', marginBottom: 5 }]}>
Start with a 1 month free trial.
</Text>
<AccountButton
navigation={navigation}
userData={{ id: userId, key, email }}
darkMode={true}
useDummyPurchaser={true}
/>
</View>
</Stack>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
Example #12
Source File: index.js From actual with MIT License | 5 votes |
render() {
const {
currentMonth,
bounds,
editMode,
initialized,
showBudgetDetails
} = this.state;
const {
categories,
categoryGroups,
prefs,
budgetType,
navigation,
applyBudgetAction
} = this.props;
let numberFormat = prefs.numberFormat || 'comma-dot';
if (!categoryGroups || !initialized) {
return (
<View
style={{
flex: 1,
backgroundColor: 'white',
alignItems: 'center',
justifyContent: 'center'
}}
>
<AnimatedLoading width={25} height={25} />
</View>
);
}
return (
<SafeAreaView
edges={['top']}
style={{ flex: 1, backgroundColor: colors.p5 }}
>
<FocusAwareStatusBar barStyle="light-content" />
<SyncRefresh onSync={this.sync}>
{({ refreshing, onRefresh }) => (
<BudgetTable
// This key forces the whole table rerender when the number
// format changes
key={numberFormat}
categories={categories}
categoryGroups={categoryGroups}
type={budgetType}
month={currentMonth}
monthBounds={bounds}
editMode={editMode}
navigation={navigation}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
onEditMode={flag => this.setState({ editMode: flag })}
onShowBudgetDetails={this.onShowBudgetDetails}
onPrevMonth={this.onPrevMonth}
onNextMonth={this.onNextMonth}
onAddCategory={this.onAddCategory}
onReorderCategory={this.onReorderCategory}
onReorderGroup={this.onReorderGroup}
onOpenActionSheet={this.onOpenActionSheet}
onBudgetAction={applyBudgetAction}
/>
)}
</SyncRefresh>
{showBudgetDetails && (
<BudgetSummary
month={currentMonth}
onClose={() => this.setState({ showBudgetDetails: false })}
/>
)}
</SafeAreaView>
);
}
Example #13
Source File: BudgetList.js From actual with MIT License | 5 votes |
render() {
let {
navigation,
files,
loadAllFiles,
getUserData,
showActionSheetWithOptions,
keyId
} = this.props;
return (
<SafeAreaView edges={['bottom']} style={{ flex: 1 }}>
<Modal
title="Select a file"
backgroundColor="white"
allowScrolling={false}
showOverlay={false}
edges={['top']}
rightButton={
<RefreshButton
onRefresh={() => {
getUserData();
loadAllFiles();
}}
/>
}
>
{/* <StatusBar barStyle="light-content" /> */}
<FlatList
data={files}
ListEmptyComponent={EmptyMessage}
renderItem={({ item: file }) => (
<File
file={file}
showActionSheetWithOptions={showActionSheetWithOptions}
onSelect={() => {
if (file.state === 'broken') {
showBrokenMessage(file, showActionSheetWithOptions, () =>
this.onDelete(file)
);
} else if (file.state === 'remote') {
this.props.downloadBudget(file.cloudFileId);
} else {
this.props.loadBudget(file.id);
}
}}
onDelete={this.onDelete}
/>
)}
keyExtractor={item => item.id}
style={{ flex: 1 }}
/>
<View
style={{
alignItems: 'center',
marginHorizontal: 10,
marginVertical: 15,
flexDirection: 'row'
}}
>
<Button primary style={{ flex: 1 }} onPress={() => this.onCreate()}>
New file
</Button>
</View>
</Modal>
<UserButton
navigation={navigation}
keyId={keyId}
onLogOut={() => {
iap.resetUser();
this.props.signOut();
}}
/>
</SafeAreaView>
);
}
Example #14
Source File: index.js From musicont with MIT License | 5 votes |
Index = ({ songs, playlists, navigation }) => {
const [assets] = useAssets([require('../../assets/icons/hamburger.png'), require('../../assets/icons/search.png')]);
const [drawer, setDrawer] = useState(false);
return (
<Drawer active={drawer} current="playlist" onItemPressed={() => setDrawer(false)}>
<SafeAreaView style={styles.container}>
<Header
options={{
left: {
children: drawer ? <Icon name="x" color="#C4C4C4" /> : <Image source={require('../../assets/icons/hamburger.png')} resizeMode="contain" />,
onPress: () => setDrawer(!drawer),
},
middle: {
show: true,
text: 'Playlists',
},
right: {
show: false,
},
}}
/>
{playlists && playlists?.length > 0 ? (
<ScrollView style={{ flex: 1 }} contentContainerStyle={styles.sections} showsVerticalScrollIndicator={false}>
{playlists.map((playlist, key) => (
<Card.Playlist
key={key}
style={styles.item}
overlayStyle={{ height: 200 }}
imageURL={songs[playlist?.songs[0]]?.img}
title={playlist?.name}
subtitle={`${playlist?.songs.length} Songs`}
onPress={() => {
const playlistIndex = playlists.findIndex((i) => i?.name.toLowerCase() === playlist?.name.toLowerCase());
navigation.push(SCREENS.PLAYLIST, { playlistIndex });
}}
/>
))}
</ScrollView>
) : (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 24, fontWeight: 'bold', color: 'rgba(0, 0, 0, .3)' }}>No playlists yet!</Text>
</View>
)}
</SafeAreaView>
</Drawer>
);
}
Example #15
Source File: index.js From musicont with MIT License | 5 votes |
Index = ({ songs }) => {
const { goBack } = useNavigation();
const [audios, setAudios] = useState([]);
const [search, setSearch] = useState('');
const handleInput = (val) => {
const value = val.replace(' ', ' ');
setSearch(value);
if (value.length > 3) {
const results = songs.filter((song) => {
let regex = new RegExp(value, 'ig');
return regex.exec(song?.title) || regex.exec(song?.author);
});
setAudios(results);
} else {
setAudios([]);
}
};
return (
<>
<StatusBar style="dark" />
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<View style={styles.input}>
<Icon name="search" color="#FFF" />
<TextInput style={styles.textInput} onChangeText={handleInput} value={search} returnKeyType="search" placeholder="Search..." />
</View>
<TouchableOpacity style={styles.btn} onPress={() => goBack()}>
<Text style={styles.btnTxt}>Cancel</Text>
</TouchableOpacity>
</View>
<View style={styles.result}>
{audios.length > 0 ? (
<Section.MusicList audios={audios} />
) : (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 24, fontWeight: 'bold', color: 'rgba(0, 0, 0, .3)' }}>Search something...</Text>
</View>
)}
</View>
</SafeAreaView>
</TouchableWithoutFeedback>
</>
);
}
Example #16
Source File: Login.js From actual with MIT License | 5 votes |
function Login({ navigation, createBudget }) {
let [email, setEmail] = useState('');
let [loading, setLoading] = useState(false);
let [error, setError] = useState(null);
async function sendCode() {
setLoading(true);
setError(null);
let { error } = await send('subscribe-send-email-code', { email });
setLoading(false);
if (error) {
setError(getErrorMessage(error));
} else {
navigation.navigate('Confirm', { email });
}
}
let textStyle = [
styles.text,
{ fontSize: 17, lineHeight: 25, color: 'white' }
];
return (
<SafeAreaView style={{ flex: 1 }}>
<KeyboardAvoidingView>
<TransitionView navigation={navigation}>
{/* <StatusBar barStyle="light-content" /> */}
<Header
navigation={navigation}
buttons={['back', 'demo']}
loadDemoBudget={() => {
send('track', { name: 'app:create-demo' });
createBudget({ demoMode: true });
}}
/>
<Stack justify="center" style={{ flex: 1, padding: 20 }} spacing={5}>
<View>
<Text style={textStyle}>
<Text style={{ fontWeight: '700' }}>Sign in.</Text> We
{"'"}
ll email you a code that you can use to log in. You only need to
do this once. Right now, the mobile app works best as a
companion to the desktop app.
</Text>
</View>
<SingleInput
title="Email"
value={email}
loading={loading}
error={error}
inputProps={{
keyboardType: 'email-address',
placeholder: '[email protected]'
}}
onChange={setEmail}
onSubmit={sendCode}
/>
</Stack>
</TransitionView>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
Example #17
Source File: User.js From reddit-clone with MIT License | 5 votes |
User = ({ route }) => {
const { authState } = React.useContext(AuthContext)
const { colors } = useTheme()
const [isLoading, setIsLoaading] = React.useState(false)
const [userPosts, setuserPosts] = React.useState(null)
const username = route.params?.username
const getUserPostDetail = React.useCallback(async () => {
setIsLoaading(true)
const { data } = await axios.get(`user/${username || authState.userInfo.username}`)
setuserPosts(data)
setIsLoaading(false)
}, [authState.userInfo.username, username])
React.useEffect(() => {
getUserPostDetail()
}, [getUserPostDetail])
const deletePost = async (postId, index) => {
setIsLoaading(true)
const { status } = await axios.delete(`post/${postId}`)
if (status === 200) {
setuserPosts(prevData => {
prevData.splice(index, 1)
return prevData
})
}
setIsLoaading(false)
}
return (
<View as={SafeAreaView} style={styles.boxCenter}>
{userPosts ? (
<FlatList
data={userPosts.sort((a, b) => a.created < b.created)}
extraData={isLoading}
refreshing={isLoading}
onRefresh={() => getUserPostDetail()}
keyExtractor={item => item.id}
ListEmptyComponent={
<Text style={[styles.empty, { color: colors.text }]}>Ups! Not found any post!</Text>
}
ListHeaderComponent={<HeaderComponent username={username} postCount={userPosts.length} />}
stickyHeaderIndices={[0]}
ListHeaderComponentStyle={styles.headerComponentStyle}
renderItem={({ item, index }) => (
<Post
index={index}
postId={item.id}
userId={authState.userInfo.id}
score={item.score}
type={item.type}
title={item.title}
author={item.author}
category={item.category}
text={item.text}
comments={item.comments}
created={item.created}
url={item.url}
votes={item.votes}
views={item.views}
setIsLoaading={setIsLoaading}
setData={setuserPosts}
deleteButton={true}
deletePost={() => deletePost(item.id, index)}
/>
)}
/>
) : (
<>
{[1, 2, 3, 4, 5].map(i => (
<PostLoader key={i} />
))}
</>
)}
</View>
)
}
Example #18
Source File: Home.js From reddit-clone with MIT License | 5 votes |
Home = () => {
const { authState } = React.useContext(AuthContext)
const { theme } = React.useContext(ThemeContext)
const { colors } = useTheme()
const [postData, setPostData] = React.useState(null)
const [category, setCategory] = React.useState('all')
const [isLoading, setIsLoaading] = React.useState(false)
const getPostData = React.useCallback(async () => {
setIsLoaading(true)
const { data } = await axios.get(
!category || category === 'all' ? 'posts' : `posts/${category}`
)
setPostData(data)
setIsLoaading(false)
}, [category])
React.useEffect(() => {
getPostData()
}, [getPostData])
return (
<View as={SafeAreaView} style={styles.container}>
<StatusBar
barStyle={theme === 'light' ? 'dark-content' : 'light-content'}
backgroundColor={colors.background}
/>
{postData ? (
<FlatList
data={postData}
extraData={isLoading}
refreshing={isLoading}
onRefresh={() => getPostData()}
keyExtractor={item => item.id}
ListHeaderComponent={
<CategoryPicker selectedCategory={category} onClick={setCategory} addAll />
}
ListHeaderComponentStyle={[styles.categoryPicker, { backgroundColor: colors.bgColor }]}
ListEmptyComponent={
<Text style={[styles.empty, { color: colors.text }]}>Ups! Not found any post!</Text>
}
renderItem={({ item, index }) => (
<Post
index={index}
postId={item.id}
userId={authState.userInfo.id}
score={item.score}
type={item.type}
title={item.title}
author={item.author}
category={item.category}
text={item.text}
comments={item.comments}
created={item.created}
url={item.url}
votes={item.votes}
views={item.views}
setIsLoaading={setIsLoaading}
setData={setPostData}
deleteButton={false}
/>
)}
/>
) : (
<>
<CategoryLoader />
{[1, 2, 3, 4, 5].map(i => (
<PostLoader key={i} />
))}
</>
)}
</View>
)
}
Example #19
Source File: App.js From filen-mobile with GNU Affero General Public License v3.0 | 4 votes |
App = memo(() => {
const [isLoggedIn, setIsLoggedIn] = useMMKVBoolean("isLoggedIn", storage)
const setDimensions = useStore(useCallback(state => state.setDimensions))
const [darkMode, setDarkMode] = useMMKVBoolean("darkMode", storage)
const [setupDone, setSetupDone] = useState(false)
const [currentScreenName, setCurrentScreenName] = useState("MainScreen")
const setCurrentRoutes = useStore(useCallback(state => state.setCurrentRoutes))
const toastBottomOffset = useStore(useCallback(state => state.toastBottomOffset))
const toastTopOffset = useStore(useCallback(state => state.toastTopOffset))
const setNetInfo = useStore(useCallback(state => state.setNetInfo))
const showNavigationAnimation = useStore(useCallback(state => state.showNavigationAnimation))
const [userId, setUserId] = useMMKVNumber("userId", storage)
const [cameraUploadEnabled, setCameraUploadEnabled] = useMMKVBoolean("cameraUploadEnabled:" + userId, storage)
const setBiometricAuthScreenState = useStore(useCallback(state => state.setBiometricAuthScreenState))
const setCurrentShareItems = useStore(useCallback(state => state.setCurrentShareItems))
const setAppState = useStore(useCallback(state => state.setAppState))
const [lang, setLang] = useMMKVString("lang", storage)
const [nodeJSAlive, setNodeJSAlive] = useState(true)
const setContentHeight = useStore(useCallback(state => state.setContentHeight))
const isDeviceReady = useStore(useCallback(state => state.isDeviceReady))
const [startOnCloudScreen, setStartOnCloudScreen] = useMMKVBoolean("startOnCloudScreen:" + userId, storage)
const [userSelectedTheme, setUserSelectedTheme] = useMMKVString("userSelectedTheme", storage)
const [currentDimensions, setCurrentDimensions] = useState({ window: Dimensions.get("window"), screen: Dimensions.get("screen") })
const handleShare = useCallback(async (items) => {
if(!items){
return false
}
if(typeof items !== "undefined"){
if(typeof items.data !== "undefined"){
if(items.data !== null){
if(items.data.length > 0){
await new Promise((resolve) => {
const wait = BackgroundTimer.setInterval(() => {
if(typeof navigationRef !== "undefined"){
const navState = navigationRef.getState()
if(typeof navState !== "undefined"){
if(typeof navState.routes !== "undefined"){
if(navState.routes.filter(route => route.name == "SetupScreen" || route.name == "BiometricAuthScreen" || route.name == "LoginScreen").length == 0){
if(storage.getBoolean("isLoggedIn")){
BackgroundTimer.clearInterval(wait)
return resolve()
}
}
}
}
}
}, 250)
})
let containsValidItems = true
if(Platform.OS == "android"){
if(Array.isArray(items.data)){
for(let i = 0; i < items.data.length; i++){
if(items.data[i].indexOf("file://") == -1 && items.data[i].indexOf("content://") == -1){
containsValidItems = false
}
}
}
else{
if(items.data.indexOf("file://") == -1 && items.data.indexOf("content://") == -1){
containsValidItems = false
}
}
}
else{
for(let i = 0; i < items.data.length; i++){
if(items.data[i].data.indexOf("file://") == -1 && items.data[i].data.indexOf("content://") == -1){
containsValidItems = false
}
}
}
if(containsValidItems){
setCurrentShareItems(items)
showToast({ type: "upload" })
}
else{
showToast({ message: i18n(lang, "shareMenuInvalidType") })
}
}
}
}
}
})
const initBackgroundFetch = useCallback(() => {
BackgroundFetch.configure({
minimumFetchInterval: 15,
requiredNetworkType: BackgroundFetch.NETWORK_TYPE_ANY,
stopOnTerminate: false,
startOnBoot: true,
enableHeadless: false
}, (taskId) => {
console.log("[" + Platform.OS + "] BG fetch running:", taskId)
const waitForInit = (callback) => {
const timeout = (+new Date() + 15000)
const wait = BackgroundTimer.setInterval(() => {
if(timeout > (+new Date())){
if(isLoggedIn && cameraUploadEnabled && setupDone && isDeviceReady){
BackgroundTimer.clearInterval(wait)
return callback(false)
}
}
else{
BackgroundTimer.clearInterval(wait)
return callback(true)
}
}, 10)
}
waitForInit((timedOut) => {
if(timedOut){
console.log("[" + Platform.OS + "] BG fetch timed out:", taskId)
BackgroundFetch.finish(taskId)
}
else{
runCameraUpload({
runOnce: true,
maxQueue: 1,
callback: () => {
console.log("[" + Platform.OS + "] BG fetch done:", taskId)
BackgroundFetch.finish(taskId)
}
})
}
})
}, (taskId) => {
console.log("[" + Platform.OS + "] BG fetch timeout:", taskId)
BackgroundFetch.finish(taskId)
}).then((status) => {
console.log("[" + Platform.OS + "] BG fetch init status:", status)
}).catch((err) => {
console.log("[" + Platform.OS + "] BG fetch init error:", err)
})
})
const setAppearance = useCallback(() => {
BackgroundTimer.setTimeout(() => {
if(typeof userSelectedTheme == "string" && userSelectedTheme.length > 1){
if(userSelectedTheme == "dark"){
setDarkMode(true)
setStatusBarStyle(true)
}
else{
setDarkMode(false)
setStatusBarStyle(false)
}
}
else{
if(Appearance.getColorScheme() == "dark"){
setDarkMode(true)
setStatusBarStyle(true)
}
else{
setDarkMode(false)
setStatusBarStyle(false)
}
}
}, 1000) // We use a timeout due to the RN appearance event listener firing both "dark" and "light" on app resume which causes the screen to flash for a second
})
useEffect(() => {
if(isLoggedIn && cameraUploadEnabled && setupDone){
runCameraUpload({
maxQueue: 10,
runOnce: false,
callback: undefined
})
}
}, [isLoggedIn, cameraUploadEnabled, setupDone])
useEffect(() => {
initBackgroundFetch()
//global.nodeThread.pingPong(() => {
// setNodeJSAlive(false)
//})
NetInfo.fetch().then((state) => {
setNetInfo(state)
}).catch((err) => {
console.log(err)
})
//BackgroundTimer.start()
const appStateListener = AppState.addEventListener("change", (nextAppState) => {
setAppState(nextAppState)
if(nextAppState == "background"){
if(Math.floor(+new Date()) > storage.getNumber("biometricPinAuthTimeout:" + userId) && storage.getBoolean("biometricPinAuth:" + userId)){
setBiometricAuthScreenState("auth")
storage.set("biometricPinAuthTimeout:" + userId, (Math.floor(+new Date()) + 500000))
navigationRef.current.dispatch(StackActions.push("BiometricAuthScreen"))
}
}
if(nextAppState == "active"){
checkAppVersion({ navigation: navigationRef })
}
})
const netInfoListener = NetInfo.addEventListener((state) => {
setNetInfo(state)
})
const dimensionsListener = Dimensions.addEventListener("change", ({ window, screen }) => {
setDimensions({ window, screen })
setCurrentDimensions({ window, screen })
})
const navigationRefListener = navigationRef.addListener("state", (event) => {
if(typeof event.data !== "undefined"){
if(typeof event.data.state !== "undefined"){
if(typeof event.data.state.routes !== "undefined"){
//console.log("Current Screen:", event.data.state.routes[event.data.state.routes.length - 1].name, event.data.state.routes[event.data.state.routes.length - 1].params)
setCurrentScreenName(event.data.state.routes[event.data.state.routes.length - 1].name)
setCurrentRoutes(event.data.state.routes)
}
}
}
})
ShareMenu.getInitialShare(handleShare)
const shareMenuListener = ShareMenu.addNewShareListener(handleShare)
setAppearance()
const appearanceListener = Appearance.addChangeListener(() => {
setAppearance()
})
if(isLoggedIn && !setupDone){
setup({ navigation: navigationRef }).then(() => {
setSetupDone(true)
if(storage.getBoolean("biometricPinAuth:" + userId)){
setBiometricAuthScreenState("auth")
storage.set("biometricPinAuthTimeout:" + userId, (Math.floor(+new Date()) + 500000))
navigationRef.current.dispatch(StackActions.push("BiometricAuthScreen"))
}
else{
navigationRef.current.dispatch(CommonActions.reset({
index: 0,
routes: [
{
name: "MainScreen",
params: {
parent: startOnCloudScreen ? (storage.getBoolean("defaultDriveOnly:" + userId) ? storage.getString("defaultDriveUUID:" + userId) : "base") : "recents"
}
}
]
}))
}
}).catch((err) => {
console.log(err)
if(typeof storage.getString("masterKeys") == "string" && typeof storage.getString("apiKey") == "string" && typeof storage.getString("privateKey") == "string" && typeof storage.getString("publicKey") == "string" && typeof storage.getNumber("userId") == "number"){
if(storage.getString("masterKeys").length > 16 && storage.getString("apiKey").length > 16 && storage.getString("privateKey").length > 16 && storage.getString("publicKey").length > 16 && storage.getNumber("userId") !== 0){
setSetupDone(true)
if(storage.getBoolean("biometricPinAuth:" + userId)){
setBiometricAuthScreenState("auth")
storage.set("biometricPinAuthTimeout:" + userId, (Math.floor(+new Date()) + 500000))
navigationRef.current.dispatch(StackActions.push("BiometricAuthScreen"))
}
else{
navigationRef.current.dispatch(CommonActions.reset({
index: 0,
routes: [
{
name: "MainScreen",
params: {
parent: startOnCloudScreen ? (storage.getBoolean("defaultDriveOnly:" + userId) ? storage.getString("defaultDriveUUID:" + userId) : "base") : "recents"
}
}
]
}))
}
}
else{
setSetupDone(false)
showToast({ message: i18n(lang, "appSetupNotPossible") })
}
}
else{
setSetupDone(false)
showToast({ message: i18n(lang, "appSetupNotPossible") })
}
})
}
// Reset on app launch
storage.set("cameraUploadRunning", false)
return () => {
dimensionsListener.remove()
shareMenuListener.remove()
navigationRef.removeListener(navigationRefListener)
navigationRefListener()
appearanceListener.remove()
netInfoListener()
appStateListener.remove()
}
}, [])
return (
<>
<NavigationContainer ref={navigationRef}>
<Fragment>
<SafeAreaProvider style={{
backgroundColor: darkMode ? "black" : "white",
}}>
<SafeAreaView mode="padding" style={{
backgroundColor: currentScreenName == "ImageViewerScreen" ? "black" : (darkMode ? "black" : "white"),
paddingTop: Platform.OS == "android" ? 5 : 5,
height: "100%",
width: "100%"
}}>
<View style={{
width: currentScreenName == "ImageViewerScreen" ? currentDimensions.screen.width : "100%",
height: currentScreenName == "ImageViewerScreen" ? currentDimensions.screen.height : "100%",
backgroundColor: darkMode ? "black" : "white"
}} onLayout={(e) => setContentHeight(e.nativeEvent.layout.height)}>
{
nodeJSAlive ? (
<>
<Stack.Navigator initialRouteName={isLoggedIn ? (setupDone ? "MainScreen" : "SetupScreen") : "LoginScreen"} screenOptions={{
contentStyle: {
backgroundColor: darkMode ? "black" : "white"
},
headerStyle: {
backgroundColor: darkMode ? "black" : "white"
},
headerShown: false,
animation: showNavigationAnimation ? "default" : "none"
}}>
<Stack.Screen name="SetupScreen" component={SetupScreen} options={{
title: "SetupScreen"
}}></Stack.Screen>
<Stack.Screen name="LoginScreen" options={{
title: "LoginScreen"
}}>{(props) => <LoginScreen {...props} setSetupDone={setSetupDone} />}</Stack.Screen>
<Stack.Screen name="RegisterScreen" component={RegisterScreen} options={{
title: "RegisterScreen"
}}></Stack.Screen>
<Stack.Screen name="ForgotPasswordScreen" component={ForgotPasswordScreen} options={{
title: "ForgotPasswordScreen"
}}></Stack.Screen>
<Stack.Screen name="ResendConfirmationScreen" component={ResendConfirmationScreen} options={{
title: "ResendConfirmationScreen"
}}></Stack.Screen>
<Stack.Screen name="MainScreen" initialParams={{ parent: startOnCloudScreen ? (storage.getBoolean("defaultDriveOnly:" + userId) ? storage.getString("defaultDriveUUID:" + userId) : "base") : "recents" }} component={MainScreen} options={{
title: "MainScreen"
}}></Stack.Screen>
<Stack.Screen name="SettingsScreen" component={SettingsScreen} options={{
title: "SettingsScreen"
}}></Stack.Screen>
<Stack.Screen name="TransfersScreen" component={TransfersScreen} options={{
title: "TransfersScreen"
}}></Stack.Screen>
<Stack.Screen name="CameraUploadScreen" component={CameraUploadScreen} options={{
title: "CameraUploadScreen"
}}></Stack.Screen>
<Stack.Screen name="BiometricAuthScreen" component={BiometricAuthScreen} options={{
title: "BiometricAuthScreen"
}}></Stack.Screen>
<Stack.Screen name="LanguageScreen" component={LanguageScreen} options={{
title: "LanguageScreen"
}}></Stack.Screen>
<Stack.Screen name="SettingsAdvancedScreen" component={SettingsAdvancedScreen} options={{
title: "SettingsAdvancedScreen"
}}></Stack.Screen>
<Stack.Screen name="SettingsAccountScreen" component={SettingsAccountScreen} options={{
title: "SettingsAccountScreen"
}}></Stack.Screen>
<Stack.Screen name="EventsScreen" component={EventsScreen} options={{
title: "EventsScreen"
}}></Stack.Screen>
<Stack.Screen name="EventsInfoScreen" component={EventsInfoScreen} options={{
title: "EventsInfoScreen"
}}></Stack.Screen>
<Stack.Screen name="GDPRScreen" component={GDPRScreen} options={{
title: "GDPRScreen"
}}></Stack.Screen>
<Stack.Screen name="InviteScreen" component={InviteScreen} options={{
title: "InviteScreen"
}}></Stack.Screen>
<Stack.Screen name="TwoFactorScreen" component={TwoFactorScreen} options={{
title: "TwoFactorScreen"
}}></Stack.Screen>
<Stack.Screen name="ChangeEmailPasswordScreen" component={ChangeEmailPasswordScreen} options={{
title: "ChangeEmailPasswordScreen"
}}></Stack.Screen>
<Stack.Screen name="TextEditorScreen" component={TextEditorScreen} options={{
title: "TextEditorScreen"
}}></Stack.Screen>
<Stack.Screen name="UpdateScreen" component={UpdateScreen} options={{
title: "UpdateScreen"
}}></Stack.Screen>
<Stack.Screen name="ImageViewerScreen" component={ImageViewerScreen} options={{
title: "ImageViewerScreen",
presentation: "fullScreenModal"
}}></Stack.Screen>
</Stack.Navigator>
<>
{
setupDone && isLoggedIn && ["MainScreen", "SettingsScreen", "TransfersScreen", "CameraUploadScreen", "EventsScreen", "EventsInfoScreen", "SettingsAdvancedScreen", "SettingsAccountScreen", "LanguageScreen", "GDPRScreen", "InviteScreen", "TwoFactorScreen", "ChangeEmailPasswordScreen"].includes(currentScreenName) && (
<View style={{
position: "relative",
width: "100%",
bottom: 0,
height: 50
}}>
<BottomBar navigation={navigationRef} currentScreenName={currentScreenName} />
</View>
)
}
</>
</>
) : (
<View style={{
width: "100%",
height: "100%",
justifyContent: "center",
alignItems: "center"
}}>
<Ionicon name="information-circle-outline" size={70} color={darkMode ? "white" : "black"} />
<Text style={{
color: darkMode ? "white" : "black",
marginTop: 5,
width: "70%",
textAlign: "center"
}}>
{i18n(lang, "nodeJSProcessDied")}
</Text>
</View>
)
}
{
nodeJSAlive && (
<>
<TransfersIndicator navigation={navigationRef} />
<TopBarActionSheet navigation={navigationRef} />
<BottomBarAddActionSheet navigation={navigationRef} />
<ItemActionSheet navigation={navigationRef} />
<FolderColorActionSheet navigation={navigationRef} />
<PublicLinkActionSheet navigation={navigationRef} />
<ShareActionSheet navigation={navigationRef} />
<FileVersionsActionSheet navigation={navigationRef} />
<ProfilePictureActionSheet navigation={navigationRef} />
<SortByActionSheet navigation={navigationRef} />
</>
)
}
</View>
</SafeAreaView>
</SafeAreaProvider>
{
nodeJSAlive && (
<>
<Disable2FATwoFactorDialog navigation={navigationRef} />
<DeleteAccountTwoFactorDialog navigation={navigationRef} />
<RedeemCodeDialog navigation={navigationRef} />
<ConfirmStopSharingDialog navigation={navigationRef} />
<ConfirmRemoveFromSharedInDialog navigation={navigationRef} />
<ConfirmPermanentDeleteDialog navigation={navigationRef} />
<RenameDialog navigation={navigationRef} />
<CreateFolderDialog navigation={navigationRef} />
<CreateTextFileDialog navigation={navigationRef} />
<BulkShareDialog navigation={navigationRef} />
<FullscreenLoadingModal navigation={navigationRef} />
</>
)
}
</Fragment>
</NavigationContainer>
<Toast
ref={(ref) => global.toast = ref}
offsetBottom={toastBottomOffset}
offsetTop={toastTopOffset}
pointerEvents="box-none"
style={{
zIndex: 99999
}}
/>
</>
)
})
Example #20
Source File: CharacterScreen.js From hero with MIT License | 4 votes |
CharacterScreen = ({ route, navigation }) => {
const {
hero,
image,
publisher,
comicPicture,
summary,
firstIssue,
firstIssueURL,
} = route.params;
let publisherLogo = null;
let logoShape = null;
// let firstIssueID = null;
if (publisher === "Marvel Comics" || publisher === "Marvel") {
publisherLogo = require(`../assets/images/Marvel-Logo.jpg`);
logoShape = styles.publisherLogoRectangle;
} else if (publisher === "DC Comics") {
publisherLogo = require(`../assets/images/DC-Logo.png`);
logoShape = styles.publisherLogoSquare;
}
const activeLightboxProps = {
resizeMode: "contain",
marginHorizontal: 20,
flex: 1,
width: null,
};
// if (comicPicture) {
// comicPictureURL = require(comicPicture);
// }
function searchComic(firstComic) {
fetch(
`https://comicvine.gamespot.com/api/characters/?api_key=${apiComic.key}&sort=deck:desc&filter=name:${hero.name}&format=json`
)
.then((res) => {
if (res.status === 404) {
throw new Error("I didn't find this hero. Please try again!");
} else {
return res.json();
}
})
.then((result) => {
console.log("====================================");
console.log("NEW SEARCH");
console.log("====================================");
console.log(result.results);
});
}
function searchFirstComic() {
fetch(
`https://comicvine.gamespot.com/api/issue/4000-${firstIssue.id}/?api_key=${apiComic.key}&format=json`
)
.then((res) => {
if (res.status === 404) {
throw new Error("I didn't find this hero. Please try again!");
} else {
return res.json();
}
})
.then((result) => {
console.log("FIRST ISSUE DETAILS");
console.log(result.results.image.original_url);
// comicPicture = require(result.results[0].image.original_url);
// summary = result.results[0].deck;
});
}
// useEffect(() => {
// // console.log(publisherVine);
// // searchComic(hero.biography["first-appearance"]);
// // searchFirstComic();
// }, []);
return (
<View style={styles.appContainer}>
<StatusBar
translucent
backgroundColor="transparent"
barStyle="dark-content"
/>
<SafeAreaView
style={{ flex: 1, backgroundColor: "transparent" }}
forceInset={{ top: "always" }}
>
<Header title={""} backbutton={true} navigation={navigation} />
<Image source={image} style={styles.heroImage} />
<LinearGradient
colors={["#ffffff00", COLORS.beige]}
style={styles.bottomFade}
locations={[0.3, 1]}
/>
<View style={styles.heroInfoContainer}>
<View style={styles.heroTitleContainer}>
<Text style={styles.heroTitle}>{hero.name}</Text>
<View style={styles.heroHeader}>
<Text style={{ ...styles.h4, marginLeft: 3, fontSize: 16 }}>
{hero.biography["full-name"]}
</Text>
<Image source={publisherLogo} style={logoShape} />
</View>
</View>
<Divider
orientation="horizontal"
width={3}
style={{ ...styles.divider, marginBottom: 0 }}
color={COLORS.navy}
/>
<ScrollView
style={{ height: 340 }}
contentContainerStyle={{
width: "100%",
paddingBottom: 40,
marginTop: 10,
}}
showsVerticalScrollIndicator={false}
>
<Text
style={{
...styles.p,
fontSize: 12,
marginBottom: 20,
lineHeight: 18,
}}
>
{summary}
</Text>
{/********** STATS DETAILS ***************/}
<View
style={{
flexDirection: "row",
flexWrap: "wrap",
justifyContent: "space-around",
alignItems: "center",
// backgroundColor: COLORS.grey,
borderRadius: 20,
// padding: 10,
marginBottom: 10,
}}
>
<View
style={{
alignItems: "center",
justifyContent: "center",
padding: 5,
}}
>
<AnimatedCircularProgress
size={60}
width={10}
duration={2000}
backgroundWidth={8}
rotation={-124}
arcSweepAngle={250}
fill={Number(hero.powerstats.intelligence)}
tintColor={COLORS.red}
tintColorSecondary={COLORS.green}
// onAnimationComplete={() => console.log("onAnimationComplete")}
backgroundColor={COLORS.navy}
padding={0}
lineCap={"round"}
// renderCap={({ center }) => (
// <Circle cx={center.x} cy={center.y} r="10" fill="blue" />
// )}
>
{(fill) => (
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
left: 1,
}}
>
{Math.floor(fill)}
</Text>
)}
</AnimatedCircularProgress>
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
fontSize: 10,
marginTop: -10,
}}
>
Intelligence
</Text>
</View>
<View
style={{
alignItems: "center",
justifyContent: "center",
padding: 5,
}}
>
<AnimatedCircularProgress
size={60}
width={10}
duration={2000}
backgroundWidth={8}
rotation={-124}
arcSweepAngle={250}
fill={Number(hero.powerstats.strength)}
tintColor={COLORS.red}
tintColorSecondary={COLORS.green}
// onAnimationComplete={() => console.log("onAnimationComplete")}
backgroundColor={COLORS.navy}
padding={0}
lineCap={"round"}
// renderCap={({ center }) => (
// <Circle cx={center.x} cy={center.y} r="10" fill="blue" />
// )}
>
{(fill) => (
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
left: 1,
}}
>
{Math.floor(fill)}
</Text>
)}
</AnimatedCircularProgress>
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
fontSize: 10,
marginTop: -10,
}}
>
Strength
</Text>
</View>
<View
style={{
alignItems: "center",
justifyContent: "center",
padding: 5,
}}
>
<AnimatedCircularProgress
size={60}
width={10}
duration={2000}
backgroundWidth={8}
rotation={-124}
arcSweepAngle={250}
fill={Number(hero.powerstats.speed)}
tintColor={COLORS.red}
tintColorSecondary={COLORS.green}
// onAnimationComplete={() => console.log("onAnimationComplete")}
backgroundColor={COLORS.navy}
padding={0}
lineCap={"round"}
// renderCap={({ center }) => (
// <Circle cx={center.x} cy={center.y} r="10" fill="blue" />
// )}
>
{(fill) => (
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
left: 1,
}}
>
{Math.floor(fill)}
</Text>
)}
</AnimatedCircularProgress>
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
fontSize: 10,
marginTop: -10,
}}
>
Speed
</Text>
</View>
<View
style={{
alignItems: "center",
justifyContent: "center",
padding: 5,
}}
>
<AnimatedCircularProgress
size={60}
width={10}
duration={2000}
backgroundWidth={8}
rotation={-124}
arcSweepAngle={250}
fill={Number(hero.powerstats.durability)}
tintColor={COLORS.red}
tintColorSecondary={COLORS.green}
// onAnimationComplete={() => console.log("onAnimationComplete")}
backgroundColor={COLORS.navy}
padding={0}
lineCap={"round"}
// renderCap={({ center }) => (
// <Circle cx={center.x} cy={center.y} r="10" fill="blue" />
// )}
>
{(fill) => (
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
left: 1,
}}
>
{Math.floor(fill)}
</Text>
)}
</AnimatedCircularProgress>
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
fontSize: 10,
marginTop: -10,
}}
>
Durability
</Text>
</View>
<View
style={{
alignItems: "center",
justifyContent: "center",
padding: 5,
}}
>
<AnimatedCircularProgress
size={60}
width={10}
duration={2000}
backgroundWidth={8}
rotation={-124}
arcSweepAngle={250}
fill={Number(hero.powerstats.power)}
tintColor={COLORS.red}
tintColorSecondary={COLORS.green}
// onAnimationComplete={() => console.log("onAnimationComplete")}
backgroundColor={COLORS.navy}
padding={0}
lineCap={"round"}
// renderCap={({ center }) => (
// <Circle cx={center.x} cy={center.y} r="10" fill="blue" />
// )}
>
{(fill) => (
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
left: 1,
}}
>
{Math.floor(fill)}
</Text>
)}
</AnimatedCircularProgress>
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
fontSize: 10,
marginTop: -10,
}}
>
Power
</Text>
</View>
<View
style={{
alignItems: "center",
justifyContent: "center",
padding: 5,
}}
>
<AnimatedCircularProgress
size={60}
width={10}
duration={2000}
backgroundWidth={8}
rotation={-124}
arcSweepAngle={250}
fill={Number(hero.powerstats.combat)}
tintColor={COLORS.red}
tintColorSecondary={COLORS.green}
// onAnimationComplete={() => console.log("onAnimationComplete")}
backgroundColor={COLORS.navy}
padding={0}
lineCap={"round"}
// renderCap={({ center }) => (
// <Circle cx={center.x} cy={center.y} r="10" fill="blue" />
// )}
>
{(fill) => (
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
left: 1,
}}
>
{Math.floor(fill)}
</Text>
)}
</AnimatedCircularProgress>
<Text
style={{
...styles.p,
fontFamily: "Flame-Regular",
fontSize: 10,
marginTop: -10,
}}
>
Combat
</Text>
</View>
</View>
{/********** BIOGRAPHY DETAILS ***************/}
<View style={styles.heroDetailsContainer}>
<Text style={{ ...styles.h2 }}>Biography</Text>
<Divider
orientation="horizontal"
width={2}
inset={true}
style={styles.divider}
color={COLORS.navy}
/>
{Object.entries(hero.biography).map(([key, value, index]) => {
// console.log(`${key}: ${value}`);
let str = value.toString();
if (
key != "full-name" &&
key != "place-of-birth" &&
key != "first-appearance" &&
key != "alter-egos" &&
"No alter egos found."
) {
str = str.replace(/,|;\s*(?![^()]*\))/g, "\n\u2022 ");
}
return (
<View
key={index}
style={{
flexDirection:
key == "aliases" || key == "alter-egos"
? "column"
: "row",
justifyContent: "space-between",
alignItems: "flex-start",
flexWrap: "wrap",
marginBottom: 5,
}}
>
<Text style={styles.h4}>{key}:</Text>
{str.split(`/,[s]*/g, ", "`).map((value) => (
<Text
style={{ ...styles.p, textTransform: "capitalize" }}
>
{key == "alter-egos" || key == "aliases"
? "\u2022 " + value
: value && value == "-"
? "unknown"
: value}
</Text>
))}
</View>
);
})}
</View>
{/********** COMIC PICTURE ***************/}
<View style={styles.comicPictureContainer}>
{firstIssueURL ? (
<Lightbox
// renderHeader={() => {
// return (
// <View
// style={{
// justifyContent: "center",
// alignItems: "flex-start",
// paddingHorizontal: 15,
// top: 70,
// }}
// >
// <Text
// style={{ ...styles.heroTitle, color: COLORS.beige }}
// >
// First Issue
// </Text>
// </View>
// );
// }}
activeProps={activeLightboxProps}
>
<Image
source={{
uri: firstIssueURL,
}}
style={styles.comicPicture}
/>
</Lightbox>
) : (
<Text style={styles.h4}>NO PICTURE</Text>
)}
</View>
{/********** APPEARANCE DETAILS ***************/}
<View style={styles.heroDetailsContainer}>
<Text style={{ ...styles.h2 }}>Appearence</Text>
<Divider
orientation="horizontal"
width={2}
inset={true}
style={styles.divider}
color={COLORS.navy}
/>
{Object.entries(hero.appearance).map(([key, value, index]) => {
// console.log(`${key}: ${value}`);
const str = value.toString();
return (
<View
key={index}
style={{
flexDirection: "row",
justifyContent: "space-between",
alignItems: "stretch",
flexWrap: "wrap",
}}
>
<Text style={styles.h4}>{key}:</Text>
<Text style={{ ...styles.p, marginTop: -2 }}>
{str
.split(`/,[s]*/g, ", "`)
.map((value) =>
str.includes(",") ? (
<Text>{value.replace(/,(?=[^\s])/g, ", ")}</Text>
) : (
<Text>{value}</Text>
)
)}
</Text>
</View>
);
})}
</View>
{/********** WORK DETAILS ***************/}
<View style={styles.heroDetailsContainer}>
<Text style={{ ...styles.h2 }}>Work</Text>
<Divider
orientation="horizontal"
width={2}
inset={true}
style={styles.divider}
color={COLORS.navy}
/>
{Object.entries(hero.work).map(([key, value, index]) => {
// console.log(`${key}: ${value}`);
let str = value;
if (key != "base") {
str = str.replace(/,|;\s*(?![^()]*\))/g, "\n\u2022 ");
}
return (
<View
key={index}
style={{
flexDirection: key == "base" ? "row" : "column",
justifyContent: "space-between",
alignItems: key == "base" ? "stretch" : "flex-start",
flexWrap: "wrap",
marginBottom: 5,
}}
>
<Text style={{ ...styles.h4, marginBottom: 4 }}>
{key}:
</Text>
{str.split(`/,[s]*/g, ", "`).map((value) => (
<Text
style={{
...styles.p,
textTransform: "capitalize",
lineHeight: key == "occupation" ? 20 : 0,
marginTop: -2,
}}
>
{key == "base"
? value
: "\u2022 " + value && value != "-"
? "\u2022 " + value
: "unknown"}
</Text>
))}
</View>
);
})}
</View>
{/********** CONNECTIONS DETAILS ***************/}
<View style={styles.heroDetailsContainer}>
<Text style={{ ...styles.h2 }}>Connections</Text>
<Divider
orientation="horizontal"
width={2}
inset={true}
style={styles.divider}
color={COLORS.navy}
/>
{Object.entries(hero.connections).map(([key, value, index]) => {
// console.log(`${key}: ${value}`);
let str = value.toString();
if (key == "group-affiliation") {
str = value.replace(/,|;\s*(?![^()]*\))/g, "\n\u2022 ");
} else {
str = value.replace(/,|;\s*(?![^()]*\))/g, "\n\u2022 ");
}
// const firstLetter = str.charAt(0).toUpperCase() + str.slice(1);
return (
<View
key={index}
style={{
flexDirection: "column",
justifyContent: "space-between",
alignItems: "flex-start",
flexWrap: "wrap",
marginBottom: 5,
}}
>
<Text style={styles.h4}>{key}:</Text>
{str.split(`/,[s]*/g, ", "`).map((value) => (
<Text
style={{
...styles.p,
textTransform: "capitalize",
lineHeight: 24,
}}
>
{value != "-" ? "\u2022 " + value : "unknown"}
</Text>
))}
</View>
);
})}
</View>
</ScrollView>
<LinearGradient
colors={["#ffffff00", COLORS.beige]}
style={styles.bottomFadeInfo}
locations={[0.8, 1]}
pointerEvents={"none"}
/>
</View>
</SafeAreaView>
</View>
);
}
Example #21
Source File: App.js From redis-examples with MIT License | 4 votes |
render(){
this.height = Math.round(Dimensions.get('screen').height);
this.width = Math.round(Dimensions.get('screen').width);
return (
<SafeAreaView style={{
width: this.width,
height: this.height,
flex: 1,
alignItems: 'center'}}>
<StatusBar
backgroundColor="#f4511e"/>
<View style={{height: this.height/8}} />
<View
style={{
flex:1,
width: this.width,
alignItems: 'center',
justifyContent: 'center',
}}>
<View
style={{
flex:1,
width: this.width,
alignItems: 'center',
justifyContent: 'center',
}}>
<TextInput
spellCheck={false}
autoCorrect={false}
placeholderTextColor="rgba(0,0,0,0.4)"
placeholder={"First name"}
style={{
width: this.width*7/10,
borderColor: 'purple',
borderWidth: 1,
borderRadius: 8
}}
onChangeText={(text) =>
this.setState({firstname: text})
}></TextInput>
</View>
<View
style={{
flex:1,
width: this.width,
alignItems: 'center',
justifyContent: 'center',
}}>
<TextInput
spellCheck={false}
autoCorrect={false}
placeholderTextColor="rgba(0,0,0,0.4)"
placeholder={"Last name"}
style={{
width: this.width*7/10,
borderColor: 'purple',
borderWidth: 1,
borderRadius: 8
}}
onChangeText={(text) =>
this.setState({lastname: text})
}></TextInput>
</View>
<View
style={{
flex:1,
width: this.width,
alignItems: 'center',
justifyContent: 'center',
}}>
<TextInput
spellCheck={false}
autoCorrect={false}
placeholderTextColor="rgba(0,0,0,0.4)"
placeholder={"Score"}
style={{
width: this.width*7/10,
borderColor: 'purple',
borderWidth: 1,
borderRadius: 8
}}
onChangeText={(text) =>
this.setState({score: text})
}></TextInput>
</View>
</View>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<TouchableHighlight
style={{backgroundColor: "green", alignItems: 'center', borderColor: "green",
borderRadius: 8, borderWidth: 1, paddingVertical: 10, paddingHorizontal: 20}}
onPress={() =>{this.addScore()}}>
<Text style={{color:"white"}}>Submit Score</Text>
</TouchableHighlight>
</View>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<TouchableHighlight
style={{backgroundColor: "#2196F3", alignItems: 'center', borderColor: "#2196F3",
borderRadius: 8, borderWidth: 1, paddingVertical: 10, paddingHorizontal: 20}}
onPress={() =>{this.props.navigation.navigate('Leaderboard')}}>
<Text style={{color:"white"}}>Go to Leaderboard</Text>
</TouchableHighlight>
</View>
</SafeAreaView>
);
}
Example #22
Source File: Confirm.js From actual with MIT License | 4 votes |
function Confirm({ route, navigation, getUserData, loginUser, createBudget }) {
let [code, setCode] = useState('');
let [loading, setLoading] = useState(false);
let [error, setError] = useState(null);
let { signingUp } = route.params || {};
async function onConfirm() {
let { email } = route.params || {};
setLoading(true);
let { confirmed, error, userId, key, validSubscription } = await send(
'subscribe-confirm',
{ email, code }
);
if (error) {
setLoading(false);
setError(getErrorMessage(error));
} else if (!confirmed) {
setLoading(false);
setError(getErrorMessage('not-confirmed'));
} else if (!validSubscription) {
if (Platform.OS === 'ios') {
// Eagerly load in the offerings (otherwise the subscribe button
// shows a loading state which is weird)
await setupPurchases({ id: userId, email: email });
await getOfferings();
setLoading(false);
navigation.navigate('Subscribe', { email, userId, key });
} else {
// This is a "half-created" account, right now on Android we
// don't fix it here, we just tell the user. This is super
// rare - only happens if a user on iOS creates an account but
// doesn't subscribe, and then tries to log in on Android with
// that account
alert(
'An error occurred loading your account. Please contact [email protected] for support'
);
setLoading(false);
}
} else {
setLoading(false);
// This will load the user in the backend and rerender the app
// in the logged in state
loginUser(userId, key);
if (global.SentryClient) {
global.SentryClient.setUser({
id: userId,
ip_address: '{{auto}}'
});
}
}
}
let textStyle = [
styles.text,
{ fontSize: 17, lineHeight: 25, color: 'white' }
];
return (
<SafeAreaView style={{ flex: 1 }}>
<KeyboardAvoidingView>
<TransitionView navigation={navigation}>
<Header
navigation={navigation}
buttons={['back', 'demo']}
loadDemoBudget={() => createBudget({ demoMode: true })}
/>
<Stack justify="center" style={{ flex: 1, padding: 20 }} spacing={5}>
<View>
{signingUp ? (
<Text style={textStyle}>
Enter the code you got in your email to activate your account:
</Text>
) : (
<Text style={textStyle}>
Enter the code you got in your email:
</Text>
)}
</View>
<SingleInput
title="Code"
value={code}
loading={loading}
error={error}
inputProps={{ keyboardType: 'numeric' }}
onChange={setCode}
onSubmit={onConfirm}
/>
</Stack>
</TransitionView>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
Example #23
Source File: index.js From tcap-mobile with GNU General Public License v3.0 | 4 votes |
render() {
return (
<SafeAreaView style={styles.wrapper}>
<StatusBarColor
backgroundColor={Colors.primary_bg}
barStyle="light-content"
/>
{!this.state.disableBackButton && (
<View style={styles.backButtonWrapper}>
<TouchableOpacity
onPress={this.navigateBack}
style={styles.backButton}>
<Icon
color={Colors.title}
name={'angle-left'}
size={24}
style={{alignSelf: 'center'}}
/>
</TouchableOpacity>
</View>
)}
<View style={styles.container}>
{this.state.mode === PIN_SCREEN_MODE.LOGIN_PIN && (
<View style={styles.recoverButtonWrapper}>
<TouchableOpacity
onPress={this.navigateToRecoverAccount.bind(this)}>
<Text style={styles.recoverAccount}>Recover Account</Text>
</TouchableOpacity>
</View>
)}
<View style={styles.headerContainer}>
<View style={styles.titleWrapper}>
<Text style={styles.title}>{this.getTitle()}</Text>
</View>
<View style={styles.pinWrapper}>
<View style={this.getCircleStyle(1)} />
<View style={this.getCircleStyle(2)} />
<View style={this.getCircleStyle(3)} />
<View style={this.getCircleStyle(4)} />
<View style={this.getCircleStyle(5)} />
<View style={this.getCircleStyle(6)} />
</View>
</View>
</View>
<View style={styles.keyPadContainer}>
<Image
source={require('../../../../assets/images/backgrounds/pin-pattern.png')}
style={styles.keyPadImage}
/>
<View style={styles.keyPadWrapper}>
<View style={styles.keyRow}>
<TouchableOpacity
onPress={() => this.onButtonPress('1')}
style={styles.key}>
<Text style={styles.keyStyle}>1</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.onButtonPress('2')}
style={styles.key}>
<Text style={styles.keyStyle}>2</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.onButtonPress('3')}
style={styles.key}>
<Text style={styles.keyStyle}>3</Text>
</TouchableOpacity>
</View>
<View style={styles.keyRow}>
<TouchableOpacity
onPress={() => this.onButtonPress('4')}
style={styles.key}>
<Text style={styles.keyStyle}>4</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.onButtonPress('5')}
style={styles.key}>
<Text style={styles.keyStyle}>5</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.onButtonPress('6')}
style={styles.key}>
<Text style={styles.keyStyle}>6</Text>
</TouchableOpacity>
</View>
<View style={styles.keyRow}>
<TouchableOpacity
onPress={() => this.onButtonPress('7')}
style={styles.key}>
<Text style={styles.keyStyle}>7</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.onButtonPress('8')}
style={styles.key}>
<Text style={styles.keyStyle}>8</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => this.onButtonPress('9')}
style={styles.key}>
<Text style={styles.keyStyle}>9</Text>
</TouchableOpacity>
</View>
<View style={styles.keyRow}>
<View style={styles.key} />
<TouchableOpacity
onPress={() => this.onButtonPress('0')}
style={styles.key}>
<Text style={styles.keyStyle}>0</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.deleteKeyPress}
style={styles.key}>
<Icon
color="#fff"
name={'backspace'}
size={22}
style={{alignSelf: 'center'}}
/>
</TouchableOpacity>
</View>
</View>
</View>
<LoadingIndicator
message={this.state.loadingMessage}
visible={this.state.isLoading}
/>
<ErrorDialog
message={this.state.errorMessage}
onDismiss={() => {
this.setState({showError: false});
}}
title={this.state.errorTitle}
visible={this.state.showError}
/>
</SafeAreaView>
);
}
Example #24
Source File: SignUp.js From reddit-clone with MIT License | 4 votes |
SignUp = ({ navigation }) => {
const { setStorage } = React.useContext(AuthContext)
const { colors } = useTheme()
const [isLoading, setIsLoading] = React.useState(false)
return (
<KeyboardAvoidingView behavior="padding" style={{ flex: 1 }}>
<Formik
initialValues={{ username: '', password: '', passwordConfirmation: '' }}
onSubmit={async (values, { setStatus, resetForm }) => {
try {
const { data } = await axios.post('signup', values)
const { token, expiresAt, userInfo } = data
setStorage(token, expiresAt, userInfo)
navigation.navigate('Home')
resetForm({})
} catch (error) {
setStatus(error.response.data.message)
}
}}
validationSchema={Yup.object({
username: Yup.string()
.required('Required')
.max(32, 'Must be at most 32 characters long')
.matches(/^[a-zA-Z0-9_-]+$/, 'Contains invalid characters'),
password: Yup.string()
.required('Required')
.min(6, 'Must be at least 6 characters long')
.max(50, 'Must be at most 50 characters long'),
passwordConfirmation: Yup.string().oneOf(
[Yup.ref('password'), null],
'Passwords must match'
)
})}
>
{({
handleChange,
handleBlur,
handleSubmit,
touched,
errors,
status,
values,
setTouched
}) => (
<TouchableWithoutFeedback onPress={() => navigation.goBack()}>
<View as={SafeAreaView} style={styles.container}>
<View
style={[styles.modal, { backgroundColor: colors.background }]}
onStartShouldSetResponder={() => true}
onResponderRelease={() => setTouched(errors)}
>
{!!status && <Text style={styles.status}>{status}</Text>}
{touched.username && errors.username && (
<Text style={styles.errorMessage}>{errors.username}</Text>
)}
<TextInput
style={[
styles.textInput,
touched.username && errors.username && { borderColor: colors.red },
{ color: colors.text }
]}
placeholder="Username"
placeholderTextColor={colors.text}
value={values.username}
onChangeText={handleChange('username')}
onBlur={handleBlur('username')}
/>
{touched.password && errors.password && (
<Text style={styles.errorMessage}>{errors.password}</Text>
)}
<TextInput
style={[
styles.textInput,
touched.password && errors.password && { borderColor: colors.red },
{ color: colors.text }
]}
placeholder="Password"
placeholderTextColor={colors.text}
value={values.password}
onChangeText={handleChange('password')}
onBlur={handleBlur('password')}
secureTextEntry
/>
{touched.passwordConfirmation && errors.passwordConfirmation && (
<Text style={styles.errorMessage}>{errors.passwordConfirmation}</Text>
)}
<TextInput
style={[
styles.textInput,
touched.passwordConfirmation &&
errors.passwordConfirmation && {
borderColor: colors.red
},
{ color: colors.text }
]}
placeholder="Confirm Password"
placeholderTextColor={colors.text}
value={values.passwordConfirmation}
onChangeText={handleChange('passwordConfirmation')}
onBlur={handleBlur('passwordConfirmation')}
secureTextEntry
/>
<View style={styles.buttonContainer}>
<Button
onPress={handleSubmit}
title="Create Account"
bgColor={colors.signUpButton}
>
{isLoading && <ActivityIndicator size="small" color="white" />}
</Button>
</View>
</View>
</View>
</TouchableWithoutFeedback>
)}
</Formik>
</KeyboardAvoidingView>
)
}
Example #25
Source File: Intro.js From actual with MIT License | 4 votes |
render() {
let { navigation, createBudget } = this.props;
let { selectedFeature } = this.state;
//let textStyle = [styles.text, { color: 'white' }];
return (
<SafeAreaView style={{ flex: 1 }}>
<TransitionView navigation={navigation}>
<View
style={{ justifyContent: 'center', alignItems: 'center', flex: 1 }}
>
<ScalableImage
source={Icon}
width={35}
style={{ marginBottom: 20, marginTop: 30 }}
/>
<View style={{ height: 240 }}>
<ScrollView
ref={el => (this.scrollView = el)}
pagingEnabled={true}
horizontal={true}
showsHorizontalScrollIndicator={false}
onScrollBeginDrag={this.onScrollBegin}
onScrollEndDrag={this.onScrollEnd}
onMomentumScrollEnd={this.onMomentumScrollEnd}
>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
flex: 0
}}
>
<Feature
title="Welcome to Actual"
subtitle={
<Text>
Actual is a privacy-focused app that lets you track your
finances without all the fuss. Create your own budgeting
workflows quickly and discover your spending habits.{' '}
<ExternalLink href="https://actualbudget.com/">
Learn more
</ExternalLink>
</Text>
}
/>
<Feature
title="Powerful budgeting made simple"
subtitle="Based on tried and true methods, our budgeting system is based off of your real income instead of made up numbers."
/>
<Feature
title="The fastest way to manage transactions"
subtitle="Breeze through your transactions and update them easily with a streamlined, minimal interface."
/>
<Feature
title="A privacy-focused approach"
subtitle="All of your data exists locally and is always available. We only upload your data to our servers when syncing across devices, and we encrypt it so even we can't read it."
/>
</View>
</ScrollView>
<View style={{ alignItems: 'center' }}>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
width: 45
}}
>
<SlideshowIndicator selected={selectedFeature === 0} />
<SlideshowIndicator selected={selectedFeature === 1} />
<SlideshowIndicator selected={selectedFeature === 2} />
<SlideshowIndicator selected={selectedFeature === 3} />
</View>
</View>
</View>
</View>
<View
style={{
marginHorizontal: 50,
marginBottom: 15,
justifyContent: 'flex-end'
}}
>
<Button
primary
style={{ marginBottom: 10, backgroundColor: 'white' }}
contentStyle={{ borderWidth: 0 }}
textStyle={{ fontSize: 17, color: colors.n1 }}
onPress={() => {
navigation.navigate('SubscribeEmail');
}}
>
Get started
</Button>
<Button
style={{
marginBottom: 10,
backgroundColor: 'rgba(180, 180, 180, .15)'
}}
contentStyle={{ borderWidth: 0 }}
textStyle={{ fontSize: 17, color: 'white' }}
onPress={() => {
navigation.navigate('Login');
}}
>
Log in
</Button>
</View>
<Button
bare
textStyle={{ fontWeight: 'bold', fontSize: 15, color: 'white' }}
style={{ padding: 10, alignSelf: 'center' }}
onPress={() => createBudget({ demoMode: true })}
>
Try demo
</Button>
</TransitionView>
</SafeAreaView>
);
}
Example #26
Source File: SignIn.js From reddit-clone with MIT License | 4 votes |
SignIn = ({ navigation }) => {
const { setStorage } = React.useContext(AuthContext)
const { colors } = useTheme()
const [isLoading, setIsLoading] = React.useState(false)
return (
<KeyboardAvoidingView behavior="padding" style={{ flex: 1 }}>
<Formik
initialValues={{ username: '', password: '' }}
onSubmit={async (values, { setStatus, resetForm }) => {
setIsLoading(true)
try {
const { data } = await axios.post('authenticate', values)
const { token, expiresAt, userInfo } = data
setStorage(token, expiresAt, userInfo)
navigation.navigate('Home')
resetForm({})
} catch (error) {
setStatus(error.response.data.message)
}
setIsLoading(false)
}}
validationSchema={Yup.object({
username: Yup.string()
.required('Required')
.max(32, 'Must be at most 32 characters long')
.matches(/^[a-zA-Z0-9_-]+$/, 'Contains invalid characters'),
password: Yup.string()
.required('Required')
.min(6, 'Must be at least 6 characters long')
.max(50, 'Must be at most 50 characters long')
})}
>
{({
handleChange,
handleBlur,
handleSubmit,
touched,
errors,
status,
values,
setTouched
}) => (
<TouchableWithoutFeedback onPress={() => navigation.goBack()}>
<View as={SafeAreaView} style={styles.container}>
<View
style={[styles.modal, { backgroundColor: colors.background }]}
onStartShouldSetResponder={() => true}
onResponderRelease={() => setTouched(errors)}
>
{!!status && <Text style={styles.status}>{status}</Text>}
{touched.username && errors.username && (
<Text style={styles.errorMessage}>{errors.username}</Text>
)}
<TextInput
style={[
styles.textInput,
touched.username && errors.username && { borderColor: colors.red },
{ color: colors.text }
]}
placeholder="Username"
placeholderTextColor={colors.text}
value={values.username}
autoCorrect={false}
onChangeText={handleChange('username')}
onBlur={handleBlur('username')}
/>
{touched.password && errors.password && (
<Text style={styles.errorMessage}>{errors.password}</Text>
)}
<TextInput
style={[
styles.textInput,
touched.password && errors.password && { borderColor: colors.red },
{ color: colors.text }
]}
placeholder="Password"
placeholderTextColor={colors.text}
value={values.password}
onChangeText={handleChange('password')}
onBlur={handleBlur('password')}
secureTextEntry
/>
<View style={styles.buttonContainer}>
<Button onPress={handleSubmit} title="Login" bgColor={colors.signInButton}>
{isLoading && <ActivityIndicator size="small" color="white" />}
</Button>
</View>
</View>
</View>
</TouchableWithoutFeedback>
)}
</Formik>
</KeyboardAvoidingView>
)
}
Example #27
Source File: PostDetail.js From reddit-clone with MIT License | 4 votes |
PostDetail = ({ route, navigation }) => {
const { authState } = React.useContext(AuthContext)
const flatListRef = React.useRef()
const [post, setPost] = React.useState(null)
const [isLoading, setIsLoaading] = React.useState(false)
const [comment, setComment] = React.useState('')
const [isFocused, setIsFocused] = React.useState(null)
const { postId } = route.params
const { comments } = route.params
const getPostData = React.useCallback(async () => {
setIsLoaading(true)
const { data } = await axios.get(`post/${postId}`)
setPost(data)
setIsLoaading(false)
}, [postId])
React.useEffect(() => {
getPostData()
}, [getPostData])
React.useEffect(() => {
isFocused && flatListRef.current.scrollToOffset({ animated: true, offset: 0 })
}, [isFocused])
const createComment = async () => {
const { data } = await axios.post(`/post/${postId}`, {
comment
})
setPost(data)
setComment('')
}
const deleteComment = async commentId => {
setIsLoaading(true)
const { data } = await axios.delete(`/post/${postId}/${commentId}`)
setPost(data)
setIsLoaading(false)
}
const deletePost = async postId => {
setIsLoaading(true)
const { status } = await axios.delete(`post/${postId}`)
if (status === 200) {
navigation.push('Home')
}
setIsLoaading(false)
}
return (
<View as={SafeAreaView} style={styles.container}>
{post ? (
<>
<FlatList
ref={flatListRef}
data={post.comments.sort((a, b) => a.created < b.created)}
refreshing={isLoading}
onRefresh={() => getPostData()}
keyExtractor={item => item.id}
ListHeaderComponent={
<Post
postId={post.id}
userId={authState.userInfo.id}
score={post.score}
type={post.type}
title={post.title}
author={post.author}
category={post.category}
text={post.text}
comments={post.comments}
created={post.created}
url={post.url}
votes={post.votes}
views={post.views}
setIsLoaading={setIsLoaading}
setData={setPost}
postType="item"
deleteButton={true}
deletePost={() => deletePost(post.id)}
/>
}
ListHeaderComponentStyle={styles.headerComponentStyle}
renderItem={({ item, index }) => (
<CommentListItem
body={item.body}
author={item.author}
created={item.created}
deleteComment={() => deleteComment(item.id)}
/>
)}
/>
{authState.token && (
<CreateComment
onPress={createComment}
setComment={setComment}
setIsFocused={setIsFocused}
comment={comment}
/>
)}
</>
) : (
<>
<PostLoader />
{comments.map(i => (
<CommentLoader key={i.id} />
))}
</>
)}
</View>
)
}
Example #28
Source File: CreatePost.js From reddit-clone with MIT License | 4 votes |
CreatePost = () => {
const { colors } = useTheme()
const [isLoading, setIsLoading] = React.useState(false)
const [message, setMessage] = React.useState(null)
const fadeAnim = React.useRef(new Animated.Value(0)).current
const fadeIn = () => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 2000,
useNativeDriver: true
}).start()
setTimeout(() => {
setMessage(null)
}, 6000)
}
return (
<ScrollView as={SafeAreaView} style={[styles.container, { backgroundColor: colors.bgColor }]}>
<Formik
initialValues={{
type: 'text',
category: '',
title: '',
url: '',
text: ''
}}
onSubmit={async (values, { setStatus, resetForm }) => {
setIsLoading(true)
try {
await axios.post('posts', values)
resetForm({ ...values, type: 'text' })
setMessage('Successfully Created!')
fadeIn()
} catch (error) {
setStatus(error.response.data.message)
}
setIsLoading(false)
}}
validationSchema={Yup.object({
type: Yup.mixed().oneOf(['text', 'link']),
category: Yup.string().required('Required'),
title: Yup.string()
.required('Required')
.max(100, 'Must be at most 100 characters long'),
text: Yup.string().when('type', {
is: 'text',
then: Yup.string()
.required('Required')
.min(4, 'Must be at least 4 characters long')
}),
url: Yup.string().when('type', {
is: 'link',
then: Yup.string()
.required('Required')
.url('Invalid Url')
})
})}
>
{({
handleChange,
handleBlur,
handleSubmit,
touched,
errors,
status,
values,
setFieldValue
}) => (
<View>
{message && (
<Animated.View
style={{
opacity: fadeAnim
}}
>
{!!message && <Text style={styles.message}>{message}</Text>}
</Animated.View>
)}
{!!status && <Text style={styles.status}>{status}</Text>}
<View style={styles.flexRow}>
<Text style={[styles.formLabel, { color: colors.text }]}>Type</Text>
{touched.type && errors.type && (
<Text style={styles.errorMessage}>{errors.type}</Text>
)}
</View>
<TypeSwichContainer>
<TypeSwichButton selected={values.type} onClick={setFieldValue} type="text" />
<TypeSwichButton selected={values.type} onClick={setFieldValue} type="link" />
</TypeSwichContainer>
<View style={styles.flexRow}>
<Text style={[styles.formLabel, { color: colors.text }]}>Category</Text>
{touched.category && errors.category && (
<Text style={styles.errorMessage}>{errors.category}</Text>
)}
</View>
<CategoryPicker selectedCategory={values.category} setFieldValue={setFieldValue} />
<View style={styles.flexRow}>
<Text style={[styles.formLabel, { color: colors.text }]}>Title</Text>
{touched.title && errors.title && (
<Text style={styles.errorMessage}>{errors.title}</Text>
)}
</View>
<TextInput
style={[
styles.textInput,
{ borderColor: colors.border, color: colors.text, height: 40 },
touched.title && errors.title && { borderColor: colors.red }
]}
value={values.title}
onChangeText={handleChange('title')}
onBlur={handleBlur('title')}
/>
{values.type === 'link' ? (
<>
<View style={styles.flexRow}>
<Text style={[styles.formLabel, { color: colors.text }]}>Url</Text>
{touched.url && errors.url && (
<Text style={styles.errorMessage}>{errors.url}</Text>
)}
</View>
<TextInput
style={[
styles.textInput,
{ borderColor: colors.border, color: colors.text },
touched.url && errors.url && { borderColor: colors.red }
]}
multiline
value={values.url}
onChangeText={handleChange('url')}
onBlur={handleBlur('url')}
/>
</>
) : (
<>
<View style={styles.flexRow}>
<Text style={[styles.formLabel, { color: colors.text }]}>Text</Text>
{touched.text && errors.text && (
<Text style={styles.errorMessage}>{errors.text}</Text>
)}
</View>
<TextInput
style={[
styles.textInput,
{ borderColor: colors.border, color: colors.text },
touched.text && errors.text && { borderColor: colors.red }
]}
multiline
value={values.text}
onChangeText={handleChange('text')}
onBlur={handleBlur('text')}
/>
</>
)}
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[styles.submitButton, { backgroundColor: colors.blue }]}
onPress={handleSubmit}
>
{isLoading ? (
<ActivityIndicator size="small" color="white" />
) : (
<Plus color="white" />
)}
<Text style={styles.submitButtonText}>Create Post</Text>
</TouchableOpacity>
</View>
</View>
)}
</Formik>
</ScrollView>
)
}
Example #29
Source File: Post.js From reddit-clone with MIT License | 4 votes |
Post = ({
index,
postId,
userId,
score,
type,
title,
author,
category,
text,
comments,
created,
url,
votes,
views,
setIsLoaading,
setData,
postType,
deleteButton,
deletePost
}) => {
const { colors } = useTheme()
const navigation = useNavigation()
const { authState } = React.useContext(AuthContext)
const route = useRoute()
const isUpVoted = () => {
return votes.find(v => v.user === userId)?.vote === 1
}
const isDownVoted = () => {
return votes.find(v => v.user === userId)?.vote === -1
}
const upVote = async () => {
setIsLoaading(true)
const { data } = await axios.get(`post/${postId}/upvote`)
if (postType !== 'item') {
setData(prevData => {
prevData[index] = data
return prevData
})
} else {
setData(data)
}
setIsLoaading(false)
}
const downVote = async () => {
setIsLoaading(true)
const { data } = await axios.get(`post/${postId}/downvote`)
if (postType !== 'item') {
setData(prevData => {
prevData[index] = data
return prevData
})
} else {
setData(data)
}
setIsLoaading(false)
}
const unVote = async () => {
setIsLoaading(true)
const { data } = await axios.get(`post/${postId}/unvote`)
if (postType !== 'item') {
setData(prevData => {
prevData[index] = data
return prevData
})
} else {
setData(data)
}
setIsLoaading(false)
}
return (
<View
as={SafeAreaView}
style={[
styles.container,
{ backgroundColor: colors.bgColor, borderColor: colors.postBorder }
]}
>
<View style={styles.headerContainer}>
<View style={styles.headerLeft}>
<Text style={[styles.regularFont, { color: colors.text }]}>{category} </Text>
<Text
style={[styles.italicFont, { color: colors.blue }]}
onPress={() => navigation.navigate('User', { username: author.username })}
>
@{author?.username} ·{' '}
</Text>
<Text style={[styles.dateText, { color: colors.text }]}>{moment(created).fromNow()}</Text>
</View>
<View style={styles.headerRight}>
{deleteButton && author?.id === authState.userInfo.id && (
<TouchableOpacity style={styles.trash} activeOpacity={0.5} onPress={deletePost}>
<Trash color={colors.red} width={20} height={20} />
</TouchableOpacity>
)}
</View>
</View>
<Text
style={[styles.title, { color: colors.text }]}
onPress={() => navigation.navigate('PostDetail', { postId, category, comments })}
>
{title}
</Text>
<Text
numberOfLines={route.name === 'PostDetail' ? 10000 : 10}
style={[
styles.regularFont,
{ color: colors.text },
type === 'link' && route.name === 'PostDetail' && styles.link
]}
onPress={() =>
route.name === 'PostDetail' && type === 'link'
? Linking.openURL(url)
: navigation.navigate('PostDetail', { postId, category, comments })
}
>
{type === 'link' ? url : text}
</Text>
<View style={styles.bottomContainer}>
<View style={styles.centerAlign}>
<TouchableOpacity onPress={() => (isUpVoted() ? unVote() : upVote())}>
<ArrowUp
width={22}
height={22}
strokeWidth={4}
color={isUpVoted() ? colors.green : colors.icon}
/>
</TouchableOpacity>
<Text style={[styles.score, { color: colors.text }]}>{score}</Text>
<TouchableOpacity onPress={() => (isDownVoted() ? unVote() : downVote())}>
<ArrowDown
width={22}
height={22}
strokeWidth={4}
color={isDownVoted() ? colors.red : colors.icon}
/>
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.centerAlign}
activeOpacity={0.7}
onPress={() => navigation.navigate('PostDetail', { postId, category, comments })}
>
<MessageSquare
color={colors.icon}
style={styles.commentIcon}
width={20}
height={20}
strokeWidth={3}
/>
<Text style={[styles.commentText, { color: colors.text }]}>{comments?.length}</Text>
</TouchableOpacity>
<Text style={[styles.italicFont, { color: colors.text }]}>{views} views</Text>
</View>
</View>
)
}