diff options
| author | Maksymilian Jopek <maks@jopek.eu> | 2023-03-28 17:18:05 +0200 |
|---|---|---|
| committer | Maksymilian Jopek <maks@jopek.eu> | 2023-03-28 17:36:09 +0200 |
| commit | 1cb36cd073252f4a185cd9775382da4c6861a8cb (patch) | |
| tree | 30d374fc87e0409364f03faa8f7c58eb2bf7b882 /components | |
| parent | 67b6f338cfe4da739d39dc6764d11efa00105d81 (diff) | |
| download | remarques-1cb36cd073252f4a185cd9775382da4c6861a8cb.tar.gz remarques-1cb36cd073252f4a185cd9775382da4c6861a8cb.tar.zst remarques-1cb36cd073252f4a185cd9775382da4c6861a8cb.zip | |
Working app
Diffstat (limited to 'components')
| -rw-r--r-- | components/CategoryView.js | 61 | ||||
| -rw-r--r-- | components/DrawerContent.js | 43 | ||||
| -rw-r--r-- | components/NoteView.js | 155 | ||||
| -rw-r--r-- | components/NotesList.js | 185 | ||||
| -rw-r--r-- | components/Options.js | 68 |
5 files changed, 512 insertions, 0 deletions
diff --git a/components/CategoryView.js b/components/CategoryView.js new file mode 100644 index 0000000..a9c6222 --- /dev/null +++ b/components/CategoryView.js @@ -0,0 +1,61 @@ +import * as React from 'react'; +import { SafeAreaView, TextInput, StyleSheet, Text, TouchableOpacity } from 'react-native'; +import * as SecureStore from 'expo-secure-store'; + +export default function CategoryView() { + let [name, setName] = React.useState("") + const ti = React.createRef() + + async function addCategory() { + let nk = await SecureStore.getItemAsync('categories') + let categories = [] + if (!nk) categories = ["default"]; else categories = JSON.parse(nk); + if (!categories.find(c => c === name)) + categories.push(name) + await SecureStore.setItemAsync('categories', JSON.stringify(categories)) + + ti.current.clear() + + // props.navigation.navigate('s1') + } + return ( + <SafeAreaView style={styles.cont}> + <TextInput + underlineColorAndroid="#FFFFFF" + placeholder="NAME..." + placeholderTextColor="#FFFFFF" + onChangeText={setName} + style={styles.input} + ref={ti} + /> + <TouchableOpacity onPress={addCategory}><Text style={styles.txt}>Add</Text></TouchableOpacity> + </SafeAreaView> + ) +} + +const styles = StyleSheet.create({ + cont: { + flex: 1, + backgroundColor: "black", + padding: 20, + alignItems: "center" + }, + ico: { + width: 200, + height: 200, + }, + txt: { + fontSize: 30, + fontWeight: "bold", + color: "#FFFFFF" + }, + input: { + height: 40, + width: "100%", + margin: 12, + borderWidth: 1, + padding: 10, + color: "#FFFFFF", + } +}) + diff --git a/components/DrawerContent.js b/components/DrawerContent.js new file mode 100644 index 0000000..41b67cb --- /dev/null +++ b/components/DrawerContent.js @@ -0,0 +1,43 @@ +import * as React from "react" +import { Image, Alert, StyleSheet } from 'react-native' +import { DrawerContentScrollView, DrawerItem } from '@react-navigation/drawer'; + +import icon from "../assets/pencil-circle.png" +import iIcon from "../assets/i.png" +import cIcon from "../assets/text-plus-icon.png" +import plusIcon from "../assets/plus.png" +import newIcon from "../assets/new-icon.png" + +export default function DrawerContent(props) { + window.navigation = props.navigation + return ( + <DrawerContentScrollView {...props}> + <Image source={icon} style={styles.topImg} /> + <DrawerItem + label="Notes list" + icon={() => <Image source={newIcon} style={styles.icon} />} + onPress={() => props.navigation.navigate("notesList")} + /> + <DrawerItem + label="Add note" + icon={() => <Image source={plusIcon} style={styles.icon} />} + onPress={() => props.navigation.navigate("addNote")} + /> + <DrawerItem + label="Add category" + icon={() => <Image source={cIcon} style={styles.icon} />} + onPress={() => props.navigation.navigate("addCategory")} + /> + <DrawerItem + label="Info" + icon={() => <Image source={iIcon} style={styles.icon} />} + onPress={() => Alert.alert("Alert", "Alerting from best note app, version 2.0")} + /> + </DrawerContentScrollView> + ); +} + +const styles = StyleSheet.create({ + topImg: { width: 100, height: 100, margin: 30, alignSelf: "center" }, + icon: { width: 30, height: 30 }, +}) diff --git a/components/NoteView.js b/components/NoteView.js new file mode 100644 index 0000000..820eaf9 --- /dev/null +++ b/components/NoteView.js @@ -0,0 +1,155 @@ +import * as React from 'react'; +import { SafeAreaView, TextInput, StyleSheet, Text, TouchableOpacity, Dimensions } from 'react-native'; +import { Picker } from '@react-native-picker/picker'; +import * as SecureStore from 'expo-secure-store'; + +export default class NoteView extends React.Component { + constructor(props) { + super(props) + const note = props.route.params?.note ?? {}; + this.state = { + note: note, + isNew: Object.keys(note).length === 0, + title: note.title ?? "", + body: note.body ?? "", + category: note.category ?? "", + ti1: React.createRef(), + ti2: React.createRef(), + categories: [], + } + this.setTitle = this.setTitle.bind(this) + this.setBody = this.setBody.bind(this) + this.setCategory = this.setCategory.bind(this) + this.setCategories = this.setCategories.bind(this) + this.addNote = this.addNote.bind(this) + this.funkcja = () => null; + } + componentDidMount() { + const a = () => { + const n = this.props.route.params?.note ?? {}; + getCategories(this.setCategories, this.setCategory, this.state.category) + console.log('note', n, ' ', Date.now()) + this.setState({ note: n }) + this.setTitle(n.title ?? "") + this.setBody(n.body ?? "") + this.setCategory(n.category ?? "") + } + a() + this.props.navigation.addListener('focus', a) + } + componentWillUnmount() { + this.funkcja(); + } + + setTitle(t) { this.setState({ title: t }) } + setBody(t) { this.setState({ body: t }) } + setCategory(t) { this.setState({ category: t }) } + setCategories(t) { this.setState({ categories: t }) } + + async addNote() { + try { + let nk = await SecureStore.getItemAsync('notesKeys') + let notesKeys = [] + if (!nk) notesKeys = [0]; else notesKeys = JSON.parse(nk); + const key = this.state.isNew ? Math.max(...notesKeys) + 1 : this.state.note.key; + const date = Date.now(); + const colors = ["darkred", "darkblue", "darkcyan", "darkgreen"] + const color = this.state.isNew ? colors[Math.floor(Math.random() * colors.length)] : this.state.note.color + if (this.state.isNew) + notesKeys.push(key); + let [title, body, category] = [this.state.title, this.state.body, this.state.category] + if (category === "") category = this.state.categories[0] + await SecureStore.setItemAsync(key.toString(), JSON.stringify({ title, body, date, color, key, category })) + await SecureStore.setItemAsync('notesKeys', JSON.stringify(notesKeys.filter(el => el !== 0))) + console.log(key.toString(), JSON.stringify({ title, body, date, color, key, category })) + console.log('notesKeys', JSON.stringify(notesKeys.filter(el => el !== 0))) + console.log('categories', this.state.categories) + + // this.state.ti1.current.clear() + // this.state.ti2.current.clear() + + this.props.navigation.navigate('notesList') + } catch (e) { + console.error(e) + } + } + render() { + return ( + <SafeAreaView style={styles.cont}> + <TextInput + underlineColorAndroid="#FFFFFF" + placeholder="TITLE..." + placeholderTextColor="#FFFFFF" + onChangeText={this.setTitle} + value={this.state.title} + style={styles.input} + ref={this.state.ti1} + /> + <TextInput + underlineColorAndroid="#FFFFFF" + placeholder="BODY..." + placeholderTextColor="#FFFFFF" + onChangeText={this.setBody} + value={this.state.body} + style={styles.input} + multiline={true} + ref={this.state.ti2} + /> + <Picker + selectedValue={this.state.category} + onValueChange={(v, _) => this.setCategory(v)} + style={styles.picker} + itemStyle={styles.pickerItem} + > + {this.state.categories.map((c, i) => <Picker.Item value={c} label={c} key={i} />)} + </Picker> + <TouchableOpacity onPress={this.addNote}><Text style={styles.txt}>{this.state.isNew ? "Add" : "Confirm"}</Text></TouchableOpacity> + </SafeAreaView> + ) + } +} +async function getCategories(setCategories, setCategory, category) { + let categories = await SecureStore.getItemAsync('categories') + if (!categories) categories = ["default"]; else categories = JSON.parse(categories); + setCategories(categories); + if (category === "") + setCategory(categories[0]) +} + +const styles = StyleSheet.create({ + cont: { + flex: 1, + backgroundColor: "black", + padding: 20, + alignItems: "center" + }, + ico: { + width: 200, + height: 200, + }, + txt: { + fontSize: 30, + fontWeight: "bold", + color: "#FFFFFF" + }, + picker: { + color: "white", + borderColor: "white", + width: 200, + height: 30, + backgroundColor: "darkgrey", + margin: 15, + }, + pickerItem: { + backgroundColor: "black", + color: "white", + }, + input: { + // height: 40, + width: "100%", + margin: 12, + borderWidth: 1, + padding: 10, + color: "#FFFFFF", + } +}) diff --git a/components/NotesList.js b/components/NotesList.js new file mode 100644 index 0000000..9525b11 --- /dev/null +++ b/components/NotesList.js @@ -0,0 +1,185 @@ +import * as React from 'react'; +import { View, StyleSheet, Text, FlatList, TouchableOpacity, Alert, TextInput } from 'react-native'; +import * as SecureStore from 'expo-secure-store'; + +import { getFont } from "./Options" + +export default class NotesList extends React.Component { + constructor(props) { + super(props) + this.state = { + notes: [], + search: '', + font: 0, + sortOrder: true, + } + this.setNotes = this.setNotes.bind(this) + this.setSearch = this.setSearch.bind(this) + this.setFont = this.setFont.bind(this) + this.setSortOrder = this.setSortOrder.bind(this) + this.funkcja = () => null; + } + setNotes(s) { this.setState({ notes: s }) } + setSearch(s) { this.setState({ search: s }) } + setFont(s) { this.setState({ font: s }) } + setSortOrder(s) { this.setState({ sortOrder: s }) } + + componentDidMount() { + getNotes(this.setNotes); getFont(this.setFont); + this.props.navigation.addListener('focus', () => { getNotes(this.setNotes); getFont(this.setFont); }) + } + componentWillUnmount() { + this.funkcja(); + } + render() { + const filterNotes = (n) => { + return n.title.includes(this.state.search) || + n.body.includes(this.state.search) || + n.category.includes(this.state.search) + } + const sortNotes = (a, b) => { + return this.state.sortOrder ? a.date - b.date : b.date - a.date; + } + return ( + <View style={styles.cont} > + <View> + <TextInput + placeholder="SEARCH IN NOTES..." + placeholderTextColor="#FFFFFF" + onChangeText={this.setSearch} + style={styles.input} + defaultValue={this.state.search} + // ref={ti} + /> + </View> + <TouchableOpacity style={styles.btn} onPress={() => this.setSortOrder(!this.state.sortOrder)}><Text style={[styles.txt, { textAlign: "center" }]}>Change sort order</Text></TouchableOpacity> + <View> + <FlatList + data={this.state.notes.filter(filterNotes).sort(sortNotes)} + renderItem={item => { + const note = item.item + let date = new Date(note.date) + const ms = ["Sty", "Lut", "Mar", "Kwi", "Maj", "Cze", "Lip", "Sie", "Wrz", "Paz", "Lis", "Gru"] + date = `${date.toISOString().substr(8, 2)} ${ms[date.getMonth()]}` + return ( + <TouchableOpacity onLongPress={() => + Alert.alert("Delete?", "There's no way back", [ + { + text: "Cancel", + style: "cancel" + }, + { + text: "OK", + onPress: () => deleteItem(note, this.setNotes) + } + ]) + } + onPress={() => this.props.navigation.navigate("editNote", { note }) + } + > + <View key={item.index} style={[styles.note, { backgroundColor: note.color }]}> + <View><Text style={[styles.category, { color: note.color, fontSize: this.state.font }]}>{note.category}</Text></View> + <View><Text style={[styles.date, { fontSize: this.state.font }]}>{date}</Text></View> + <View style={{ flex: 1 }}><Text style={[styles.title, { fontSize: this.state.font }]}>{note.title}</Text></View> + <View style={{ flex: 1 }}><Text style={[styles.body, { flexWrap: "wrap", fontSize: this.state.font }]}>{note.body}</Text></View> + </View> + </TouchableOpacity> + ) + }} + keyExtractor={(_, i) => i.toString()} + contentContainerStyle={styles.list} + style={styles.list} + numColumns={2} + /> + </View> + </View> + ) + } +} + +async function deleteItem(note, setNotes) { + let keyList = JSON.parse(await SecureStore.getItemAsync('notesKeys')) + await SecureStore.deleteItemAsync(note.key.toString()) + keyList = keyList.filter(n => n !== note.key) + await SecureStore.setItemAsync('notesKeys', JSON.stringify(keyList)) + + getNotes(setNotes) +} + +async function getNotes(setNotes) { + let notesKeys = await SecureStore.getItemAsync('notesKeys') + if (!notesKeys) notesKeys = []; else notesKeys = JSON.parse(notesKeys); + const notes = []; + for (const key of notesKeys) { + notes.push(JSON.parse(await SecureStore.getItemAsync(key.toString()))) + } + setNotes(notes); +} + +const styles = StyleSheet.create({ + cont: { + flex: 1, + flexDirection: "column", + backgroundColor: "black", + }, + note: { + width: 160, + height: 160, + backgroundColor: "red", + borderRadius: 10, + padding: 10, + marginTop: 30, + marginLeft: 30, + }, + list: { + // height: 680, + }, + btn: { + // borderColor: "red", + borderWidth: 3, + textAlign: "center", + flex: 0, + }, + ico: { + width: 200, + height: 200, + }, + input: { + fontSize: 25, + alignSelf: "center", + textAlign: "center", + width: "80%", + backgroundColor: "darkgrey", + borderRadius: 8, + margin: 10, + height: 60, + }, + category: { + backgroundColor: "black", + // width: "fit-content", + margin: 10, + padding: 5, + borderRadius: 8, + alignSelf: "flex-start", + }, + date: { + fontSize: 18, + color: "#FFFFFF", + textAlign: "right", + }, + title: { + fontSize: 25, + fontWeight: "bold", + color: "#FFFFFF" + }, + body: { + fontSize: 25, + color: "#FFFFFF" + }, + txt: { + fontSize: 25, + fontWeight: "bold", + color: "#FFFFFF" + }, +}) + diff --git a/components/Options.js b/components/Options.js new file mode 100644 index 0000000..fd0c21c --- /dev/null +++ b/components/Options.js @@ -0,0 +1,68 @@ +import * as React from 'react'; +import { SafeAreaView, TextInput, StyleSheet, Text, TouchableOpacity } from 'react-native'; +import * as SecureStore from 'expo-secure-store'; + +let a = true +export default function CategoryView(props) { + let [font, setFont] = React.useState(0) + + async function setFontSS(f) { + setFont(f); + await SecureStore.setItemAsync('font', f.toString()) + } + + React.useEffect(() => getFont(setFont), []) + if (a) { + props.navigation.addListener('focus', () => getFont(setFont)) + a = false + } + + return ( + <SafeAreaView style={styles.cont}> + <Text style={styles.txt}>Selected font: {font}</Text> + <TouchableOpacity onPress={() => setFontSS(12)}><Text style={[styles.txt, styles.btn]}>Font 12</Text></TouchableOpacity> + <TouchableOpacity onPress={() => setFontSS(19)}><Text style={[styles.txt, styles.btn]}>Font 19</Text></TouchableOpacity > + <TouchableOpacity onPress={() => setFontSS(26)}><Text style={[styles.txt, styles.btn]}>Font 26</Text></TouchableOpacity > + </SafeAreaView > + ) +} +export async function getFont(setFont) { + let font = await SecureStore.getItemAsync('font') + if (!font) { font = 22; await SecureStore.setItemAsync('font', '22'); } else font = JSON.parse(font); + setFont(parseInt(font)); +} + +const styles = StyleSheet.create({ + cont: { + flex: 1, + backgroundColor: "black", + padding: 20, + alignItems: "center" + }, + ico: { + width: 200, + height: 200, + }, + txt: { + fontSize: 30, + fontWeight: "bold", + color: "#FFFFFF" + }, + btn: { + textAlign: "center", + borderColor: "pink", + borderWidth: 5, + margin: 10, + padding: 10, + }, + input: { + height: 40, + width: "100%", + margin: 12, + borderWidth: 1, + padding: 10, + color: "#FFFFFF", + } +}) + + |
