diff --git a/App.js b/App.js
index 83d0f59..9c49dc7 100644
--- a/App.js
+++ b/App.js
@@ -1,7 +1,6 @@
-import React, { useState, useEffect } from "react";
-import Home from "./components/Home/Home";
-
+import React from "react";
import { Text, View, StyleSheet, StatusBar } from "react-native";
+import { NativeRouter, Route, Routes } from "react-router-native";
import AppLoading from "expo-app-loading";
import {
useFonts,
@@ -9,11 +8,10 @@ import {
Epilogue_500Medium,
Epilogue_700Bold,
} from "@expo-google-fonts/epilogue";
-import { SafeAreaView } from "react-native-safe-area-context";
-import { NavigationContainer } from "@react-navigation/native";
-import { createNativeStackNavigator } from "@react-navigation/native-stack";
-
-const Stack = createNativeStackNavigator();
+import Home from "./components/Home/Home";
+import HomeCategoria from "./components/HomeCategoria/HomeCategoria";
+import AddCard from "./components/AddCard/AddCard";
+import ConfirmDelete from "./components/ConfirmDelete/ConfirmDelete";
export default function App() {
let [fontsLoaded] = useFonts({
@@ -21,25 +19,28 @@ export default function App() {
Epilogue_500Medium,
Epilogue_700Bold,
});
-
if (!fontsLoaded) {
return ;
} else {
return (
-
-
-
-
+
+ } />
+ }
+ />
+ }
+ />
+
+ }
/>
-
-
+
+
);
}
}
diff --git a/app.json b/app.json
index 9c8354f..2b5a01d 100644
--- a/app.json
+++ b/app.json
@@ -1,7 +1,7 @@
{
"expo": {
"name": "Study Cards",
- "slug": "Study Cards",
+ "slug": "study-cards",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
diff --git a/assets/icons/arrows-rotate-solid.svg b/assets/icons/arrows-rotate-solid.svg
new file mode 100644
index 0000000..b6e4dcf
--- /dev/null
+++ b/assets/icons/arrows-rotate-solid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/icons/play-solid.svg b/assets/icons/play-solid.svg
new file mode 100644
index 0000000..eed74b4
--- /dev/null
+++ b/assets/icons/play-solid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/icons/trash-solid.svg b/assets/icons/trash-solid.svg
new file mode 100644
index 0000000..ddc0dff
--- /dev/null
+++ b/assets/icons/trash-solid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/components/AddCard/AddCard.jsx b/components/AddCard/AddCard.jsx
new file mode 100644
index 0000000..3ac3f18
--- /dev/null
+++ b/components/AddCard/AddCard.jsx
@@ -0,0 +1,262 @@
+import React, { useState, useEffect } from 'react';
+import { View, Text, ScrollView, FlatList, TextInput, Button, TouchableOpacity } from 'react-native';
+import { styles } from './AddCard.styles';
+import { useParams } from 'react-router-native';
+import { LinearGradient } from 'expo-linear-gradient';
+import CategoriasIcon from '../../assets/icons/categorias.svg'
+import { Link } from 'react-router-native';
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
+import CardsDB from '../../services/sqlite/Card'
+import DetalhesDB from '../../services/sqlite/Detalhes'
+
+const AddCard = () => {
+ // Recebe os parametros vindos do router
+ const { categoriaId, cor, nome } = useParams()
+
+ // Cria os states para atualizar enquanto o usuário modifica
+ const [titulo, setTitulo] = useState('')
+ const [resposta, setResposta] = useState('')
+ const [tituloDetalhe, setTituloDetalhe] = useState('')
+ const [respostaDetalhe, setRespostaDetalhe] = useState('')
+ const [detalheVisibility, setDetalheVisibility] = useState(false)
+ const [adicionarVisibility, setAdicionarVisibility] = useState(true)
+ const [idDetalhe, setIdDetalhe] = useState(0)
+ const [detalhes, setDetalhes] = useState([])
+ const [detalheSelected, setDetalheSelected] = useState(-1)
+
+ // Pega as cores para formar o fundo gradiente
+ const gradientColors = getColors(cor)
+
+ const geraFlatList = () => {
+ console.log(detalhes.length)
+ if(detalhes.length != 0) {
+ console.log(detalhes[idDetalhe-1])
+ return(
+
+ Detalhes
+ item.id}
+ contentContainerStyle={styles.cardList}>
+
+
+ );
+ }
+ }
+
+ function setaDetalhes(){
+ if (detalheVisibility){
+ return(
+
+
+ setTituloDetalhe(novoTitulo)}
+ />
+ escondeDetalhe()}>
+ x
+
+
+ setRespostaDetalhe(novaResposta)}
+ />
+
+ )
+ }
+ }
+
+ function setaButtonAdicionar(){
+ if(adicionarVisibility && detalheSelected == -1 && !detalheVisibility){
+ return(
+ exibeDetalhe()}>
+ Adicionar Detalhe
+
+ )
+ }
+ }
+
+ function exibeSalvarDetalhe(){
+ if (detalheVisibility){
+ return (
+ salvarDetalhe()}>
+ Salvar Detalhe
+
+ );
+ }
+
+ }
+
+ function exibeDetalhe(){
+ setAdicionarVisibility(false)
+ setDetalheVisibility(true)
+ }
+
+ function escondeDetalhe(){
+ setAdicionarVisibility(true)
+ setDetalheVisibility(false)
+ setTituloDetalhe('')
+ setRespostaDetalhe('')
+ }
+
+ function salvarDetalhe() {
+ var novo_detalhe = {
+ id: idDetalhe,
+ titulo: tituloDetalhe,
+ resposta: respostaDetalhe
+ }
+ setDetalhes(detalhes.concat([novo_detalhe]))
+ setIdDetalhe(novo_detalhe.id + 1)
+ setTituloDetalhe('')
+ setRespostaDetalhe('')
+ setAdicionarVisibility(true)
+ setDetalheVisibility(false)
+ }
+
+ function deletarDetalhe(){
+ var indexDetalhe = detalhes.findIndex(detalhe => detalhe.id == detalheSelected);
+ setDetalhes(detalhes.filter((_, i) => i !== indexDetalhe));
+ setDetalheSelected(-1)
+ }
+
+ function showMenuDetalhe(){
+ if (detalheSelected != -1){
+ return (
+ deletarDetalhe()}>
+ Deletar
+
+ );
+ }
+ }
+
+ const renderDetalhe = ({item}) => {
+ id = item.id
+ var isSelected = false
+
+ if (detalheSelected == item.id){
+ isSelected = true
+ }
+
+ function selecionaDetalhe(){
+ if (detalheSelected == item.id){
+ setDetalheSelected(-1)
+ }else{
+ setDetalheSelected(item.id)
+ }
+ }
+ return (
+ selecionaDetalhe()}>
+ {item.titulo}
+ {item.resposta}
+
+ );
+ }
+
+ return (
+
+ // Constrói a visualização do card
+
+
+ Novo Card
+
+
+ {nome}
+
+
+
+
+
+
+ setTitulo(novoTitulo)}
+ />
+ setResposta(novaResposta)}
+ />
+
+ {geraFlatList()}
+ {setaDetalhes()}
+
+
+
+ {exibeSalvarDetalhe()}
+ {setaButtonAdicionar()}
+ {showMenuDetalhe()}
+
+
+
+ insertCard(titulo, resposta, categoriaId, detalhes)}>
+ Salvar
+
+
+ Cancelar
+
+
+
+ )
+}
+
+/** Transforma as cores em HEXADECIMAL para construir o gradiente */
+function getColors(colorStr){
+ var initialColor = colorStr.split("-")[0]
+ var finalColor = colorStr.split("-")[1]
+ return ["#" + initialColor, "#" + finalColor]
+
+}
+
+function insertCard(titulo, resposta, categoriaId, detalhes){
+ // Adiciona Card
+ var novoCard = {
+ titulo: titulo,
+ resposta: resposta,
+ categoriaId: categoriaId
+ }
+
+ //create
+ CardsDB.createCard(novoCard)
+ .then( id => {
+ console.log('Card created with id: '+ id)
+ insertDetalhes(detalhes, id)
+ })
+ .catch( err => console.log(err) )
+
+
+}
+
+function insertDetalhes(detalhes, cardId){
+ // Adiciona Detalhes
+ for(let detalhe of detalhes){
+
+ var novoDetalhe = {
+ cardId: cardId,
+ titulo: detalhe.titulo,
+ resposta: detalhe.resposta
+ }
+
+ //create
+ DetalhesDB.createDetalhe(novoDetalhe)
+ .then( id => console.log('Detalhe created with id: '+ id) )
+ .catch( err => console.log(err) )
+}
+}
+
+export default AddCard
\ No newline at end of file
diff --git a/components/AddCard/AddCard.styles.js b/components/AddCard/AddCard.styles.js
new file mode 100644
index 0000000..3f8e31f
--- /dev/null
+++ b/components/AddCard/AddCard.styles.js
@@ -0,0 +1,177 @@
+import { StyleSheet } from "react-native";
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
+
+export const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: "#1a1a1a",
+ width: "100%",
+ height: "100%",
+ alignItems: "center",
+ },
+
+ header_detalhe: {
+ marginTop: 20,
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "space-between",
+ },
+
+ close_detalhe: {
+ backgroundColor: "#c0392b",
+ padding: 4,
+ paddingTop: 0,
+ width: 32,
+ borderRadius: 50,
+ },
+
+ cardTituloDetalhe: {
+ width: vw(70),
+ color: "#f2f2f2",
+ textAlign: "left",
+ fontFamily: "Epilogue_700Bold",
+ fontSize: 17,
+ //borderBottomWidth: 2,
+ //borderBottomColor: "#f2f2f2",
+ },
+
+ btn_card: {
+ position: "absolute",
+ bottom: 20,
+ backgroundColor: "#1a1a1a",
+ borderRadius: 50,
+ textAlign: "center",
+ padding: 12,
+ },
+
+ menu_footer: {
+ height: vh(10),
+ width: "100%",
+ },
+
+ btn_text: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ width: vw(36),
+ textAlign: "center",
+ },
+
+ btn_card_text: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ textAlign: "center",
+ width: vw(70),
+ },
+
+ btn_card_text_x: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ textAlign: "center",
+ },
+
+ btn_right: {
+ position: "absolute",
+ right: 20,
+ bottom: 20,
+ },
+
+ btn_left: {
+ position: "absolute",
+ left: 20,
+ bottom: 20,
+ backgroundColor: "#c0392b",
+ },
+
+ btn_layout: {
+ backgroundColor: "#16a085",
+ padding: 10,
+ borderRadius: 50,
+ },
+
+ header: {
+ width: "100%",
+ },
+
+ titulo: {
+ color: "#f2f2f2",
+ marginLeft: 20,
+ marginTop: 20,
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 40,
+ },
+
+ categoria: {
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ marginLeft: 20,
+ marginTop: 10,
+ },
+
+ categoryText: {
+ color: "#f2f2f2",
+ marginLeft: 10,
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 23,
+ },
+
+ categoryItem: {
+ marginTop: 10,
+ borderRadius: 10,
+ width: "100%",
+ },
+
+ cardBody: {
+ flex: 1,
+ width: vw(90),
+ height: vh(70),
+ borderRadius: 40,
+ padding: 20,
+ marginLeft: vw(3),
+ marginRight: vw(3),
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ },
+
+ scrollView: {
+ marginTop: "5%",
+ marginBottom: 70,
+ },
+
+ cardTitulo: {
+ marginTop: 10,
+ width: vw(70),
+ color: "#f2f2f2",
+ textAlign: "left",
+ fontFamily: "Epilogue_700Bold",
+ fontSize: 25,
+ //backgroundColor: "#1a1a1a80",
+ borderRadius: 8,
+ //borderWidth: 1,
+ //borderColor: "#f2f2f2",
+ },
+
+ cardResposta: {
+ marginTop: 10,
+ width: vw(70),
+ color: "#f2f2f2",
+ textAlign: "left",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 17,
+ backgroundColor: "#1a1a1a60",
+ borderRadius: 8,
+ //borderWidth: 1,
+ // borderColor: "#f2f2f2",
+ padding: 8,
+ },
+
+ elevation: {
+ elevation: 15,
+ shadowColor: "#121212",
+ },
+});
diff --git a/components/AddCategoria/AddCategoria.jsx b/components/AddCategoria/AddCategoria.jsx
new file mode 100644
index 0000000..064587d
--- /dev/null
+++ b/components/AddCategoria/AddCategoria.jsx
@@ -0,0 +1,245 @@
+import React, { useState, useEffect } from 'react';
+import { View, Text, ScrollView, FlatList, TextInput, Button, TouchableOpacity } from 'react-native';
+import { styles } from './AddCategoria.styles';
+import { useParams } from 'react-router-native';
+import { LinearGradient } from 'expo-linear-gradient';
+import CategoriasIcon from '../../assets/icons/categorias.svg'
+import { Link } from 'react-router-native';
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
+import CardsDB from '../../services/sqlite/Card'
+import DetalhesDB from '../../services/sqlite/Detalhes'
+
+const AddCategoria = () => {
+ // Recebe os parametros vindos do router
+ const { categoriaId, cor, nome } = useParams()
+
+ // Cria os states para atualizar enquanto o usuário modifica
+ const [titulo, setTitulo] = useState('')
+ const [resposta, setResposta] = useState('')
+ const [tituloDetalhe, setTituloDetalhe] = useState('')
+ const [respostaDetalhe, setRespostaDetalhe] = useState('')
+ const [detalheVisibility, setDetalheVisibility] = useState(false)
+ const [adicionarVisibility, setAdicionarVisibility] = useState(true)
+ const [idDetalhe, setIdDetalhe] = useState(0)
+ const [detalhes, setDetalhes] = useState([])
+ const [detalheSelected, setDetalheSelected] = useState(-1)
+
+ // Pega as cores para formar o fundo gradiente
+ const gradientColors = getColors(cor)
+
+ const geraFlatList = () => {
+ console.log(detalhes.length)
+ if(detalhes.length != 0) {
+ console.log(detalhes[idDetalhe-1])
+ return(
+
+ Detalhes
+ item.id}
+ contentContainerStyle={styles.cardList}>
+
+
+ );
+ }
+ }
+
+ function setaDetalhes(){
+ if (detalheVisibility){
+ return(
+
+
+ setTituloDetalhe(novoTitulo)}
+ />
+ escondeDetalhe()}>
+ x
+
+
+ setRespostaDetalhe(novaResposta)}
+ />
+
+ )
+ }
+ }
+
+ function setaButtonAdicionar(){
+ if(adicionarVisibility && detalheSelected == -1 && !detalheVisibility){
+ return(
+ exibeDetalhe()}>
+ Adicionar Detalhe
+
+ )
+ }
+ }
+
+ function exibeSalvarDetalhe(){
+ if (detalheVisibility){
+ return (
+ salvarDetalhe()}>
+ Salvar Detalhe
+
+ );
+ }
+
+ }
+
+ function exibeDetalhe(){
+ setAdicionarVisibility(false)
+ setDetalheVisibility(true)
+ }
+
+ function escondeDetalhe(){
+ setAdicionarVisibility(true)
+ setDetalheVisibility(false)
+ setTituloDetalhe('')
+ setRespostaDetalhe('')
+ }
+
+ function salvarDetalhe() {
+ var novo_detalhe = {
+ id: idDetalhe,
+ titulo: tituloDetalhe,
+ resposta: respostaDetalhe
+ }
+ setDetalhes(detalhes.concat([novo_detalhe]))
+ setIdDetalhe(novo_detalhe.id + 1)
+ setTituloDetalhe('')
+ setRespostaDetalhe('')
+ setAdicionarVisibility(true)
+ setDetalheVisibility(false)
+ }
+
+ function deletarDetalhe(){
+ var indexDetalhe = detalhes.findIndex(detalhe => detalhe.id == detalheSelected);
+ setDetalhes(detalhes.filter((_, i) => i !== indexDetalhe));
+ setDetalheSelected(-1)
+ }
+
+ function showMenuDetalhe(){
+ if (detalheSelected != -1){
+ return (
+ deletarDetalhe()}>
+ Deletar
+
+ );
+ }
+ }
+
+ const renderDetalhe = ({item}) => {
+ id = item.id
+ var isSelected = false
+
+ if (detalheSelected == item.id){
+ isSelected = true
+ }
+
+ function selecionaDetalhe(){
+ if (detalheSelected == item.id){
+ setDetalheSelected(-1)
+ }else{
+ setDetalheSelected(item.id)
+ }
+ }
+ return (
+ selecionaDetalhe()}>
+ {item.titulo}
+ {item.resposta}
+
+ );
+ }
+
+ return (
+
+ // Constrói a visualização do card
+
+
+ Novo Card
+
+
+ {nome}
+
+
+
+
+
+
+ setTitulo(novoTitulo)}
+ />
+ setResposta(novaResposta)}
+ />
+
+ {geraFlatList()}
+ {setaDetalhes()}
+
+
+
+ {exibeSalvarDetalhe()}
+ {setaButtonAdicionar()}
+ {showMenuDetalhe()}
+
+
+
+ insertCard(titulo, resposta, categoriaId, detalhes)}>
+ Salvar
+
+
+ Cancelar
+
+
+
+ )
+}
+
+/** Transforma as cores em HEXADECIMAL para construir o gradiente */
+function getColors(colorStr){
+ var initialColor = colorStr.split("-")[0]
+ var finalColor = colorStr.split("-")[1]
+ return ["#" + initialColor, "#" + finalColor]
+
+}
+
+function insertCard(titulo, resposta, categoriaId, detalhes){
+ // Adiciona Card
+ var novoCard = {
+ titulo: titulo,
+ resposta: resposta,
+ categoriaId: categoriaId
+ }
+
+ //create
+ CardsDB.createCard(novoCard)
+ .then( id => {
+ console.log('Card created with id: '+ id)
+ insertDetalhes(detalhes, id)
+ })
+ .catch( err => console.log(err) )
+
+
+}
+
+export default AddCategoria
\ No newline at end of file
diff --git a/components/AddCategoria/AddCategoria.styles.js b/components/AddCategoria/AddCategoria.styles.js
new file mode 100644
index 0000000..3f8e31f
--- /dev/null
+++ b/components/AddCategoria/AddCategoria.styles.js
@@ -0,0 +1,177 @@
+import { StyleSheet } from "react-native";
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
+
+export const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: "#1a1a1a",
+ width: "100%",
+ height: "100%",
+ alignItems: "center",
+ },
+
+ header_detalhe: {
+ marginTop: 20,
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "space-between",
+ },
+
+ close_detalhe: {
+ backgroundColor: "#c0392b",
+ padding: 4,
+ paddingTop: 0,
+ width: 32,
+ borderRadius: 50,
+ },
+
+ cardTituloDetalhe: {
+ width: vw(70),
+ color: "#f2f2f2",
+ textAlign: "left",
+ fontFamily: "Epilogue_700Bold",
+ fontSize: 17,
+ //borderBottomWidth: 2,
+ //borderBottomColor: "#f2f2f2",
+ },
+
+ btn_card: {
+ position: "absolute",
+ bottom: 20,
+ backgroundColor: "#1a1a1a",
+ borderRadius: 50,
+ textAlign: "center",
+ padding: 12,
+ },
+
+ menu_footer: {
+ height: vh(10),
+ width: "100%",
+ },
+
+ btn_text: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ width: vw(36),
+ textAlign: "center",
+ },
+
+ btn_card_text: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ textAlign: "center",
+ width: vw(70),
+ },
+
+ btn_card_text_x: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ textAlign: "center",
+ },
+
+ btn_right: {
+ position: "absolute",
+ right: 20,
+ bottom: 20,
+ },
+
+ btn_left: {
+ position: "absolute",
+ left: 20,
+ bottom: 20,
+ backgroundColor: "#c0392b",
+ },
+
+ btn_layout: {
+ backgroundColor: "#16a085",
+ padding: 10,
+ borderRadius: 50,
+ },
+
+ header: {
+ width: "100%",
+ },
+
+ titulo: {
+ color: "#f2f2f2",
+ marginLeft: 20,
+ marginTop: 20,
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 40,
+ },
+
+ categoria: {
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ marginLeft: 20,
+ marginTop: 10,
+ },
+
+ categoryText: {
+ color: "#f2f2f2",
+ marginLeft: 10,
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 23,
+ },
+
+ categoryItem: {
+ marginTop: 10,
+ borderRadius: 10,
+ width: "100%",
+ },
+
+ cardBody: {
+ flex: 1,
+ width: vw(90),
+ height: vh(70),
+ borderRadius: 40,
+ padding: 20,
+ marginLeft: vw(3),
+ marginRight: vw(3),
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ },
+
+ scrollView: {
+ marginTop: "5%",
+ marginBottom: 70,
+ },
+
+ cardTitulo: {
+ marginTop: 10,
+ width: vw(70),
+ color: "#f2f2f2",
+ textAlign: "left",
+ fontFamily: "Epilogue_700Bold",
+ fontSize: 25,
+ //backgroundColor: "#1a1a1a80",
+ borderRadius: 8,
+ //borderWidth: 1,
+ //borderColor: "#f2f2f2",
+ },
+
+ cardResposta: {
+ marginTop: 10,
+ width: vw(70),
+ color: "#f2f2f2",
+ textAlign: "left",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 17,
+ backgroundColor: "#1a1a1a60",
+ borderRadius: 8,
+ //borderWidth: 1,
+ // borderColor: "#f2f2f2",
+ padding: 8,
+ },
+
+ elevation: {
+ elevation: 15,
+ shadowColor: "#121212",
+ },
+});
diff --git a/components/BtnAdd/BtnAdd.jsx b/components/BtnAdd/BtnAdd.jsx
deleted file mode 100644
index 0611842..0000000
--- a/components/BtnAdd/BtnAdd.jsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import { View, Text, TouchableOpacity } from 'react-native';
-import { styles } from './BtnAdd.styles';
-//import { BtnAddWrapper } from './BtnAdd.styles';
-
-const BtnAdd = (props) => {
- return (
-
- +
-
- );
-}
-
-export default BtnAdd;
diff --git a/components/BtnAdd/BtnAdd.styles.js b/components/BtnAdd/BtnAdd.styles.js
index a7f4326..0dd2916 100644
--- a/components/BtnAdd/BtnAdd.styles.js
+++ b/components/BtnAdd/BtnAdd.styles.js
@@ -1,20 +1,37 @@
-import { StyleSheet } from 'react-native';
+import { StyleSheet } from "react-native";
export const styles = StyleSheet.create({
- button: {
- backgroundColor: '#f2f2f2',
- alignItems:'center',
- justifyContent:'center',
- width:90,
- height:90,
- borderRadius:50,
- position: 'absolute',
- bottom: 20,
- right: 20,
- },
+ button: {
+ backgroundColor: "#f2f2f2",
+ alignItems: "center",
+ justifyContent: "center",
+ width: 65,
+ height: 65,
+ borderRadius: 50,
+ position: "absolute",
+ bottom: 20,
+ right: 125,
+ },
- plus: {
- fontSize: 50,
- color: '#1A1A1A',
- },
- });
+ button_categoria: {
+ backgroundColor: "#f2f2f2",
+ alignItems: "center",
+ justifyContent: "center",
+ width: 90,
+ height: 90,
+ borderRadius: 50,
+ position: "absolute",
+ bottom: 20,
+ right: 20,
+ },
+
+ plus: {
+ fontSize: 40,
+ color: "#1A1A1A",
+ },
+
+ plus_categoria: {
+ fontSize: 55,
+ color: "#1A1A1A",
+ },
+});
diff --git a/components/BtnAdd/BtnAddCard.jsx b/components/BtnAdd/BtnAddCard.jsx
new file mode 100644
index 0000000..fdda527
--- /dev/null
+++ b/components/BtnAdd/BtnAddCard.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { View, Text, TouchableOpacity } from 'react-native';
+import { styles } from './BtnAdd.styles';
+//import { BtnAddWrapper } from './BtnAdd.styles';
+import { Link } from 'react-router-native';
+
+const BtnAddCard = (props) => {
+
+ return (
+
+ +
+
+ );
+}
+
+export default BtnAddCard;
diff --git a/components/BtnAdd/BtnAddCategoria.jsx b/components/BtnAdd/BtnAddCategoria.jsx
new file mode 100644
index 0000000..4a4be27
--- /dev/null
+++ b/components/BtnAdd/BtnAddCategoria.jsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { View, Text, TouchableOpacity } from 'react-native';
+import { styles } from './BtnAdd.styles';
+//import { BtnAddWrapper } from './BtnAdd.styles';
+import { Link } from 'react-router-native';
+
+const BtnAddCategoria = (props) => {
+ return (
+
+ +
+
+ );
+}
+
+export default BtnAddCategoria;
diff --git a/components/BtnCategorias/BtnCategorias.jsx b/components/BtnCategorias/BtnCategorias.jsx
index 39bdaf9..1a291e7 100644
--- a/components/BtnCategorias/BtnCategorias.jsx
+++ b/components/BtnCategorias/BtnCategorias.jsx
@@ -3,15 +3,18 @@ import { View, Text, TouchableOpacity } from 'react-native';
import { styles } from './BtnCategorias.styles';
//import { BtnCategoriasWrapper } from './BtnCategorias.styles';
import CategoriasIcon from '../../assets/icons/categorias.svg'
+import { Link } from 'react-router-native'
const BtnCategorias = (props) => {
return (
-
-
- Categorias
-
+
+
+ {/**/}
+ Voltar
+
+
);
}
diff --git a/components/BtnCategorias/BtnCategorias.styles.js b/components/BtnCategorias/BtnCategorias.styles.js
index 70c0227..f3e30d1 100644
--- a/components/BtnCategorias/BtnCategorias.styles.js
+++ b/components/BtnCategorias/BtnCategorias.styles.js
@@ -1,26 +1,32 @@
-import { StyleSheet } from 'react-native';
-import { vw, vh, vmin, vmax } from 'react-native-expo-viewport-units';
+import { StyleSheet } from "react-native";
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
export const styles = StyleSheet.create({
- button: {
- backgroundColor: '#f2f2f2',
- display: 'flex',
- flexDirection: 'row',
- padding: 10,
- paddingLeft: 20,
- paddingRight: 20,
- alignItems:'center',
- justifyContent:'center',
- borderRadius:50,
- position: 'absolute',
- bottom: 20,
- left: 20,
- },
+ button: {
+ backgroundColor: "#f2f2f2",
+ display: "flex",
+ flexDirection: "row",
+ padding: 10,
+ paddingLeft: 20,
+ paddingRight: 20,
+ alignItems: "center",
+ justifyContent: "center",
+ borderRadius: 50,
+ position: "absolute",
+ bottom: 20,
+ left: 20,
+ },
- text: {
- marginLeft: 10,
- fontSize: 20,
- color: '#1A1A1A',
- fontFamily: 'Epilogue_700Bold',
- },
-});
\ No newline at end of file
+ view: {
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "center",
+ },
+
+ text: {
+ fontSize: 20,
+ color: "#1A1A1A",
+ fontFamily: "Epilogue_700Bold",
+ },
+});
diff --git a/components/BtnPlay/BtnPlay.jsx b/components/BtnPlay/BtnPlay.jsx
new file mode 100644
index 0000000..9e8c02d
--- /dev/null
+++ b/components/BtnPlay/BtnPlay.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { View, Text, TouchableOpacity } from 'react-native';
+import { styles } from './BtnPlay.styles';
+//import { BtnCategoriasWrapper } from './BtnCategorias.styles';
+import Play from '../../assets/icons/play-solid.svg'
+import { Link } from 'react-router-native'
+
+
+const BtnCategorias = (props) => {
+
+ return (
+
+
+
+
+
+ );
+}
+
+export default BtnCategorias;
diff --git a/components/BtnPlay/BtnPlay.styles.js b/components/BtnPlay/BtnPlay.styles.js
new file mode 100644
index 0000000..010a555
--- /dev/null
+++ b/components/BtnPlay/BtnPlay.styles.js
@@ -0,0 +1,31 @@
+import { StyleSheet } from "react-native";
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
+
+export const styles = StyleSheet.create({
+ button: {
+ backgroundColor: "#f2f2f2",
+ display: "flex",
+ flexDirection: "row",
+
+ padding: 28,
+ alignItems: "center",
+ justifyContent: "center",
+ borderRadius: 50,
+ position: "absolute",
+ bottom: 20,
+ right: 20,
+ },
+
+ view: {
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "center",
+ },
+
+ text: {
+ fontSize: 20,
+ color: "#1A1A1A",
+ fontFamily: "Epilogue_700Bold",
+ },
+});
diff --git a/components/Card/Card.jsx b/components/Card/Card.jsx
index e135a29..95f8536 100644
--- a/components/Card/Card.jsx
+++ b/components/Card/Card.jsx
@@ -1,53 +1,105 @@
import React, { useState } from 'react';
-import { View, Text, ScrollView } from 'react-native';
+import { View, Text, ScrollView, TouchableOpacity, FlatList } from 'react-native';
import { styles } from './Card.styles';
+import { verso_styles } from './Verso.styles';
//import { CardWrapper } from './Card.styles';
import { LinearGradient } from 'expo-linear-gradient';
import LampIconOn from '../../assets/icons/lamp-on.svg';
import LampIconOff from '../../assets/icons/lamp-off.svg';
import StarIcon from '../../assets/icons/star.svg';
+import TurnCardIcon from '../../assets/icons/arrows-rotate-solid.svg'
+import TrashIcon from '../../assets/icons/trash-solid.svg'
+import CardsDB from '../../services/sqlite/Card'
+import DetalhesDB from '../../services/sqlite/Detalhes'
+import { Link } from 'react-router-native';
-const Card = (props) => {
- const gradientColors = getColors(props.cor)
- const [showDica, setShowDica] = useState(false)
+class Card extends React.Component {
- function getLampIcon(showDica){
- if(showDica == true){
- return (
-
- setShowDica(false)} />
-
- );
-
- }else {
- return (
-
- setShowDica(true)} />
-
- );
- }
+ state = {
+ detalhes: [],
+ id: this.props.id,
+ categoriaId: this.props.categoriaId,
+ categoriaNome: this.props.categoriaNome,
+ cor: this.props.cor,
+ titulo: this.props.titulo,
+ resposta: this.props.resposta,
+ isTurned: false
+ }
+
+ componentDidMount() {
+ this.getDetalhes();
}
+ getDetalhes = () => {
+ DetalhesDB.allDetalhesCard(this.state.id).then(res => {
+ this.setState({
+ detalhes: res,
+ });
+ });
+ }
+
+ render (){
+ const gradientColors = getColors(this.state.cor)
+ const renderDetalhe = ({item}) => {
+ return (
+
+ {item.titulo}
+ {item.resposta}
+
+ );
+}
return (
-
-
+
+
+
+
+ {this.state.isTurned ? verso(this.state): frente(this.state)}
+ {console.log(`/confirm-delete/Card/${this.state.categoriaId}/${this.state.categoriaNome}/${this.state.cor}/${this.state.titulo}/${this.state.id}`)}
+
+
+
+
+ this.setState({
+ isTurned: this.state.isTurned ? false : true,
+ })}>
+
+
+
+
+
+ );
+
+ function frente(card){
+ return(
-
- {props.titulo}
- {returnDica(showDica, styles, props.dica)}
+
+ {card.titulo}
+
+
+ )
+ }
+
+ function verso(card){
+ return(
+ // Constrói a visualização do card
+
+ {card.titulo}
+ {card.resposta}
+ {(card.detalhes.length > 0) ? Detalhes : null}
+ item.id}
+ contentContainerStyle={styles.cardList}>
+
-
- {getLampIcon(showDica)}
-
-
-
-
-
-);
+ );
+ }
+ }
}
function getColors(colorStr){
@@ -57,30 +109,29 @@ function getColors(colorStr){
}
-function getLampIcon(showDica){
- if(showDica == true){
- return (
-
- );
-
- }else {
- return (
-
- );
- }
+function deleteCard(cardId){
+
+ //delete
+ CardsDB.removeCard(cardId)
+ .then( id => {
+ console.log('Card deleted with id: '+ id)
+ deleteDetalhes(cardId)
+ })
+ .catch( err => console.log(err) )
+
+
}
-function returnDica(showDica, styles, dica) {
- if(showDica == true){
- return (
-
- {dica}
- );
- }else{
- return (
-
- );
- }
+function deleteDetalhes(cardId){
+
+ //delete
+ DetalhesDB.removeDetalhe(cardId)
+ .then( cardId => {
+ console.log('Detalhes deleted with cardId: '+ cardId)
+ })
+ .catch( err => console.log(err) )
+
+
}
export default Card;
diff --git a/components/Card/Card.styles.js b/components/Card/Card.styles.js
index a331d08..56ac845 100644
--- a/components/Card/Card.styles.js
+++ b/components/Card/Card.styles.js
@@ -5,7 +5,7 @@ export const styles = StyleSheet.create({
cardBody: {
flex: 1,
width: vw(80),
- height: vh(65),
+ height: vh(68),
borderRadius: 40,
padding: 20,
marginLeft: vw(3),
diff --git a/components/Card/Verso.styles.js b/components/Card/Verso.styles.js
new file mode 100644
index 0000000..ca1e1de
--- /dev/null
+++ b/components/Card/Verso.styles.js
@@ -0,0 +1,193 @@
+import { StyleSheet } from "react-native";
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
+
+export const verso_styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: "#1a1a1a",
+ width: "100%",
+ height: "100%",
+ alignItems: "center",
+ },
+
+ verse_button: {
+ position: "absolute",
+ right: 23,
+ bottom: 23,
+ },
+
+ trash_button: {
+ position: "absolute",
+ left: 23,
+ //top: 0,
+ bottom: 23,
+ backgroundColor: "#c0392b",
+ padding: 15,
+ borderRadius: 50,
+ },
+
+ header_detalhe: {
+ marginTop: 20,
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "space-between",
+ },
+
+ close_detalhe: {
+ backgroundColor: "#c0392b",
+ padding: 4,
+ paddingTop: 0,
+ width: 32,
+ borderRadius: 50,
+ },
+
+ cardTituloDetalhe: {
+ width: vw(70),
+ color: "#f2f2f2",
+ textAlign: "left",
+ fontFamily: "Epilogue_700Bold",
+ fontSize: 17,
+ //borderBottomWidth: 2,
+ //borderBottomColor: "#f2f2f2",
+ },
+
+ btn_card: {
+ position: "absolute",
+ bottom: 20,
+ backgroundColor: "#1a1a1a",
+ borderRadius: 50,
+ textAlign: "center",
+ padding: 12,
+ },
+
+ menu_footer: {
+ height: vh(10),
+ width: "100%",
+ },
+
+ btn_text: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ width: vw(36),
+ textAlign: "center",
+ },
+
+ btn_card_text: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ textAlign: "center",
+ width: vw(70),
+ },
+
+ btn_card_text_x: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ textAlign: "center",
+ },
+
+ btn_right: {
+ position: "absolute",
+ right: 20,
+ bottom: 20,
+ },
+
+ btn_left: {
+ position: "absolute",
+ left: 20,
+ bottom: 20,
+ backgroundColor: "#c0392b",
+ },
+
+ btn_layout: {
+ backgroundColor: "#16a085",
+ padding: 10,
+ borderRadius: 50,
+ },
+
+ header: {
+ width: "100%",
+ },
+
+ titulo: {
+ color: "#f2f2f2",
+ marginLeft: 20,
+ marginTop: 20,
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 40,
+ },
+
+ categoria: {
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ marginLeft: 20,
+ marginTop: 10,
+ },
+
+ categoryText: {
+ color: "#f2f2f2",
+ marginLeft: 10,
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 23,
+ },
+
+ categoryItem: {
+ marginTop: 10,
+ borderRadius: 10,
+ width: "100%",
+ },
+
+ cardBody: {
+ flex: 1,
+ width: vw(90),
+ height: vh(70),
+ borderRadius: 40,
+ padding: 20,
+ marginLeft: vw(3),
+ marginRight: vw(3),
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ },
+
+ scrollView: {
+ marginTop: "5%",
+ marginBottom: 70,
+ },
+
+ cardTitulo: {
+ marginTop: 10,
+ width: vw(70),
+ color: "#f2f2f2",
+ textAlign: "left",
+ fontFamily: "Epilogue_700Bold",
+ fontSize: 25,
+ //backgroundColor: "#1a1a1a80",
+ borderRadius: 8,
+ //borderWidth: 1,
+ //borderColor: "#f2f2f2",
+ },
+
+ cardResposta: {
+ marginTop: 10,
+ width: vw(70),
+ color: "#f2f2f2",
+ textAlign: "left",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 17,
+ backgroundColor: "#1a1a1a60",
+ borderRadius: 8,
+ //borderWidth: 1,
+ // borderColor: "#f2f2f2",
+ padding: 8,
+ },
+
+ elevation: {
+ elevation: 15,
+ shadowColor: "#121212",
+ },
+});
diff --git a/components/CardList/CardList.jsx b/components/CardList/CardList.jsx
index a61cbcb..35828c0 100644
--- a/components/CardList/CardList.jsx
+++ b/components/CardList/CardList.jsx
@@ -5,66 +5,44 @@ import { styles } from './CardList.styles';
import * as cards from '../test/cards.json';
import * as favoritos from '../test/favoritos.json';
import Card from '../Card/Card';
-
-const CardList = (props) => {
-
- const renderCard = ({item}) => {
-
- return (
-
- );
+import CardsDB from '../../services/sqlite/Card'
+
+class CardList extends React.Component {
+
+ state = {
+ categoriaId: this.props.categoriaId,
+ categoriaNome: this.props.categoriaNome,
+ cor: this.props.cor,
}
- return (
- item.cardId}
- contentContainerStyle={styles.cardList}>
-
- );
-}
-
-function getCardsByCategoryId(categoryId) {
- var cardsObj = [];
-
- if(categoryId == "a"){
- for(var i=0; i < (Object.keys(cards).length - 1) ; i++){
- cardsObj.push(cards[i]);
- }
- }else if(categoryId == "f"){
- let favoritosIds = getFavoritosCardIds()
-
- var array = ["pal1", "pal2", "pal3"]
- for(var pos in favoritosIds){
-
- for(var i=0; i < (Object.keys(cards).length - 1); i++){
-
- if(cards[i].cardId == favoritosIds[pos]){
- console.log(cards[i].titulo)
- cardsObj.push(cards[i])
- }
- }
- }
-
- }else{
- for(var i=0; i < (Object.keys(cards).length - 1); i++){
- if(cards[i].categoriaId == categoryId){
- cardsObj.push(cards[i])
- }
- }
+ componentDidMount() {
+ this.getCards();
}
- return cardsObj
-}
-
-function getFavoritosCardIds(){
- var favoritosIds = []
- for(var i=0; i < (Object.keys(favoritos).length - 1); i++){
- favoritosIds.push(favoritos[i].cardId)
+ getCards = () => {
+ CardsDB.allCardsCategory(this.state.categoriaId).then(res => {
+ this.setState({
+ cards: res,
+ });
+ });
+ }
+ render(){
+ const renderCard = ({item}) => {
+ return (
+
+ );
+ }
+ return (
+ item.id}
+ contentContainerStyle={styles.cardList}>
+
+ );
}
- return favoritosIds
}
export default CardList;
diff --git a/components/Categoria/Categoria.jsx b/components/Categoria/Categoria.jsx
new file mode 100644
index 0000000..7ab81cf
--- /dev/null
+++ b/components/Categoria/Categoria.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { View, Text, ScrollView, FlatList } from 'react-native';
+import { styles } from './Categoria.styles';
+//import { CategoriasWrapper } from './Categorias.styles';
+import CardsIcon from '../../assets/icons/cards.svg'
+
+const Categoria = (props) => {
+ color = "#" + props.cor.split("-")[0]
+ return(
+
+ {props.nome}
+
+
+ {props.quantCards}
+
+
+ );
+
+}
+
+export default Categoria;
diff --git a/components/Categoria/Categoria.styles.js b/components/Categoria/Categoria.styles.js
new file mode 100644
index 0000000..32f8a1c
--- /dev/null
+++ b/components/Categoria/Categoria.styles.js
@@ -0,0 +1,36 @@
+import { StyleSheet } from "react-native";
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
+
+export const styles = StyleSheet.create({
+ nome: {
+ marginTop: 10,
+ color: "#f2f2f2",
+ textAlign: "center",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ },
+ categoria: {
+ display: "flex",
+ flexDirection: "row",
+ justifyContent: "space-between",
+ padding: 20,
+ alignItems: "center",
+ backgroundColor: "#111",
+ borderRadius: 8,
+ marginBottom: 15,
+ borderLeftWidth: 10,
+ },
+
+ textQuantCards: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ marginLeft: 5,
+ },
+
+ quantCards: {
+ display: "flex",
+ flexDirection: "row",
+ alignItems: "center",
+ },
+});
diff --git a/components/Categorias/Categorias.jsx b/components/Categorias/Categorias.jsx
deleted file mode 100644
index 0e6488b..0000000
--- a/components/Categorias/Categorias.jsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import React, { PureComponent } from 'react';
-import { View, Text } from 'react-native';
-import { connect } from 'react-redux';
-import PropTypes from 'prop-types';
-import * as styles from './Categorias.styles';
-//import { CategoriasWrapper } from './Categorias.styles';
-
-class Categorias extends PureComponent {
- constructor(props) {
- super(props);
-
- this.state = {
- hasError: false,
- };
- }
-
- componentWillMount = () => {
- console.log('Categorias will mount');
- }
-
- componentDidMount = () => {
- console.log('Categorias mounted');
- }
-
- componentWillReceiveProps = (nextProps) => {
- console.log('Categorias will receive props', nextProps);
- }
-
- componentWillUpdate = (nextProps, nextState) => {
- console.log('Categorias will update', nextProps, nextState);
- }
-
-
- componentDidUpdate = () => {
- console.log('Categorias did update');
- }
-
- componentWillUnmount = () => {
- console.log('Categorias will unmount');
- }
-
- render () {
- if (this.state.hasError) {
- return (
-
- Something went wrong.
-
- );
- }
- return (
-
- Test content
-
- );
- }
-}
-
-Categorias.propTypes = {
- // bla: PropTypes.string,
-};
-
-Categorias.defaultProps = {
- // bla: 'test',
-};
-
-const mapStateToProps = state => ({
- // blabla: state.blabla,
-});
-
-const mapDispatchToProps = dispatch => ({
- // fnBlaBla: () => dispatch(action.name()),
-});
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps,
-)(Categorias);
diff --git a/components/Categorias/Categorias.styles.js b/components/Categorias/Categorias.styles.js
deleted file mode 100644
index 80a725e..0000000
--- a/components/Categorias/Categorias.styles.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import styled from 'styled-components/native';
-
-export const CategoriasWrapper = styled.View`
- flex: 1
-`;
diff --git a/components/Categorias/index.js b/components/Categorias/index.js
deleted file mode 100644
index fb8fb14..0000000
--- a/components/Categorias/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import Categorias from './Categorias';
-
-export default Categorias;
diff --git a/components/CategoriasList/CategoriasList.jsx b/components/CategoriasList/CategoriasList.jsx
index 8f50cf3..91d9b8d 100644
--- a/components/CategoriasList/CategoriasList.jsx
+++ b/components/CategoriasList/CategoriasList.jsx
@@ -1,64 +1,54 @@
-import React, { PureComponent } from 'react';
-import { View, Text } from 'react-native';
-import PropTypes from 'prop-types';
-import * as styles from './CategoriasList.styles';
-//import { CategoriasListWrapper } from './CategoriasList.styles';
+import React from 'react';
+import { View, Text, ScrollView, FlatList, TouchableOpacity } from 'react-native';
+import { styles } from './CategoriasList.styles';
+//import { CardListWrapper } from './CardList.styles';
+import Categoria from '../Categoria/Categoria';
+import CategoriaDB from '../../services/sqlite/Categoria'
+import CardDB from '../../services/sqlite/Card'
+import { Link } from 'react-router-native'
-class CategoriasList extends PureComponent {
- constructor(props) {
- super(props);
+class CategoriasList extends React.Component {
- this.state = {
- hasError: false,
- };
+ state = {
+ categorias: [],
}
- componentWillMount = () => {
- console.log('CategoriasList will mount');
+ componentDidMount() {
+ this.getCategorias();
}
- componentDidMount = () => {
- console.log('CategoriasList mounted');
+ getCategorias = () => {
+ CategoriaDB.allCategorias().then(res => {
+ this.setState({
+ categorias: res,
+ });
+ });
}
- componentWillReceiveProps = (nextProps) => {
- console.log('CategoriasList will receive props', nextProps);
- }
-
- componentWillUpdate = (nextProps, nextState) => {
- console.log('CategoriasList will update', nextProps, nextState);
- }
-
- componentDidUpdate = () => {
- console.log('CategoriasList did update');
- }
-
- componentWillUnmount = () => {
- console.log('CategoriasList will unmount');
- }
-
- render () {
- if (this.state.hasError) {
+ render() {
+ const renderCategoria = ({item}) => {
return (
-
- Something went wrong.
-
+ console.log(item.nome)}>
+
+
);
}
+ if (Object.keys(this.state.categorias).length > 0){
return (
-
- Test content
-
- );
- }
+ item.id}
+ contentContainerStyle={styles.categoriasList}>
+
+
+ );
+}else{
+ return(
+ Crie uma nova categoria
+ );
+ }
+ }
}
-CategoriasList.propTypes = {
- // bla: PropTypes.string,
-};
-
-CategoriasList.defaultProps = {
- // bla: 'test',
-};
-
export default CategoriasList;
diff --git a/components/CategoriasList/CategoriasList.styles.js b/components/CategoriasList/CategoriasList.styles.js
index 329bd39..0113bcf 100644
--- a/components/CategoriasList/CategoriasList.styles.js
+++ b/components/CategoriasList/CategoriasList.styles.js
@@ -1,5 +1,17 @@
-import styled from 'styled-components/native';
+import { StyleSheet } from "react-native";
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
-export const CategoriasListWrapper = styled.View`
- flex: 1
-`;
+export const styles = StyleSheet.create({
+ categoriasList: {
+ paddingLeft: 20 - vw(3),
+ paddingRight: 20 - vw(3),
+ },
+
+ semCategoriasMensagem: {
+ marginTop: 10,
+ color: "#f2f2f2",
+ textAlign: "center",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 20,
+ },
+});
diff --git a/components/ConfirmDelete/ConfirmDelete.jsx b/components/ConfirmDelete/ConfirmDelete.jsx
new file mode 100644
index 0000000..bd9a29b
--- /dev/null
+++ b/components/ConfirmDelete/ConfirmDelete.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import { View, Text, TouchableOpacity } from 'react-native';
+import { styles } from './ConfirmDelete.styles';
+//import { BtnAddWrapper } from './BtnAdd.styles';
+import { useParams, Link } from 'react-router-native';
+import CardsDB from '../../services/sqlite/Card'
+import DetalhesDB from '../../services/sqlite/Detalhes'
+
+const ConfirmDelete = (props) => {
+
+ const { who, categoriaId, categoriaNome, cor, nome, id } = useParams()
+ console.log(props)
+ "/home-categoria/:id/:cor/:nome"
+ return(
+
+
+ Deseja realmente excluir {(who == "Card") ? `o card "${nome}"?` : `a categoria "${nome}"?`}
+
+ (who == "Card") ? deleteCard(id) : null}>
+ Sim
+
+
+ Não, voltar
+
+
+
+
+ );
+}
+
+
+
+function deleteCard(cardId){
+
+ //delete
+ CardsDB.removeCard(cardId)
+ .then( id => {
+ console.log('Card deleted with id: '+ id)
+ deleteDetalhes(cardId)
+ })
+ .catch( err => console.log(err) )
+
+
+}
+
+function deleteDetalhes(cardId){
+
+ //delete
+ DetalhesDB.removeDetalhe(cardId)
+ .then( cardId => {
+ console.log('Detalhes deleted with cardId: '+ cardId)
+ })
+ .catch( err => console.log(err) )
+
+
+}
+
+export default ConfirmDelete;
diff --git a/components/ConfirmDelete/ConfirmDelete.styles.js b/components/ConfirmDelete/ConfirmDelete.styles.js
new file mode 100644
index 0000000..ef62c25
--- /dev/null
+++ b/components/ConfirmDelete/ConfirmDelete.styles.js
@@ -0,0 +1,58 @@
+import { StyleSheet } from "react-native";
+import { vw, vh, vmin, vmax } from "react-native-expo-viewport-units";
+
+export const styles = StyleSheet.create({
+ backgroud: {
+ flex: 1,
+ backgroundColor: "#1a1a1a",
+ width: "100%",
+ height: "100%",
+ justifyContent: "center",
+ },
+
+ modal: {
+ backgroundColor: "#2a2a2a",
+ padding: 20,
+ margin: 20,
+ borderRadius: 38,
+ },
+
+ btn_container: {
+ display: "flex",
+ flexDirection: "row",
+ justifyContent: "space-between",
+ },
+
+ categoryText: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_500Medium",
+ fontSize: 25,
+ marginBottom: 40,
+ },
+
+ plus: {
+ fontSize: 50,
+ color: "#1A1A1A",
+ },
+
+ btn_text: {
+ color: "#f2f2f2",
+ fontFamily: "Epilogue_700Bold",
+ fontSize: 17,
+ width: vw(32),
+ textAlign: "center",
+ },
+
+ btn_right: {
+ backgroundColor: "#16a085",
+ },
+
+ btn_left: {
+ backgroundColor: "#c0392b",
+ },
+
+ btn_layout: {
+ padding: 10,
+ borderRadius: 50,
+ },
+});
diff --git a/components/Home/Home.jsx b/components/Home/Home.jsx
index 48fdba6..943b739 100644
--- a/components/Home/Home.jsx
+++ b/components/Home/Home.jsx
@@ -1,43 +1,25 @@
import React from 'react';
import { View, Text } from 'react-native';
import { styles } from './Home.styles';
-import BtnAdd from '../BtnAdd/BtnAdd';
+import BtnAddCategoria from '../BtnAdd/BtnAddCategoria';
import BtnCategorias from '../BtnCategorias/BtnCategorias';
import BtnFavoritos from '../BtnFavoritos/BtnFavoritos';
-import CardList from '../CardList/CardList';
+import CategoriasList from '../CategoriasList/CategoriasList';
import SearchIcon from '../../assets/icons/search.svg'
import * as categorias from '../test/categorias.json';
const Home = (props) => {
- var categoryName = getCategoryName(props.route.params.categoryId)
return (
- {categoryName}
+ Decks
-
+
-
-
+
);
}
-function getCategoryName(categoryId){
- // puxar os dados da categoria no BD
- if(categoryId == "a"){
- return "Todos"
- }else if(categoryId == "f"){
- return "Favoritos"
- }else{
- for(var i=0; i < Object.keys(categorias).length; i++){
- if(categorias[i].categoriaId == categoryId){
- console.log(categorias[i].nome)
- return categorias[i].nome
- }
- }
- }
-}
-
export default Home;
\ No newline at end of file
diff --git a/components/HomeCategoria/HomeCategoria.jsx b/components/HomeCategoria/HomeCategoria.jsx
new file mode 100644
index 0000000..b5922a1
--- /dev/null
+++ b/components/HomeCategoria/HomeCategoria.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { View, Text } from 'react-native';
+import { styles } from './HomeCategoria.styles';
+import BtnAddCard from '../BtnAdd/BtnAddCard';
+import BtnPlay from '../BtnPlay/BtnPlay';
+import BtnCategorias from '../BtnCategorias/BtnCategorias';
+import BtnFavoritos from '../BtnFavoritos/BtnFavoritos';
+import CardList from '../CardList/CardList';
+import SearchIcon from '../../assets/icons/search.svg'
+import { useParams, Link } from 'react-router-native'
+import * as categorias from '../test/categorias.json';
+
+const HomeCategoria = (props) => {
+ const { id, cor, nome } = useParams()
+ return (
+
+ {nome}
+
+
+
+
+
+
+
+
+ );
+}
+
+export default HomeCategoria;
\ No newline at end of file
diff --git a/components/HomeCategoria/HomeCategoria.styles.js b/components/HomeCategoria/HomeCategoria.styles.js
new file mode 100644
index 0000000..02b7f66
--- /dev/null
+++ b/components/HomeCategoria/HomeCategoria.styles.js
@@ -0,0 +1,30 @@
+import { StyleSheet } from 'react-native';
+import { vw, vh, vmin, vmax } from 'react-native-expo-viewport-units';
+
+export const styles = StyleSheet.create({
+ home: {
+ flex: 1,
+ backgroundColor: '#1a1a1a',
+ width: '100%',
+ height: '100%',
+ },
+
+ categoryText: {
+ color: '#f2f2f2',
+ marginLeft: 20,
+ marginTop: 20,
+ fontFamily: 'Epilogue_500Medium',
+ fontSize: 40,
+ },
+
+ searchIcon: {
+ position: 'absolute',
+ top: 30,
+ right: 30,
+ },
+
+ cardList: {
+ height: '100%',
+ marginTop: '5%',
+ }
+ });
diff --git a/package.json b/package.json
index 872b9c0..e1b53a3 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"expo-font": "~10.0.4",
"expo-linear-gradient": "~11.0.1",
"expo-splash-screen": "~0.14.1",
+ "expo-sqlite": "~10.1.0",
"expo-status-bar": "~1.2.0",
"react": "17.0.1",
"react-dom": "17.0.1",
@@ -27,7 +28,7 @@
"react-native-screens": "~3.10.1",
"react-native-svg": "12.1.1",
"react-native-web": "0.17.1",
- "react-router-native": "^6.2.1",
+ "react-router-native": "^6.3.0",
"rn-faded-scrollview": "^1.0.12",
"styled-components": "^5.3.3"
},
diff --git a/services/sqlite/Card.js b/services/sqlite/Card.js
new file mode 100644
index 0000000..bf82301
--- /dev/null
+++ b/services/sqlite/Card.js
@@ -0,0 +1,182 @@
+/*
+- id
+- titulo
+- resposta
+- categoriaId
+ */
+
+import db from "./SQLiteDatabase";
+
+/**
+ * INICIALIZAÇÃO DA TABELA
+ * - Executa sempre, mas só cria a tabela caso não exista (primeira execução)
+ */
+db.transaction((tx) => {
+ //<<<<<<<<<<<<<<<<<<<<<<<< USE ISSO APENAS DURANTE OS TESTES!!! >>>>>>>>>>>>>>>>>>>>>>>
+ //tx.executeSql("DROP TABLE cars;");
+ //<<<<<<<<<<<<<<<<<<<<<<<< USE ISSO APENAS DURANTE OS TESTES!!! >>>>>>>>>>>>>>>>>>>>>>>
+
+ tx.executeSql(
+ "CREATE TABLE IF NOT EXISTS cards (id INTEGER PRIMARY KEY AUTOINCREMENT, titulo TEXT, resposta TEXT, categoriaId INT);"
+ );
+});
+
+/**
+ * CRIAÇÃO DE UM NOVO REGISTRO
+ * - Recebe um objeto;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é o ID do registro (criado por AUTOINCREMENT)
+ * - Pode retornar erro (reject) caso exista erro no SQL ou nos parâmetros.
+ */
+const createCard = (obj) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "INSERT INTO cards (titulo, resposta, categoriaId) values (?, ?, ?);",
+ [obj.titulo, obj.resposta, obj.categoriaId],
+ //-----------------------
+ (_, { rowsAffected, insertId }) => {
+ if (rowsAffected > 0) resolve(insertId);
+ else reject("Error inserting obj: " + JSON.stringify(obj)); // insert falhou
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * ATUALIZA UM REGISTRO JÁ EXISTENTE
+ * - Recebe o ID do registro e um OBJETO com valores atualizados;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é a quantidade de registros atualizados;
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL.
+ */
+const updateCard = (id, obj) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "UPDATE cars SET titulo=?, resposta=? WHERE id=?;",
+ [obj.titulo, obj.resposta, id],
+ //-----------------------
+ (_, { rowsAffected }) => {
+ if (rowsAffected > 0) resolve(rowsAffected);
+ else reject("Error updating obj: id=" + id); // nenhum registro alterado
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * BUSCA UM REGISTRO POR MEIO DO ID
+ * - Recebe o ID do registro;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é o objeto (caso exista);
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL.
+ */
+const findCard = (id) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "SELECT * FROM cards WHERE id=?;",
+ [id],
+ //-----------------------
+ (_, { rows }) => {
+ if (rows.length > 0) resolve(rows._array[0]);
+ else reject("Obj not found: id=" + id); // nenhum registro encontrado
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * BUSCA UM REGISTRO POR MEIO DO TITULO (brand)
+ * - Recebe a marca do carro;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é um array com os objetos encontrados;
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL;
+ * - Pode retornar um array vazio caso nenhum objeto seja encontrado.
+ */
+const findCardByTitulo = (brand) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "SELECT * FROM cards WHERE titulo LIKE %?%;",
+ [brand],
+ //-----------------------
+ (_, { rows }) => {
+ if (rows.length > 0) resolve(rows._array);
+ else reject("Obj not found: titulo=" + brand); // nenhum registro encontrado
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * BUSCA TODOS OS REGISTROS DE UMA DETERMINADA TABELA
+ * - Não recebe parâmetros;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é uma lista (Array) de objetos;
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL;
+ * - Pode retornar um array vazio caso não existam registros.
+ */
+const allCardsCategory = (categoriaId) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "SELECT * FROM cards WHERE categoriaId=?;",
+ [categoriaId],
+ //-----------------------
+ (_, { rows }) => {
+ if (rows.length > 0) resolve(rows._array);
+ else reject("Obj not found: categoriaId=" + categoriaId); // nenhum registro encontrado
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * REMOVE UM REGISTRO POR MEIO DO ID
+ * - Recebe o ID do registro;
+ * - Retorna uma Promise:
+ * - O resultado da Promise a quantidade de registros removidos (zero indica que nada foi removido);
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL.
+ */
+const removeCard = (id) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "DELETE FROM cards WHERE id=?;",
+ [id],
+ //-----------------------
+ (_, { rowsAffected }) => {
+ resolve(rowsAffected);
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+export default {
+ createCard,
+ updateCard,
+ findCard,
+ findCardByTitulo,
+ allCardsCategory,
+ removeCard,
+};
diff --git a/services/sqlite/Categoria.js b/services/sqlite/Categoria.js
new file mode 100644
index 0000000..c6c3969
--- /dev/null
+++ b/services/sqlite/Categoria.js
@@ -0,0 +1,159 @@
+/*
+-id
+-cor
+-nome
+ */
+
+// Criar tabela
+
+// Criar categoria
+
+// Excluir categoria
+
+// Atualizar categoria
+
+import db from "./SQLiteDatabase";
+
+/**
+ * INICIALIZAÇÃO DA TABELA
+ * - Executa sempre, mas só cria a tabela caso não exista (primeira execução)
+ */
+db.transaction((tx) => {
+ //<<<<<<<<<<<<<<<<<<<<<<<< USE ISSO APENAS DURANTE OS TESTES!!! >>>>>>>>>>>>>>>>>>>>>>>
+ //tx.executeSql("DROP TABLE cars;");
+ //<<<<<<<<<<<<<<<<<<<<<<<< USE ISSO APENAS DURANTE OS TESTES!!! >>>>>>>>>>>>>>>>>>>>>>>
+
+ tx.executeSql(
+ "CREATE TABLE IF NOT EXISTS categorias (id INTEGER PRIMARY KEY AUTOINCREMENT, cor TEXT, nome TEXT);"
+ );
+});
+
+/**
+ * CRIAÇÃO DE UM NOVO REGISTRO
+ * - Recebe um objeto;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é o ID do registro (criado por AUTOINCREMENT)
+ * - Pode retornar erro (reject) caso exista erro no SQL ou nos parâmetros.
+ */
+const createCategoria = (obj) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "INSERT INTO categorias (cor, nome) values (?, ?);",
+ [obj.cor, obj.nome],
+ //-----------------------
+ (_, { rowsAffected, insertId }) => {
+ if (rowsAffected > 0) resolve(insertId);
+ else reject("Error inserting obj: " + JSON.stringify(obj)); // insert falhou
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * ATUALIZA UM REGISTRO JÁ EXISTENTE
+ * - Recebe o ID do registro e um OBJETO com valores atualizados;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é a quantidade de registros atualizados;
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL.
+ */
+const updateCategoria = (id, obj) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "UPDATE categorias SET cor=?, nome=? WHERE id=?;",
+ [obj.cor, obj.nome, id],
+ //-----------------------
+ (_, { rowsAffected }) => {
+ if (rowsAffected > 0) resolve(rowsAffected);
+ else reject("Error updating obj: id=" + id); // nenhum registro alterado
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * BUSCA UM REGISTRO POR MEIO DO ID
+ * - Recebe o ID do registro;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é o objeto (caso exista);
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL.
+ */
+const findCategoria = (id) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "SELECT * FROM categorias WHERE id=?;",
+ [id],
+ //-----------------------
+ (_, { rows }) => {
+ if (rows.length > 0) resolve(rows._array[0]);
+ else reject("Obj not found: id=" + id); // nenhum registro encontrado
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * BUSCA TODOS OS REGISTROS DE UMA DETERMINADA TABELA
+ * - Não recebe parâmetros;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é uma lista (Array) de objetos;
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL;
+ * - Pode retornar um array vazio caso não existam registros.
+ */
+const allCategorias = () => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "SELECT cat.*, COUNT(c.id) as quantCards FROM categorias as cat LEFT JOIN cards as c ON cat.id = c.categoriaId GROUP BY cat.id;",
+ [],
+ //-----------------------
+ (_, { rows }) => resolve(rows._array),
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * REMOVE UM REGISTRO POR MEIO DO ID
+ * - Recebe o ID do registro;
+ * - Retorna uma Promise:
+ * - O resultado da Promise a quantidade de registros removidos (zero indica que nada foi removido);
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL.
+ */
+const removeCategoria = (id) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "DELETE FROM categoria WHERE id=?; DELETE FROM cards WHERE categoriaId=?",
+ [id, id],
+ //-----------------------
+ (_, { rowsAffected }) => {
+ resolve(rowsAffected);
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+export default {
+ createCategoria,
+ updateCategoria,
+ findCategoria,
+ allCategorias,
+ removeCategoria,
+};
diff --git a/services/sqlite/Detalhes.js b/services/sqlite/Detalhes.js
new file mode 100644
index 0000000..a0bdc36
--- /dev/null
+++ b/services/sqlite/Detalhes.js
@@ -0,0 +1,170 @@
+/*
+-id
+-cardId
+-titulo
+-resposta
+ */
+
+// Criar tabela
+
+// Criar detalhe
+
+// Excluir detalhe
+
+// Atualizar detalhe
+
+/*
+- id
+- titulo
+- resposta
+- categoriaId
+ */
+
+import db from "./SQLiteDatabase";
+
+/**
+ * INICIALIZAÇÃO DA TABELA
+ * - Executa sempre, mas só cria a tabela caso não exista (primeira execução)
+ */
+db.transaction((tx) => {
+ //<<<<<<<<<<<<<<<<<<<<<<<< USE ISSO APENAS DURANTE OS TESTES!!! >>>>>>>>>>>>>>>>>>>>>>>
+ //tx.executeSql("DROP TABLE cars;");
+ //<<<<<<<<<<<<<<<<<<<<<<<< USE ISSO APENAS DURANTE OS TESTES!!! >>>>>>>>>>>>>>>>>>>>>>>
+
+ tx.executeSql(
+ "CREATE TABLE IF NOT EXISTS detalhes (id INTEGER PRIMARY KEY AUTOINCREMENT, titulo TEXT, resposta TEXT, cardId INT);"
+ );
+});
+
+/**
+ * CRIAÇÃO DE UM NOVO REGISTRO
+ * - Recebe um objeto;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é o ID do registro (criado por AUTOINCREMENT)
+ * - Pode retornar erro (reject) caso exista erro no SQL ou nos parâmetros.
+ */
+const createDetalhe = (obj) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "INSERT INTO detalhes (titulo, resposta, cardId) values (?, ?, ?);",
+ [obj.titulo, obj.resposta, obj.cardId],
+ //-----------------------
+ (_, { rowsAffected, insertId }) => {
+ if (rowsAffected > 0) resolve(insertId);
+ else reject("Error inserting obj: " + JSON.stringify(obj)); // insert falhou
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * ATUALIZA UM REGISTRO JÁ EXISTENTE
+ * - Recebe o ID do registro e um OBJETO com valores atualizados;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é a quantidade de registros atualizados;
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL.
+ */
+const updateDetalhe = (id, obj) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "UPDATE detalhes SET titulo=?, resposta=? WHERE id=?;",
+ [obj.titulo, obj.resposta, id],
+ //-----------------------
+ (_, { rowsAffected }) => {
+ if (rowsAffected > 0) resolve(rowsAffected);
+ else reject("Error updating obj: id=" + id); // nenhum registro alterado
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * BUSCA UM REGISTRO POR MEIO DO ID
+ * - Recebe o ID do registro;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é o objeto (caso exista);
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL.
+ */
+const findDetalhe = (id) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "SELECT * FROM detalhes WHERE id=?;",
+ [id],
+ //-----------------------
+ (_, { rows }) => {
+ if (rows.length > 0) resolve(rows._array[0]);
+ else reject("Obj not found: id=" + id); // nenhum registro encontrado
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * BUSCA TODOS OS REGISTROS DE UMA DETERMINADA TABELA
+ * - Não recebe parâmetros;
+ * - Retorna uma Promise:
+ * - O resultado da Promise é uma lista (Array) de objetos;
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL;
+ * - Pode retornar um array vazio caso não existam registros.
+ */
+const allDetalhesCard = (cardId) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "SELECT * FROM detalhes WHERE cardId=?;",
+ [cardId],
+ //-----------------------
+ (_, { rows }) => {
+ if (rows.length > 0) resolve(rows._array);
+ else resolve([]); // nenhum registro encontrado
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+/**
+ * REMOVE UM REGISTRO POR MEIO DO ID
+ * - Recebe o ID do registro;
+ * - Retorna uma Promise:
+ * - O resultado da Promise a quantidade de registros removidos (zero indica que nada foi removido);
+ * - Pode retornar erro (reject) caso o ID não exista ou então caso ocorra erro no SQL.
+ */
+const removeDetalhe = (cardId) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ //comando SQL modificável
+ tx.executeSql(
+ "DELETE FROM detalhes WHERE cardId=?;",
+ [cardId],
+ //-----------------------
+ (_, { rowsAffected }) => {
+ resolve(rowsAffected);
+ },
+ (_, error) => reject(error) // erro interno em tx.executeSql
+ );
+ });
+ });
+};
+
+export default {
+ createDetalhe,
+ updateDetalhe,
+ findDetalhe,
+ allDetalhesCard,
+ removeDetalhe,
+};
diff --git a/services/sqlite/Play.js b/services/sqlite/Play.js
new file mode 100644
index 0000000..02c9621
--- /dev/null
+++ b/services/sqlite/Play.js
@@ -0,0 +1,14 @@
+import db from "./SQLiteDatabse";
+/*
+- cardId
+- categoryId
+- status
+ */
+
+// Setar cards e criar resultado geral
+
+// Atualizar Status
+
+// Finalizar jogo
+
+// Selecionar proxima carta
diff --git a/services/sqlite/ResultadoGeral.js b/services/sqlite/ResultadoGeral.js
new file mode 100644
index 0000000..e4aba8b
--- /dev/null
+++ b/services/sqlite/ResultadoGeral.js
@@ -0,0 +1,15 @@
+import db from "./SQLiteDatabse";
+/*
+- status (ativo ou concluido)
+- data
+- numAcertos
+- numErros
+- nCards
+- categoriaId
+- rel_erro_jogadas (num_erros / numAcertos + numErros)
+- performance (numAcertos / nCards)
+ */
+
+// criar resultado
+
+// atualizar resultado
diff --git a/services/sqlite/SQLiteDatabase.js b/services/sqlite/SQLiteDatabase.js
new file mode 100644
index 0000000..9a146aa
--- /dev/null
+++ b/services/sqlite/SQLiteDatabase.js
@@ -0,0 +1,7 @@
+// Inicializa o banco de dados
+
+import * as SQLite from "expo-sqlite";
+
+const db = SQLite.openDatabase("db.db");
+
+export default db;
diff --git a/yarn.lock b/yarn.lock
index 677000e..3eb8db7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1363,6 +1363,17 @@
lodash.pick "^4.4.0"
lodash.template "^4.5.0"
+"@expo/websql@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@expo/websql/-/websql-1.0.1.tgz#fff0cf9c1baa1f70f9e1d658b7c39a420d9b10a9"
+ integrity sha1-//DPnBuqH3D54dZYt8OaQg2bEKk=
+ dependencies:
+ argsarray "^0.0.1"
+ immediate "^3.2.2"
+ noop-fn "^1.0.0"
+ pouchdb-collections "^1.0.1"
+ tiny-queue "^0.2.1"
+
"@hapi/hoek@^9.0.0":
version "9.2.1"
resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz"
@@ -1878,6 +1889,11 @@ argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"
+argsarray@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/argsarray/-/argsarray-0.0.1.tgz#6e7207b4ecdb39b0af88303fa5ae22bda8df61cb"
+ integrity sha1-bnIHtOzbObCviDA/pa4ivajfYcs=
+
arr-diff@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz"
@@ -3008,6 +3024,13 @@ expo-splash-screen@~0.14.0, expo-splash-screen@~0.14.1:
"@expo/configure-splash-screen" "^0.6.0"
"@expo/prebuild-config" "^3.0.15"
+expo-sqlite@~10.1.0:
+ version "10.1.1"
+ resolved "https://registry.yarnpkg.com/expo-sqlite/-/expo-sqlite-10.1.1.tgz#282bcb20cd04e3eb68e6480630d8176c3dcb49a9"
+ integrity sha512-yxVa+sDWhfuvYN1MJkQZK74ND3mEOyVm6o2bRoecP6MDZW6c7NXS7Q7kP157b80h8meHukIfkhd48NAe1peenA==
+ dependencies:
+ "@expo/websql" "^1.0.1"
+
expo-status-bar@~1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.2.0.tgz"
@@ -3480,6 +3503,11 @@ image-size@^0.6.0:
resolved "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz"
integrity sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA==
+immediate@^3.2.2:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266"
+ integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==
+
import-fresh@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz"
@@ -4572,6 +4600,11 @@ node-stream-zip@^1.9.1:
resolved "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz"
integrity sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==
+noop-fn@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/noop-fn/-/noop-fn-1.0.0.tgz#5f33d47f13d2150df93e0cb036699e982f78ffbf"
+ integrity sha1-XzPUfxPSFQ35PgywNmmemC94/78=
+
normalize-css-color@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/normalize-css-color/-/normalize-css-color-1.0.2.tgz"
@@ -4907,6 +4940,11 @@ postcss-value-parser@^4.0.2:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+pouchdb-collections@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-1.0.1.tgz#fe63a17da977611abef7cb8026cb1a9553fd8359"
+ integrity sha1-/mOhfal3YRq+98uAJssalVP9g1k=
+
pretty-format@^26.5.2, pretty-format@^26.6.2:
version "26.6.2"
resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz"
@@ -5123,19 +5161,19 @@ react-refresh@^0.4.0:
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz"
integrity sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==
-react-router-native@^6.2.1:
- version "6.2.1"
- resolved "https://registry.yarnpkg.com/react-router-native/-/react-router-native-6.2.1.tgz#64b979c07e433c9ced30551fb5232f4f3e839b90"
- integrity sha512-MJ7n51d7UZTEXLKC2YUWL8waYTouIvyloUUIlNqERlkEFoDFH9CUuqaAmmGM6LbrphzqhR2XQDK2SgCF8lVvzg==
+react-router-native@^6.3.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/react-router-native/-/react-router-native-6.3.0.tgz#d8a14006cba4522fef335879997b7d7477d28748"
+ integrity sha512-Y+UuU6Typnz1eGWfYf2UYmh1qItbrNBK5kr3p7ZsamsLIxCKSoYo2YJyz9JOgRiv1nOFsCoSkpQJPYLAz68hlQ==
dependencies:
"@ungap/url-search-params" "^0.1.4"
history "^5.2.0"
- react-router "6.2.1"
+ react-router "6.3.0"
-react-router@6.2.1:
- version "6.2.1"
- resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.2.1.tgz#be2a97a6006ce1d9123c28934e604faef51448a3"
- integrity sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==
+react-router@6.3.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557"
+ integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==
dependencies:
history "^5.2.0"
@@ -5867,6 +5905,11 @@ through2@^2.0.1:
readable-stream "~2.3.6"
xtend "~4.0.1"
+tiny-queue@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046"
+ integrity sha1-JaZ/LG4lOyypQZd7XvdELvl6YEY=
+
tmpl@1.0.5:
version "1.0.5"
resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz"