Browse Source

Adding first prototype

master
Daniel D'Angelo Resende Barros 4 years ago
parent
commit
09967ebfb5
  1. 1
      src/.gitignore
  2. 14
      src/App.js
  3. BIN
      src/app/assets/chuva_peq.png
  4. BIN
      src/app/assets/ddangelorb.png
  5. BIN
      src/app/assets/defesa_civil.png
  6. BIN
      src/app/assets/pontos_alagamento_peq.png
  7. BIN
      src/app/assets/previsao_tempo.png
  8. 35
      src/app/components/Button.js
  9. 35
      src/app/components/CategoryPickerItem.js
  10. 27
      src/app/components/Icon.js
  11. 78
      src/app/components/ImageInput.js
  12. 40
      src/app/components/ImageInputList.js
  13. 98
      src/app/components/Picker.js
  14. 20
      src/app/components/PickerItem.js
  15. 23
      src/app/components/Screen.js
  16. 14
      src/app/components/Text.js
  17. 40
      src/app/components/TextInput.js
  18. 16
      src/app/components/forms/ErrorMessage.js
  19. 16
      src/app/components/forms/Form.js
  20. 23
      src/app/components/forms/FormField.js
  21. 34
      src/app/components/forms/FormImagePicker.js
  22. 33
      src/app/components/forms/FormPicker.js
  23. 12
      src/app/components/forms/SubmitButton.js
  24. 5
      src/app/components/forms/index.js
  25. 69
      src/app/components/lists/ListItem.js
  26. 30
      src/app/components/lists/ListItemDeleteAction.js
  27. 18
      src/app/components/lists/ListItemSeparator.js
  28. 3
      src/app/components/lists/index.js
  29. 2
      src/app/config/colors.js
  30. 12
      src/app/config/styles.js
  31. 25
      src/app/hooks/useLocation.js
  32. 14
      src/app/navigation/AccountNavigator.js
  33. 77
      src/app/navigation/AppNavigator.js
  34. 13
      src/app/navigation/FeedNavigator.js
  35. 13
      src/app/navigation/MessagesNavigator.js
  36. 35
      src/app/navigation/NewListingButton.js
  37. 13
      src/app/navigation/OfficialMessagesNavigator.js
  38. 11
      src/app/navigation/navigationTheme.js
  39. 9
      src/app/navigation/routes.js
  40. 36
      src/app/screens/AccountScreen.js
  41. 63
      src/app/screens/MapFeedScreen.js
  42. 70
      src/app/screens/MessagesScreen.js
  43. 29
      src/app/screens/OfficialMessagesScreen.js
  44. 109
      src/app/screens/SharingDataScreen.js
  45. 53
      src/app/screens/ViewImageScreen.js
  46. 7956
      src/package-lock.json
  47. 20
      src/package.json
  48. 688
      src/yarn.lock

1
src/.gitignore

@ -0,0 +1 @@
node_modules

14
src/App.js

@ -1,7 +1,13 @@
import React from 'react';
import React from "react";
import { NavigationContainer } from "@react-navigation/native";
import ViewImageScreen from "./app/screens/ViewImageScreen";
import navigationTheme from "./app/navigation/navigationTheme";
import AppNavigator from "./app/navigation/AppNavigator";
export default function App() { export default function App() {
return <ViewImageScreen />;
}
return (
<NavigationContainer theme={navigationTheme}>
<AppNavigator />
</NavigationContainer>
);
}

BIN
src/app/assets/chuva_peq.png

After

Width: 50  |  Height: 51  |  Size: 8.4 KiB

BIN
src/app/assets/ddangelorb.png

After

Width: 700  |  Height: 727  |  Size: 793 KiB

BIN
src/app/assets/defesa_civil.png

After

Width: 225  |  Height: 225  |  Size: 5.9 KiB

BIN
src/app/assets/pontos_alagamento_peq.png

After

Width: 50  |  Height: 49  |  Size: 8.4 KiB

BIN
src/app/assets/previsao_tempo.png

After

Width: 714  |  Height: 924  |  Size: 56 KiB

35
src/app/components/Button.js

@ -0,0 +1,35 @@
import React from "react";
import { StyleSheet, Text, TouchableOpacity } from "react-native";
import colors from "../config/colors";
function AppButton({ title, onPress, color = "primary" }) {
return (
<TouchableOpacity
style={[styles.button, { backgroundColor: colors[color] }]}
onPress={onPress}
>
<Text style={styles.text}>{title}</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
button: {
backgroundColor: colors.primary,
borderRadius: 25,
justifyContent: "center",
alignItems: "center",
padding: 15,
width: "100%",
marginVertical: 10,
},
text: {
color: colors.white,
fontSize: 18,
textTransform: "uppercase",
fontWeight: "bold",
},
});
export default AppButton;

35
src/app/components/CategoryPickerItem.js

@ -0,0 +1,35 @@
import React from "react";
import { View, StyleSheet, TouchableOpacity } from "react-native";
import Icon from "./Icon";
import Text from "./Text";
function CategoryPickerItem({ item, onPress }) {
return (
<View style={styles.container}>
<TouchableOpacity onPress={onPress}>
<Icon
backgroundColor={item.backgroundColor}
name={item.icon}
size={120}
/>
</TouchableOpacity>
<Text style={styles.label}>{item.label}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: 30,
paddingVertical: 15,
alignItems: "center",
width: "50%",
},
label: {
marginTop: 5,
textAlign: "center",
},
});
export default CategoryPickerItem;

27
src/app/components/Icon.js

@ -0,0 +1,27 @@
import React from "react";
import { View } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
function Icon({
name,
size = 40,
backgroundColor = "#000",
iconColor = "#fff",
}) {
return (
<View
style={{
width: size,
height: size,
borderRadius: size / 2,
backgroundColor,
justifyContent: "center",
alignItems: "center",
}}
>
<MaterialCommunityIcons name={name} color={iconColor} size={size * 0.5} />
</View>
);
}
export default Icon;

78
src/app/components/ImageInput.js

@ -0,0 +1,78 @@
import React, { useEffect } from "react";
import {
View,
StyleSheet,
Image,
TouchableWithoutFeedback,
Alert,
} from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import * as ImagePicker from "expo-image-picker";
import colors from "../config/colors";
function ImageInput({ imageUri, onChangeImage }) {
useEffect(() => {
requestPermission();
}, []);
const requestPermission = async () => {
const { granted } = await ImagePicker.requestCameraRollPermissionsAsync();
if (!granted) alert("You need to enable permission to access the library.");
};
const handlePress = () => {
if (!imageUri) selectImage();
else
Alert.alert("Delete", "Are you sure you want to delete this image?", [
{ text: "Yes", onPress: () => onChangeImage(null) },
{ text: "No" },
]);
};
const selectImage = async () => {
try {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 0.5,
});
if (!result.cancelled) onChangeImage(result.uri);
} catch (error) {
console.log("Error reading an image", error);
}
};
return (
<TouchableWithoutFeedback onPress={handlePress}>
<View style={styles.container}>
{!imageUri && (
<MaterialCommunityIcons
color={colors.medium}
name="camera"
size={40}
/>
)}
{imageUri && <Image source={{ uri: imageUri }} style={styles.image} />}
</View>
</TouchableWithoutFeedback>
);
}
const styles = StyleSheet.create({
container: {
alignItems: "center",
backgroundColor: colors.light,
borderRadius: 15,
height: 100,
justifyContent: "center",
marginVertical: 10,
overflow: "hidden",
width: 100,
},
image: {
height: "100%",
width: "100%",
},
});
export default ImageInput;

40
src/app/components/ImageInputList.js

@ -0,0 +1,40 @@
import React, { useRef } from "react";
import { View, StyleSheet, ScrollView } from "react-native";
import ImageInput from "./ImageInput";
function ImageInputList({ imageUris = [], onRemoveImage, onAddImage }) {
const scrollView = useRef();
return (
<View>
<ScrollView
ref={scrollView}
horizontal
onContentSizeChange={() => scrollView.current.scrollToEnd()}
>
<View style={styles.container}>
{imageUris.map((uri) => (
<View key={uri} style={styles.image}>
<ImageInput
imageUri={uri}
onChangeImage={() => onRemoveImage(uri)}
/>
</View>
))}
<ImageInput onChangeImage={(uri) => onAddImage(uri)} />
</View>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
},
image: {
marginRight: 10,
},
});
export default ImageInputList;

98
src/app/components/Picker.js

@ -0,0 +1,98 @@
import React, { useState } from "react";
import {
View,
StyleSheet,
TouchableWithoutFeedback,
Modal,
Button,
FlatList,
} from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import Text from "./Text";
import defaultStyles from "../config/styles";
import PickerItem from "./PickerItem";
import Screen from "./Screen";
function AppPicker({
icon,
items,
numberOfColumns = 1,
onSelectItem,
PickerItemComponent = PickerItem,
placeholder,
selectedItem,
width = "100%",
}) {
const [modalVisible, setModalVisible] = useState(false);
return (
<>
<TouchableWithoutFeedback onPress={() => setModalVisible(true)}>
<View style={[styles.container, { width }]}>
{icon && (
<MaterialCommunityIcons
name={icon}
size={20}
color={defaultStyles.colors.medium}
style={styles.icon}
/>
)}
{selectedItem ? (
<Text style={styles.text}>{selectedItem.label}</Text>
) : (
<Text style={styles.placeholder}>{placeholder}</Text>
)}
<MaterialCommunityIcons
name="chevron-down"
size={20}
color={defaultStyles.colors.medium}
/>
</View>
</TouchableWithoutFeedback>
<Modal visible={modalVisible} animationType="slide">
<Screen>
<Button title="Close" onPress={() => setModalVisible(false)} />
<FlatList
data={items}
keyExtractor={(item) => item.value.toString()}
numColumns={numberOfColumns}
renderItem={({ item }) => (
<PickerItemComponent
item={item}
label={item.label}
onPress={() => {
setModalVisible(false);
onSelectItem(item);
}}
/>
)}
/>
</Screen>
</Modal>
</>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: defaultStyles.colors.light,
borderRadius: 25,
flexDirection: "row",
padding: 15,
marginVertical: 10,
},
icon: {
marginRight: 10,
},
placeholder: {
color: defaultStyles.colors.medium,
flex: 1,
},
text: {
flex: 1,
},
});
export default AppPicker;

20
src/app/components/PickerItem.js

@ -0,0 +1,20 @@
import React from "react";
import { TouchableOpacity, StyleSheet } from "react-native";
import Text from "./Text";
function PickerItem({ item, onPress }) {
return (
<TouchableOpacity onPress={onPress}>
<Text style={styles.text}>{item.label}</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
text: {
padding: 20,
},
});
export default PickerItem;

23
src/app/components/Screen.js

@ -0,0 +1,23 @@
import React from "react";
import Constants from "expo-constants";
import { StyleSheet, SafeAreaView, View } from "react-native";
function Screen({ children, style }) {
return (
<SafeAreaView style={[styles.screen, style]}>
<View style={[styles.view, style]}>{children}</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
screen: {
paddingTop: Constants.statusBarHeight,
flex: 1,
},
view: {
flex: 1,
},
});
export default Screen;

14
src/app/components/Text.js

@ -0,0 +1,14 @@
import React from "react";
import { Text } from "react-native";
import defaultStyles from "../config/styles";
function AppText({ children, style, ...otherProps }) {
return (
<Text style={[defaultStyles.text, style]} {...otherProps}>
{children}
</Text>
);
}
export default AppText;

40
src/app/components/TextInput.js

@ -0,0 +1,40 @@
import React from "react";
import { View, TextInput, StyleSheet } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import defaultStyles from "../config/styles";
function AppTextInput({ icon, width = "100%", ...otherProps }) {
return (
<View style={[styles.container, { width }]}>
{icon && (
<MaterialCommunityIcons
name={icon}
size={20}
color={defaultStyles.colors.medium}
style={styles.icon}
/>
)}
<TextInput
placeholderTextColor={defaultStyles.colors.medium}
style={defaultStyles.text}
{...otherProps}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: defaultStyles.colors.light,
borderRadius: 25,
flexDirection: "row",
padding: 15,
marginVertical: 10,
},
icon: {
marginRight: 10,
},
});
export default AppTextInput;

16
src/app/components/forms/ErrorMessage.js

@ -0,0 +1,16 @@
import React from "react";
import { StyleSheet } from "react-native";
import Text from "../Text";
function ErrorMessage({ error, visible }) {
if (!visible || !error) return null;
return <Text style={styles.error}>{error}</Text>;
}
const styles = StyleSheet.create({
error: { color: "red" },
});
export default ErrorMessage;

16
src/app/components/forms/Form.js

@ -0,0 +1,16 @@
import React from "react";
import { Formik } from "formik";
function AppForm({ initialValues, onSubmit, validationSchema, children }) {
return (
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
>
{() => <>{children}</>}
</Formik>
);
}
export default AppForm;

23
src/app/components/forms/FormField.js

@ -0,0 +1,23 @@
import React from "react";
import { useFormikContext } from "formik";
import TextInput from "../TextInput";
import ErrorMessage from "./ErrorMessage";
function AppFormField({ name, width, ...otherProps }) {
const { setFieldTouched, handleChange, errors, touched } = useFormikContext();
return (
<>
<TextInput
onBlur={() => setFieldTouched(name)}
onChangeText={handleChange(name)}
width={width}
{...otherProps}
/>
<ErrorMessage error={errors[name]} visible={touched[name]} />
</>
);
}
export default AppFormField;

34
src/app/components/forms/FormImagePicker.js

@ -0,0 +1,34 @@
import React from "react";
import { useFormikContext } from "formik";
import ErrorMessage from "./ErrorMessage";
import ImageInputList from "../ImageInputList";
function FormImagePicker({ name }) {
const { errors, setFieldValue, touched, values } = useFormikContext();
const imageUris = values[name];
const handleAdd = (uri) => {
setFieldValue(name, [...imageUris, uri]);
};
const handleRemove = (uri) => {
setFieldValue(
name,
imageUris.filter((imageUri) => imageUri !== uri)
);
};
return (
<>
<ImageInputList
imageUris={imageUris}
onAddImage={handleAdd}
onRemoveImage={handleRemove}
/>
<ErrorMessage error={errors[name]} visible={touched[name]} />
</>
);
}
export default FormImagePicker;

33
src/app/components/forms/FormPicker.js

@ -0,0 +1,33 @@
import React from "react";
import { useFormikContext } from "formik";
import Picker from "../Picker";
import ErrorMessage from "./ErrorMessage";
function AppFormPicker({
items,
name,
numberOfColumns,
PickerItemComponent,
placeholder,
width,
}) {
const { errors, setFieldValue, touched, values } = useFormikContext();
return (
<>
<Picker
items={items}
numberOfColumns={numberOfColumns}
onSelectItem={(item) => setFieldValue(name, item)}
PickerItemComponent={PickerItemComponent}
placeholder={placeholder}
selectedItem={values[name]}
width={width}
/>
<ErrorMessage error={errors[name]} visible={touched[name]} />
</>
);
}
export default AppFormPicker;

12
src/app/components/forms/SubmitButton.js

@ -0,0 +1,12 @@
import React from "react";
import { useFormikContext } from "formik";
import Button from "../Button";
function SubmitButton({ title }) {
const { handleSubmit } = useFormikContext();
return <Button title={title} onPress={handleSubmit} />;
}
export default SubmitButton;

5
src/app/components/forms/index.js

@ -0,0 +1,5 @@
export { default as Form } from "./Form";
export { default as FormField } from "./FormField";
export { default as FormPicker } from "./FormPicker";
export { default as ErrorMessage } from "./ErrorMessage";
export { default as SubmitButton } from "./SubmitButton";

69
src/app/components/lists/ListItem.js

@ -0,0 +1,69 @@
import React from "react";
import { View, StyleSheet, Image, TouchableHighlight } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import Swipeable from "react-native-gesture-handler/Swipeable";
import Text from "../Text";
import colors from "../../config/colors";
function ListItem({
title,
subTitle,
image,
IconComponent,
onPress,
renderRightActions,
}) {
return (
<Swipeable renderRightActions={renderRightActions}>
<TouchableHighlight underlayColor={colors.light} onPress={onPress}>
<View style={styles.container}>
{IconComponent}
{image && <Image style={styles.image} source={image} />}
<View style={styles.detailsContainer}>
<Text style={styles.title} numberOfLines={1}>
{title}
</Text>
{subTitle && (
<Text style={styles.subTitle} numberOfLines={2}>
{subTitle}
</Text>
)}
</View>
<MaterialCommunityIcons
color={colors.medium}
name="chevron-right"
size={25}
/>
</View>
</TouchableHighlight>
</Swipeable>
);
}
const styles = StyleSheet.create({
container: {
alignItems: "center",
flexDirection: "row",
padding: 15,
backgroundColor: colors.white,
},
detailsContainer: {
flex: 1,
marginLeft: 10,
justifyContent: "center",
},
image: {
width: 70,
height: 70,
borderRadius: 35,
},
subTitle: {
color: colors.medium,
},
title: {
fontWeight: "500",
},
});
export default ListItem;

30
src/app/components/lists/ListItemDeleteAction.js

@ -0,0 +1,30 @@
import React from "react";
import { View, StyleSheet, TouchableWithoutFeedback } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import colors from "../../config/colors";
function ListItemDeleteAction({ onPress }) {
return (
<TouchableWithoutFeedback onPress={onPress}>
<View style={styles.container}>
<MaterialCommunityIcons
name="trash-can"
size={35}
color={colors.white}
/>
</View>
</TouchableWithoutFeedback>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: colors.danger,
width: 70,
justifyContent: "center",
alignItems: "center",
},
});
export default ListItemDeleteAction;

18
src/app/components/lists/ListItemSeparator.js

@ -0,0 +1,18 @@
import React from "react";
import { StyleSheet, View } from "react-native";
import colors from "../../config/colors";
function ListItemSeparator() {
return <View style={styles.separator} />;
}
const styles = StyleSheet.create({
separator: {
width: "100%",
height: 1,
backgroundColor: colors.light,
},
});
export default ListItemSeparator;

3
src/app/components/lists/index.js

@ -0,0 +1,3 @@
export { default as ListItem } from "./ListItem";
export { default as ListItemDeleteAction } from "./ListItemDeleteAction";
export { default as ListItemSeparator } from "./ListItemSeparator";

2
src/app/config/colors.js

@ -1,5 +1,5 @@
export default { export default {
primary: "#fc5c65",
primary: "#6a83f7",
secondary: "#4ecdc4", secondary: "#4ecdc4",
black: "#000", black: "#000",
white: "#fff", white: "#fff",

12
src/app/config/styles.js

@ -0,0 +1,12 @@
import { Platform } from "react-native";
import colors from "./colors";
export default {
colors,
text: {
color: colors.dark,
fontSize: 18,
fontFamily: Platform.OS === "android" ? "Roboto" : "Avenir",
},
};

25
src/app/hooks/useLocation.js

@ -0,0 +1,25 @@
import { useEffect, useState } from "react";
import * as Location from "expo-location";
export default useLocation = () => {
const [location, setLocation] = useState();
const getLocation = async () => {
try {
const { granted } = await Location.requestPermissionsAsync();
if (!granted) return;
const {
coords: { latitude, longitude },
} = await Location.getLastKnownPositionAsync();
setLocation({ latitude, longitude });
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getLocation();
}, []);
return location;
};

14
src/app/navigation/AccountNavigator.js

@ -0,0 +1,14 @@
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import AccountScreen from "../screens/AccountScreen";
import MessagesScreen from "../screens/MessagesScreen";
const Stack = createStackNavigator();
const AccountNavigator = () => (
<Stack.Navigator>
<Stack.Screen name="Perfil" component={AccountScreen} />
</Stack.Navigator>
);
export default AccountNavigator;

77
src/app/navigation/AppNavigator.js

@ -0,0 +1,77 @@
import React from "react";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import AccountNavigator from "./AccountNavigator";
import FeedNavigator from "./FeedNavigator";
import MessagesNavigator from "./MessagesNavigator"
import OfficialMessagesNavigator from "./OfficialMessagesNavigator"
import SharingDataScreen from "../screens/SharingDataScreen";
import NewListingButton from "./NewListingButton";
import routes from "./routes";
const Tab = createBottomTabNavigator();
const AppNavigator = () => (
<Tab.Navigator>
<Tab.Screen
name="Home"
component={FeedNavigator}
options={{
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Oficial"
component={OfficialMessagesNavigator}
options={{
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="check-circle" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="SharingData"
component={SharingDataScreen}
options={({ navigation }) => ({
tabBarButton: () => (
<NewListingButton
onPress={() => navigation.navigate(routes.SHARING_DATA)}
/>
),
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons
name="plus-circle"
color={color}
size={size}
/>
),
})}
/>
<Tab.Screen
name="Notificação"
component={MessagesNavigator}
options={{
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="bell-outline" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="Perfil"
component={AccountNavigator}
options={{
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="account" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
export default AppNavigator;

13
src/app/navigation/FeedNavigator.js

@ -0,0 +1,13 @@
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import MapFeedScreen from "../screens/MapFeedScreen";
const Stack = createStackNavigator();
const FeedNavigator = () => (
<Stack.Navigator>
<Stack.Screen name="Home" component={MapFeedScreen} />
</Stack.Navigator>
);
export default FeedNavigator;

13
src/app/navigation/MessagesNavigator.js

@ -0,0 +1,13 @@
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import MessagesScreen from "../screens/MessagesScreen";
const Stack = createStackNavigator();
const MessagesNavigator = () => (
<Stack.Navigator>
<Stack.Screen name="Notificação" component={MessagesScreen} />
</Stack.Navigator>
);
export default MessagesNavigator;

35
src/app/navigation/NewListingButton.js

@ -0,0 +1,35 @@
import React from "react";
import { View, StyleSheet, TouchableOpacity } from "react-native";
import { MaterialCommunityIcons } from "@expo/vector-icons";
import colors from "../config/colors";
function NewListingButton({ onPress }) {
return (
<TouchableOpacity onPress={onPress}>
<View style={styles.container}>
<MaterialCommunityIcons
name="plus-circle"
color={colors.white}
size={40}
/>
</View>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
container: {
alignItems: "center",
backgroundColor: colors.primary,
borderColor: colors.white,
borderRadius: 40,
borderWidth: 10,
bottom: 20,
height: 80,
justifyContent: "center",
width: 80,
},
});
export default NewListingButton;

13
src/app/navigation/OfficialMessagesNavigator.js

@ -0,0 +1,13 @@
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import OfficialMessagesScreen from "../screens/OfficialMessagesScreen";
const Stack = createStackNavigator();
const OfficialMessagesNavigator = () => (
<Stack.Navigator>
<Stack.Screen name="Previsão do Tempo" component={OfficialMessagesScreen} />
</Stack.Navigator>
);
export default OfficialMessagesNavigator;

11
src/app/navigation/navigationTheme.js

@ -0,0 +1,11 @@
import { DefaultTheme } from "@react-navigation/native";
import colors from "../config/colors";
export default {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
primary: colors.primary,
background: colors.white,
},
};

9
src/app/navigation/routes.js

@ -0,0 +1,9 @@
export default Object.freeze({
LISTING_DETAILS: "ListingDetails",
LISTING_EDIT: "ListingEdit",
LOGIN: "Login",
MESSAGES: "Messages",
REGISTER: "Register",
SHARING_DATA: "SharingData",
});

36
src/app/screens/AccountScreen.js

@ -0,0 +1,36 @@
import React from "react";
import { StyleSheet, View } from "react-native";
import { ListItem } from "../components/lists";
import colors from "../config/colors";
import Icon from "../components/Icon";
import Screen from "../components/Screen";
function AccountScreen({ navigation }) {
return (
<Screen style={styles.screen}>
<View style={styles.container}>
<ListItem
title="Daniel Barros"
subTitle="danieldrb@gmail.com"
image={require("../assets/ddangelorb.png")}
/>
</View>
<ListItem
title="Log Out"
IconComponent={<Icon name="logout" backgroundColor="#ffe66d" />}
/>
</Screen>
);
}
const styles = StyleSheet.create({
screen: {
backgroundColor: colors.light,
},
container: {
marginVertical: 20,
},
});
export default AccountScreen;

63
src/app/screens/MapFeedScreen.js

@ -0,0 +1,63 @@
import React from "react";
import { StyleSheet, View } from "react-native";
import MapView, { Marker } from "react-native-maps";
import colors from "../config/colors";
function MapFeedScreen(props) {
return (
<View style={styles.container}>
<MapView
style={styles.mapStyle}
initialRegion={{
latitude: -23.657090,
longitude: -46.699260,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}>
<Marker
coordinate={{ latitude: -23.657090, longitude: -46.699260 }}
image={require("../assets/chuva_peq.png")}
/>
<Marker
coordinate={{ latitude: -23.656282, longitude: -46.682768 }}
image={require("../assets/chuva_peq.png")}
/>
<Marker
coordinate={{ latitude: -23.666712, longitude: -46.687650 }}
image={require("../assets/chuva_peq.png")}
/>
<Marker
coordinate={{ latitude: -23.660848, longitude: -46.704396 }}
image={require("../assets/chuva_peq.png")}
/>
<Marker
coordinate={{ latitude: -23.634700, longitude: -46.721960 }}
image={require("../assets/pontos_alagamento_peq.png")}
/>
<Marker
coordinate={{ latitude: -23.650861, longitude: -46.721775 }}
image={require("../assets/pontos_alagamento_peq.png")}
/>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: colors.black,
flex: 1,
},
mapStyle: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0
},
});
export default MapFeedScreen;

70
src/app/screens/MessagesScreen.js

@ -0,0 +1,70 @@
import React, { useState } from "react";
import { FlatList, StyleSheet } from "react-native";
import Screen from "../components/Screen";
import {
ListItem,
ListItemDeleteAction,
ListItemSeparator,
} from "../components/lists";
const initialMessages = [
{
id: 1,
title: "Defesa Civil",
description: "Enviado um aviso de chuvas intensas na região do M'Boi Mirim. Há possibilidade ...",
image: require("../assets/defesa_civil.png"),
},
{
id: 2,
title: "Defesa Civil",
description:
"Enviado um aviso de alagamento na região de Pinheiros. Há possibilidade de alagamentos. Evite a região.",
image: require("../assets/defesa_civil.png"),
},
];
function MessagesScreen(props) {
const [messages, setMessages] = useState(initialMessages);
const [refreshing, setRefreshing] = useState(false);
const handleDelete = (message) => {
setMessages(messages.filter((m) => m.id !== message.id));
};
return (
<Screen>
<FlatList
data={messages}
keyExtractor={(message) => message.id.toString()}
renderItem={({ item }) => (
<ListItem
title={item.title}
subTitle={item.description}
image={item.image}
onPress={() => console.log("Message selected", item)}
renderRightActions={() => (
<ListItemDeleteAction onPress={() => handleDelete(item)} />
)}
/>
)}
ItemSeparatorComponent={ListItemSeparator}
refreshing={refreshing}
onRefresh={() => {
setMessages([
{
id: 2,
title: "T2",
description: "D2",
image: require("../assets/ddangelorb.png"),
},
]);
}}
/>
</Screen>
);
}
const styles = StyleSheet.create({});
export default MessagesScreen;

29
src/app/screens/OfficialMessagesScreen.js

@ -0,0 +1,29 @@
import React from "react";
import { Image, StyleSheet, View } from "react-native";
import colors from "../config/colors";
function OfficialMessagesScreen(props) {
return (
<View style={styles.container}>
<Image
resizeMode="contain"
style={styles.image}
source={require("../assets/previsao_tempo.png")}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: colors.black,
flex: 1,
},
image: {
width: "100%",
height: "100%",
},
});
export default OfficialMessagesScreen;

109
src/app/screens/SharingDataScreen.js

@ -0,0 +1,109 @@
import React from "react";
import { StyleSheet } from "react-native";
import * as Yup from "yup";
import {
Form,
FormField,
FormPicker as Picker,
SubmitButton,
} from "../components/forms";
import CategoryPickerItem from "../components/CategoryPickerItem";
import Screen from "../components/Screen";
import FormImagePicker from "../components/forms/FormImagePicker";
import useLocation from "../hooks/useLocation";
const validationSchema = Yup.object().shape({
title: Yup.string().required().min(1).label("Title"),
price: Yup.number().required().min(1).max(10000).label("Price"),
description: Yup.string().label("Description"),
category: Yup.object().required().nullable().label("Category"),
images: Yup.array().min(1, "Please select at least one image."),
});
const categories = [
{
backgroundColor: "#2e53ff",
icon: "wave",
label: "Pontos de alagamento",
value: 1,
},
{
backgroundColor: "#2e53ff",
icon: "weather-pouring",
label: "Chuva",
value: 2,
},
{
backgroundColor: "#2e53ff",
icon: "waves",
label: "Diário do pluviômetro",
value: 3,
},
{
backgroundColor: "#2e53ff",
icon: "waves",
label: "Diário do pluviômetro",
value: 3,
},
{
backgroundColor: "#2e53ff",
icon: "water-percent",
label: "Nível do rio",
value: 4,
},
];
function SharingDataScreen() {
const location = useLocation();
return (
<Screen style={styles.container}>
<Form
initialValues={{
title: "",
price: "",
description: "",
category: null,
images: [],
}}
onSubmit={(values) => console.log(location)}
validationSchema={validationSchema}
>
<FormImagePicker name="images" />
<FormField maxLength={255} name="title" placeholder="Título" />
<FormField
keyboardType="numeric"
maxLength={8}
name="price"
placeholder="Valor"
width={120}
/>
<Picker
items={categories}
name="category"
numberOfColumns={3}
PickerItemComponent={CategoryPickerItem}
placeholder="Categoria"
width="50%"
/>
<FormField
maxLength={255}
multiline
name="description"
numberOfLines={3}
placeholder="Descrição"
/>
<SubmitButton title="Post" />
</Form>
</Screen>
);
}
const styles = StyleSheet.create({
container: {
padding: 10,
},
});
export default SharingDataScreen;

53
src/app/screens/ViewImageScreen.js

@ -1,53 +0,0 @@
import React from "react";
import { Image, StyleSheet, View } from "react-native";
import MapView from 'react-native-maps';
import colors from "../config/colors";
function ViewImageScreen(props) {
return (
<View style={styles.container}>
<View style={styles.closeIcon}></View>
<View style={styles.deleteIcon}></View>
<MapView style={styles.mapStyle} />
<Image
resizeMode="contain"
style={styles.image}
source={require("../assets/wp6.jpg")}
/>
</View>
);
}
const styles = StyleSheet.create({
closeIcon: {
width: 50,
height: 50,
backgroundColor: colors.primary,
position: "absolute",
top: 40,
left: 30,
},
container: {
backgroundColor: colors.black,
flex: 1,
},
deleteIcon: {
width: 50,
height: 50,
backgroundColor: colors.secondary,
position: "absolute",
top: 40,
right: 30,
},
image: {
width: "100%",
height: "100%",
},
mapStyle: {
width: 300,
height: 300,
},
});
export default ViewImageScreen;

7956
src/package-lock.json
File diff suppressed because it is too large
View File

20
src/package.json

@ -8,16 +8,32 @@
"eject": "expo eject" "eject": "expo eject"
}, },
"dependencies": { "dependencies": {
"@react-native-community/masked-view": "0.1.10",
"@react-navigation/bottom-tabs": "^5.4.4",
"@react-navigation/native": "^5.3.2",
"@react-navigation/stack": "^5.3.5",
"expo": "~39.0.2", "expo": "~39.0.2",
"expo-image-picker": "~9.1.1",
"expo-location": "~9.0.0",
"expo-status-bar": "~1.0.2", "expo-status-bar": "~1.0.2",
"formik": "^2.2.5",
"react": "16.13.1", "react": "16.13.1",
"react-dom": "16.13.1", "react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-39.0.4.tar.gz", "react-native": "https://github.com/expo/react-native/archive/sdk-39.0.4.tar.gz",
"react-native-gesture-handler": "~1.7.0",
"react-native-maps": "0.27.1", "react-native-maps": "0.27.1",
"react-native-web": "~0.13.12"
"react-native-reanimated": "~1.13.0",
"react-native-safe-area-context": "3.1.4",
"react-native-screens": "~2.10.1",
"react-native-web": "~0.13.12",
"react-navigation": "^4.4.3",
"react-navigation-tabs": "^2.10.1",
"yup": "^0.28.5"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "~7.9.0"
"@babel/core": "^7.12.3",
"babel-core": "^6.26.3",
"babel-loader": "^8.2.1"
}, },
"private": true "private": true
} }

688
src/yarn.lock
File diff suppressed because it is too large
View File

Loading…
Cancel
Save