├── assets
├── icon.png
├── splash.png
├── favicon.png
└── adaptive-icon.png
├── Images
├── Preview_Image_1.png
├── Preview_Image_2.png
├── Preview_Image_3.png
└── Preview_Image_4.png
├── babel.config.js
├── .expo-shared
└── assets.json
├── .gitignore
├── App.js
├── Context
├── createDataContext.js
├── SettingsContext.js
├── BirthdayDataContext.js
└── ReminderDataContext.js
├── app.json
├── LICENSE.md
├── README.md
├── package.json
├── Screens
├── Settings_Screen.js
├── Birthday_Screen.js
├── Reminder_Screen.js
└── main.js
└── Components
├── Birthday
├── birthdaymodel.js
└── birthday_swipable.js
├── Swipablelist.js
└── model.js
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mazahir26/Reminder-App/HEAD/assets/icon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mazahir26/Reminder-App/HEAD/assets/splash.png
--------------------------------------------------------------------------------
/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mazahir26/Reminder-App/HEAD/assets/favicon.png
--------------------------------------------------------------------------------
/assets/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mazahir26/Reminder-App/HEAD/assets/adaptive-icon.png
--------------------------------------------------------------------------------
/Images/Preview_Image_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mazahir26/Reminder-App/HEAD/Images/Preview_Image_1.png
--------------------------------------------------------------------------------
/Images/Preview_Image_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mazahir26/Reminder-App/HEAD/Images/Preview_Image_2.png
--------------------------------------------------------------------------------
/Images/Preview_Image_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mazahir26/Reminder-App/HEAD/Images/Preview_Image_3.png
--------------------------------------------------------------------------------
/Images/Preview_Image_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Mazahir26/Reminder-App/HEAD/Images/Preview_Image_4.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | .expo-shared/*
4 | npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | web-build/
12 |
13 | # macOS
14 | .DS_Store
15 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import { Provider as SettingsProvider } from "./Context/SettingsContext";
2 | import { Provider as ReminderProvider } from "./Context/ReminderDataContext";
3 | import { Provider as BirthdayProvider } from "./Context/BirthdayDataContext";
4 |
5 | import React from "react";
6 | import Main from "./Screens/main";
7 |
8 | export default function App() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/Context/createDataContext.js:
--------------------------------------------------------------------------------
1 | import React, { useReducer } from "react";
2 |
3 | export default (reducer, actions, initialState) => {
4 | const Context = React.createContext();
5 |
6 | const Provider = ({ children }) => {
7 | const [state, dispatch] = useReducer(reducer, initialState);
8 | const boundActions = {};
9 | for (let key in actions) {
10 | boundActions[key] = actions[key](dispatch);
11 | }
12 |
13 | return (
14 |
15 | {children}
16 |
17 | );
18 | };
19 |
20 | return { Context, Provider };
21 | };
22 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "Reminder",
4 | "slug": "Reminder",
5 | "version": "1.0.1",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "splash": {
9 | "image": "./assets/splash.png",
10 | "resizeMode": "cover",
11 | "backgroundColor": "#eeeeee"
12 | },
13 | "notification": {
14 | "color": "#7f2ee1"
15 | },
16 | "updates": {
17 | "fallbackToCacheTimeout": 0
18 | },
19 | "assetBundlePatterns": ["**/*"],
20 | "ios": {
21 | "supportsTablet": true
22 | },
23 | "android": {
24 | "adaptiveIcon": {
25 | "foregroundImage": "./assets/adaptive-icon.png",
26 | "backgroundColor": "#FFFFFF"
27 | },
28 | "package": "com.mazahir.reminder"
29 | },
30 | "web": {
31 | "favicon": "./assets/favicon.png"
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright 2021 Mazahir
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Reminder App
2 |
3 | ## Table of Contents
4 |
5 | - [About](#about)
6 | - [Getting Started](#getting_started)
7 | - [Features](#features)
8 |
9 | ## About
10 |
11 | it's a simple reminder app made with React-Native and Expo.
12 |
13 | ## Getting Started
14 |
15 | - Install dependencies: `yarn install` (or `npm install`).
16 |
17 | - Run on both Android & iOS: `expo start` (or `npm start`).
18 |
19 | - Run on Android: `yarn android` (or `npm run android`).
20 |
21 | - Run on iOS: `yarn ios` (or `npm run ios`).
22 |
23 | ### Preview
24 |
25 | 
26 | 
27 |
28 | ## Features
29 |
30 | - Notification Support
31 | - Local Storage
32 | - Dark theme and light theme
33 | - Minimal design
34 | - Birthday Reminders
35 | - and much more..
36 |
37 | ## Testing
38 |
39 | - it has been Tested on Android 10.0
40 | - it uses expo SDK 40
41 | - if you find any bugs, please raise an issue
42 |
43 | ## License
44 |
45 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
46 |
47 | ## Thank You
48 |
49 | Thanks for checking out my project, feel free to fork it.
50 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@react-native-async-storage/async-storage": "^1.15.2",
12 | "@react-native-community/datetimepicker": "3.0.4",
13 | "@react-native-community/masked-view": "0.1.10",
14 | "@react-navigation/bottom-tabs": "^5.11.7",
15 | "@react-navigation/native": "^5.9.2",
16 | "@react-navigation/stack": "^5.14.2",
17 | "expo": "~40.0.0",
18 | "expo-notifications": "~0.8.2",
19 | "expo-status-bar": "~1.0.3",
20 | "moment": "^2.29.4",
21 | "react": "16.13.1",
22 | "react-dom": "16.13.1",
23 | "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
24 | "react-native-draggable-flatlist": "^2.5.4",
25 | "react-native-gesture-handler": "~1.8.0",
26 | "react-native-paper": "^4.7.2",
27 | "react-native-reanimated": "~2.10.0",
28 | "react-native-safe-area-context": "3.1.9",
29 | "react-native-screens": "~2.15.2",
30 | "react-native-swipeable-item": "^1.5.4",
31 | "react-native-web": "~0.13.12"
32 | },
33 | "devDependencies": {
34 | "@babel/core": "~7.9.0"
35 | },
36 | "private": true
37 | }
38 |
--------------------------------------------------------------------------------
/Context/SettingsContext.js:
--------------------------------------------------------------------------------
1 | import createDataContext from "./createDataContext";
2 | import AsyncStorage from "@react-native-async-storage/async-storage";
3 |
4 | const settings_reducer = (state, action) => {
5 | switch (action.type) {
6 | default:
7 | return state;
8 | case "init_data":
9 | return action.payload;
10 | case "toggle_darkmode":
11 | const data = {
12 | ...state,
13 | Theme: !state.Theme,
14 | };
15 | storeData(data);
16 | return data;
17 | }
18 | };
19 |
20 | const toggle_darkmode = (dispatch) => {
21 | return () => {
22 | dispatch({ type: "toggle_darkmode" });
23 | };
24 | };
25 |
26 | const init_data_Settings = (dispatch) => {
27 | return () => {
28 | getData()
29 | .then((value) => {
30 | if (value == null) {
31 | value = {
32 | Theme: false,
33 | };
34 | }
35 | dispatch({ type: "init_data", payload: value });
36 | })
37 | .catch((e) => {
38 | console.log(e);
39 | });
40 | };
41 | };
42 |
43 | const storeData = async (value) => {
44 | try {
45 | const jsonValue = JSON.stringify(value);
46 | await AsyncStorage.setItem("Settings-Data", jsonValue);
47 | } catch (e) {
48 | console.log(e);
49 | }
50 | };
51 |
52 | const getData = async () => {
53 | try {
54 | const jsonValue = await AsyncStorage.getItem("Settings-Data");
55 | return jsonValue != null ? JSON.parse(jsonValue) : null;
56 | } catch (e) {
57 | console.log(e);
58 | }
59 | };
60 |
61 | export const { Context, Provider } = createDataContext(
62 | settings_reducer,
63 | { toggle_darkmode, init_data_Settings },
64 | {
65 | Theme: false,
66 | }
67 | );
68 |
--------------------------------------------------------------------------------
/Screens/Settings_Screen.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { Text, View, StyleSheet } from "react-native";
3 | import { Feather } from "@expo/vector-icons";
4 | import { TouchableOpacity } from "react-native-gesture-handler";
5 | import { Context } from "../Context/SettingsContext";
6 | import { useTheme } from "react-native-paper";
7 |
8 | function Settings() {
9 | const { state, toggle_darkmode } = useContext(Context);
10 | const { colors } = useTheme();
11 |
12 | return (
13 |
14 |
15 |
16 | Settings
17 |
18 |
19 |
24 |
31 | Theme
32 |
33 |
38 |
39 |
40 |
41 |
42 |
43 | About
44 |
45 |
46 |
52 | Its a simple open source app created with react-native and expo
53 |
54 |
55 | );
56 | }
57 |
58 | export default Settings;
59 |
60 | const styles = StyleSheet.create({
61 | container: {
62 | flex: 1,
63 | marginTop: 50,
64 | },
65 | TitleContainer: {
66 | justifyContent: "center",
67 | marginHorizontal: 15,
68 | marginVertical: 20,
69 | },
70 | text: {
71 | fontWeight: "bold",
72 | color: "gray",
73 | fontSize: 24,
74 | },
75 | });
76 |
--------------------------------------------------------------------------------
/Screens/Birthday_Screen.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useContext } from "react";
2 | import { useTheme } from "react-native-paper";
3 | import { AntDesign } from "@expo/vector-icons";
4 | import Element from "../Components/Birthday/birthday_swipable";
5 | import Model from "../Components/Birthday/birthdaymodel";
6 | import { Context } from "../Context/BirthdayDataContext";
7 | import {
8 | Text,
9 | View,
10 | StyleSheet,
11 | FlatList,
12 | LayoutAnimation,
13 | TouchableOpacity,
14 | Platform,
15 | UIManager,
16 | } from "react-native";
17 |
18 | if (Platform.OS === "android") {
19 | UIManager.setLayoutAnimationEnabledExperimental &&
20 | UIManager.setLayoutAnimationEnabledExperimental(true);
21 | }
22 |
23 | function My_List() {
24 | const { state, add_birthday, delete_birthday, edit } = useContext(Context);
25 | const { colors } = useTheme();
26 | const [showmodel, setmodel] = useState(false);
27 | const [selecteditem, setselecteditem] = useState(null);
28 |
29 | useEffect(() => {
30 | state.sort(function (a, b) {
31 | var keyA = new Date(a.Date).getTime(),
32 | keyB = new Date(b.Date).getTime();
33 | if (keyA < keyB) return -1;
34 | if (keyA > keyB) return 1;
35 | return 0;
36 | });
37 | }, [state]);
38 |
39 | useEffect(() => {
40 | state.map((item) => {
41 | edit({ selecteditem: item, text: item.text, time: item.Date });
42 | });
43 | }, []);
44 |
45 | let itemRefs = new Map();
46 |
47 | const chnage_model = (item) => {
48 | LayoutAnimation.configureNext(
49 | LayoutAnimation.create(
50 | 200,
51 | LayoutAnimation.Types.linear,
52 | LayoutAnimation.Properties.opacity
53 | )
54 | );
55 | setselecteditem(item);
56 | setmodel(!showmodel);
57 | };
58 | const hide_model = () => {
59 | LayoutAnimation.configureNext(
60 | LayoutAnimation.create(
61 | 200,
62 | LayoutAnimation.Types.linear,
63 | LayoutAnimation.Properties.opacity
64 | )
65 | );
66 | setmodel(false);
67 | setselecteditem(null);
68 | };
69 |
70 | function emptylist() {
71 | return (
72 |
78 |
84 | {"Click on the plus icon to add Birthday Reminder."}
85 |
86 |
87 | );
88 | }
89 |
90 | function footer() {
91 | return (
92 |
99 | {
101 | add_birthday();
102 | }}
103 | >
104 |
105 |
106 |
107 | );
108 | }
109 | if (showmodel) {
110 | return (
111 |
112 | );
113 | }
114 | function header() {
115 | return (
116 |
117 |
118 | Birthdays
119 |
120 |
121 | );
122 | }
123 | return (
124 |
125 | item.key}
130 | data={state}
131 | renderItem={({ item, index }) => (
132 | {
137 | delete_birthday(item);
138 | }}
139 | showmodel={chnage_model}
140 | />
141 | )}
142 | ListFooterComponent={footer}
143 | />
144 |
145 | );
146 | }
147 |
148 | export default My_List;
149 |
150 | const styles = StyleSheet.create({
151 | container: {
152 | flex: 1,
153 | marginTop: 50,
154 | },
155 | TitleContainer: {
156 | flex: 0.4,
157 | justifyContent: "center",
158 | marginHorizontal: 7,
159 | marginVertical: 20,
160 | },
161 | text: {
162 | fontWeight: "bold",
163 | color: "gray",
164 | fontSize: 24,
165 | },
166 | });
167 |
--------------------------------------------------------------------------------
/Screens/Reminder_Screen.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useContext, useEffect } from "react";
2 | import { useTheme } from "react-native-paper";
3 | import { AntDesign } from "@expo/vector-icons";
4 | import Element from "../Components/Swipablelist";
5 | import Model from "../Components/model";
6 | import { Context } from "../Context/ReminderDataContext";
7 |
8 | import {
9 | Text,
10 | View,
11 | StyleSheet,
12 | FlatList,
13 | LayoutAnimation,
14 | TouchableOpacity,
15 | Platform,
16 | UIManager,
17 | } from "react-native";
18 | import { State } from "react-native-gesture-handler";
19 |
20 | if (Platform.OS === "android") {
21 | UIManager.setLayoutAnimationEnabledExperimental &&
22 | UIManager.setLayoutAnimationEnabledExperimental(true);
23 | }
24 |
25 | function My_List() {
26 | const { state, add_reminder, delete_reminder, edit } = useContext(Context);
27 |
28 | const { colors } = useTheme();
29 | const [showmodel, setmodel] = useState(false);
30 | const [selecteditem, setselecteditem] = useState(null);
31 |
32 | let itemRefs = new Map();
33 |
34 | useEffect(() => {
35 | state.map((item) => {
36 | let ti = new Date(item.Date);
37 | if (ti.getTime() <= Date.now()) {
38 | delete_reminder(item);
39 | }
40 | });
41 | state.sort(function (a, b) {
42 | var keyA = new Date(a.Date).getTime(),
43 | keyB = new Date(b.Date).getTime();
44 | if (keyA < keyB) return -1;
45 | if (keyA > keyB) return 1;
46 | return 0;
47 | });
48 | }, [state]);
49 |
50 | const chnage_model = (item) => {
51 | LayoutAnimation.configureNext(
52 | LayoutAnimation.create(
53 | 200,
54 | LayoutAnimation.Types.linear,
55 | LayoutAnimation.Properties.opacity
56 | )
57 | );
58 | setselecteditem(item);
59 | setmodel(!showmodel);
60 | };
61 | const hide_model = () => {
62 | LayoutAnimation.configureNext(
63 | LayoutAnimation.create(
64 | 200,
65 | LayoutAnimation.Types.linear,
66 | LayoutAnimation.Properties.opacity
67 | )
68 | );
69 | setmodel(false);
70 | setselecteditem(null);
71 | };
72 |
73 | function emptylist() {
74 | return (
75 |
81 |
87 | {
88 | "Looks like you have no reminder! \n Click on the plus icon to add one."
89 | }
90 |
91 |
92 | );
93 | }
94 |
95 | function footer() {
96 | return (
97 |
104 | {
106 | add_reminder();
107 | }}
108 | >
109 |
110 |
111 |
112 | );
113 | }
114 | if (showmodel) {
115 | return (
116 |
117 | );
118 | }
119 | function header() {
120 | return (
121 |
122 |
123 | Reminders
124 |
125 |
126 | );
127 | }
128 | return (
129 |
130 | item.key}
135 | data={state}
136 | renderItem={({ item, index }) => (
137 | {
142 | delete_reminder(item);
143 | }}
144 | showmodel={chnage_model}
145 | />
146 | )}
147 | ListFooterComponent={footer}
148 | // onDragEnd={({ data }) => this.setState({ data })}
149 | // activationDistance={10}
150 | />
151 |
152 | );
153 | }
154 |
155 | /*
156 |
157 | */
158 |
159 | export default My_List;
160 |
161 | const styles = StyleSheet.create({
162 | container: {
163 | flex: 1,
164 | marginTop: 50,
165 | },
166 | TitleContainer: {
167 | flex: 0.4,
168 | justifyContent: "center",
169 | marginHorizontal: 7,
170 | marginVertical: 20,
171 | },
172 | text: {
173 | fontWeight: "bold",
174 | color: "gray",
175 | fontSize: 24,
176 | },
177 | });
178 |
--------------------------------------------------------------------------------
/Screens/main.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useEffect, useState } from "react";
2 | import Reminder_Screen from "./Reminder_Screen";
3 | import Birthday_Screen from "./Birthday_Screen";
4 | import Settings_Screen from "./Settings_Screen";
5 | import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
6 | import { NavigationContainer } from "@react-navigation/native";
7 | import { AntDesign } from "@expo/vector-icons";
8 | import { View } from "react-native";
9 | import {
10 | DefaultTheme,
11 | Provider as PaperProvider,
12 | ActivityIndicator,
13 | } from "react-native-paper";
14 | import { Context as SettingsContext } from "../Context/SettingsContext";
15 | import { Context as ReminderContext } from "../Context/ReminderDataContext";
16 | import { Context as BirthdayContext } from "../Context/BirthdayDataContext";
17 |
18 | import * as Notifications from "expo-notifications";
19 | const lighttheme = {
20 | ...DefaultTheme,
21 | colors: {
22 | ...DefaultTheme.colors,
23 | primary: "#6c757d",
24 | accent: "#6096ba",
25 | background: "#eeeeee",
26 | tab: "#ffffff",
27 | elemprim: "rgb(220,120,120)",
28 | elemsec: "lightblue",
29 | text: "#777777",
30 | },
31 | };
32 | const darktheme = {
33 | ...DefaultTheme,
34 | colors: {
35 | ...DefaultTheme.colors,
36 | primary: "#aaafaf",
37 | accent: "#6096ba",
38 | background: "#212529",
39 | tab: "#343a40",
40 | elemprim: "#777777",
41 | elemsec: "#777777",
42 | text: "#bbbbbb",
43 | },
44 | };
45 |
46 | const Tab = createBottomTabNavigator();
47 |
48 | function main() {
49 | const { init_data, snooze } = useContext(ReminderContext);
50 | const { init_data_Birthday } = useContext(BirthdayContext);
51 | const { state, init_data_Settings } = useContext(SettingsContext);
52 | var currentTheme = state.Theme ? lighttheme : darktheme;
53 | const { colors } = currentTheme;
54 | const [loading, setLoading] = useState(true);
55 | useEffect(() => {
56 | const subscription = Notifications.addNotificationResponseReceivedListener(
57 | async (response) => {
58 | if (response.actionIdentifier === "snooze") {
59 | if (
60 | response.notification.request.content.categoryIdentifier ==
61 | "reminder"
62 | ) {
63 | snooze({
64 | text: response.notification.request.content.body,
65 | val: response.notification.request.identifier,
66 | snoozetime: 30,
67 | });
68 | }
69 | }
70 | await Notifications.dismissNotificationAsync(
71 | response.notification.request.identifier
72 | );
73 | }
74 | );
75 | return () => subscription.remove();
76 | }, []);
77 |
78 | useEffect(() => {
79 | init_data();
80 | init_data_Birthday();
81 | init_data_Settings();
82 | setTimeout(() => {
83 | setLoading(false);
84 | }, 500);
85 | }, []);
86 |
87 | if (loading) {
88 | return (
89 |
92 |
93 |
94 | );
95 | } else
96 | return (
97 |
98 |
99 |
109 | (
114 |
115 | ),
116 | }}
117 | />
118 | (
123 |
124 | ),
125 | }}
126 | />
127 | (
132 |
133 | ),
134 | }}
135 | />
136 |
137 |
138 |
139 | );
140 | }
141 |
142 | export default main;
143 |
--------------------------------------------------------------------------------
/Components/Birthday/birthdaymodel.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import moment from "moment";
3 | import DateTimePicker from "@react-native-community/datetimepicker";
4 | import { AntDesign } from "@expo/vector-icons";
5 | import { useTheme } from "react-native-paper";
6 |
7 | import {
8 | TextInput,
9 | Text,
10 | View,
11 | StyleSheet,
12 | TouchableOpacity,
13 | } from "react-native";
14 |
15 | export default function ({ selecteditem, hide_model, edit }) {
16 | const [text, settext] = useState(selecteditem.text);
17 | const [time, settime] = useState(new Date(selecteditem.Date));
18 | const [show, setShow] = useState(false);
19 | const { colors } = useTheme();
20 |
21 | if (show) {
22 | return (
23 | {
29 | if (event.type == "dismissed") {
30 | setShow(false);
31 | return;
32 | }
33 | settime(date);
34 | setShow(false);
35 | }}
36 | style={{ width: 320, backgroundColor: "gray" }} //add this
37 | />
38 | );
39 | }
40 | return (
41 |
47 | hide_model()}
49 | style={{
50 | alignSelf: "flex-end",
51 | marginHorizontal: 10,
52 | marginBottom: 10,
53 | }}
54 | >
55 |
56 |
57 |
58 |
66 |
73 | settext(text)}
78 | selectTextOnFocus={text == "Tap to change the name"}
79 | value={text}
80 | style={[styles.text, { color: colors.text }]}
81 | />
82 |
88 | {` ${
89 | moment(time).format("Do ") + moment(time).format("MMMM YYYY")
90 | }`}
91 |
92 |
93 |
94 |
95 |
101 | Tap to change
102 |
103 | {
106 | setShow(true);
107 | }}
108 | >
109 |
110 | Date
111 |
112 |
113 |
114 |
115 |
116 | {
118 | edit({ text, selecteditem, time: moment(time) });
119 | hide_model();
120 | }}
121 | style={styles.button}
122 | >
123 |
124 | Save
125 |
126 |
127 |
128 | );
129 | }
130 |
131 | const styles = StyleSheet.create({
132 | text: {
133 | fontWeight: "bold",
134 | color: "gray",
135 | fontSize: 24,
136 | },
137 | sep: {
138 | borderWidth: 1,
139 | borderColor: "gray",
140 | marginHorizontal: 10,
141 | opacity: 0.5,
142 | alignSelf: "stretch",
143 | marginVertical: 20,
144 | },
145 | model: {
146 | flexDirection: "row",
147 | alignItems: "center",
148 | justifyContent: "center",
149 | padding: 10,
150 | margin: 5,
151 | borderRadius: 10,
152 | backgroundColor: "white",
153 | borderWidth: 2,
154 | borderColor: "gray",
155 | },
156 | button: {
157 | alignSelf: "center",
158 | alignItems: "center",
159 | justifyContent: "center",
160 | paddingVertical: 5,
161 | padding: 10,
162 | margin: 5,
163 | borderRadius: 10,
164 | borderWidth: 2,
165 | borderColor: "gray",
166 | },
167 | });
168 |
--------------------------------------------------------------------------------
/Context/BirthdayDataContext.js:
--------------------------------------------------------------------------------
1 | import createDataContext from "./createDataContext";
2 | import AsyncStorage from "@react-native-async-storage/async-storage";
3 | import { LayoutAnimation } from "react-native";
4 | import * as Notifications from "expo-notifications";
5 |
6 | const Birthday_reducer = (state, action) => {
7 | switch (action.type) {
8 | case "add_birthday":
9 | LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
10 | let data = [
11 | ...state,
12 | {
13 | text: `Tap to change the name`,
14 | key: `key-${1 + Math.random() * 99}`,
15 | height: 75,
16 | Date: action.payload.time,
17 | notificationId: action.payload.value,
18 | },
19 | ];
20 | storeData(data);
21 | return data;
22 | case "init_data":
23 | if (action.payload === null) {
24 | return [];
25 | } else return action.payload;
26 | case "delete_reminder":
27 | case "delete_birthday":
28 | LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
29 | data = state.filter((d) => d !== action.payload);
30 | storeData(data);
31 | return data;
32 | case "edit":
33 | data = state.filter((d) => {
34 | if (d == action.payload.selecteditem) {
35 | let tep = action.payload.selecteditem;
36 | tep.Date = action.payload.time;
37 | tep.text = action.payload.text;
38 | tep.notificationId = action.payload.id;
39 | return tep;
40 | } else return d;
41 | });
42 | storeData(data);
43 | return data;
44 | default:
45 | return state;
46 | }
47 | };
48 |
49 | const add_birthday = (dispatch) => {
50 | return () => {
51 | let tep = new Date(Date.now());
52 | let time = new Date(Date.now());
53 | tep.setHours(0, 0, 0, 0);
54 | time.setHours(0, 0, 0, 0);
55 | time.setFullYear(tep.getFullYear() + 1);
56 | let id = notif(" ", time.getTime() / 1000 - tep.getTime() / 1000);
57 | id.then((value) => {
58 | time.setFullYear(tep.getFullYear());
59 | dispatch({ type: "add_birthday", payload: { time, value } });
60 | }).catch((e) => {
61 | console.error(e);
62 | });
63 | };
64 | };
65 | const delete_birthday = (dispatch) => {
66 | return (id) => {
67 | Cancle_Notif(id.notificationId);
68 | dispatch({ type: "delete_birthday", payload: id });
69 | };
70 | };
71 | const init_data_Birthday = (dispatch) => {
72 | return () => {
73 | getData()
74 | .then((value) => {
75 | dispatch({ type: "init_data", payload: value });
76 | })
77 | .catch((e) => {
78 | console.log(e);
79 | });
80 | };
81 | };
82 | const edit = (dispatch) => {
83 | return ({ selecteditem, text, time }) => {
84 | let tep = new Date(Date.now());
85 | let temp = new Date(time);
86 | if (tep.getMonth() > temp.getMonth()) {
87 | temp.setFullYear(tep.getFullYear() + 1);
88 | }
89 | if (tep.getMonth() == temp.getMonth()) {
90 | if (tep.getDate() >= temp.getDate()) {
91 | temp.setFullYear(tep.getFullYear() + 1);
92 | } else {
93 | temp.setFullYear(tep.getFullYear());
94 | }
95 | }
96 | if (tep.getMonth() < temp.getMonth()) {
97 | temp.setFullYear(tep.getFullYear());
98 | }
99 | tep.setHours(0, 0, 0, 0);
100 | Cancle_Notif(selecteditem.notificationId);
101 | let id = notif(text, temp.getTime() / 1000 - tep.getTime() / 1000);
102 | id.then((value) => {
103 | dispatch({
104 | type: "edit",
105 | payload: { selecteditem, text, time, id: value },
106 | });
107 | }).catch((e) => {
108 | console.error(e);
109 | });
110 | };
111 | };
112 |
113 | export const { Context, Provider } = createDataContext(
114 | Birthday_reducer,
115 | { add_birthday, delete_birthday, edit, init_data_Birthday },
116 | []
117 | );
118 |
119 | const notif = async (text, time) => {
120 | let lol = await Notifications.scheduleNotificationAsync({
121 | content: {
122 | title: "Happy Birthday ",
123 | body: text,
124 | categoryIdentifier: "birthday",
125 | },
126 | trigger: {
127 | seconds: time,
128 | },
129 | });
130 | let action = [
131 | {
132 | identifier: "Done",
133 | buttonTitle: "Done",
134 | options: {
135 | // isAuthenticationRequired?: boolean,
136 | opensAppToForeground: false,
137 | },
138 | },
139 | ];
140 |
141 | let bob = await Notifications.setNotificationCategoryAsync(
142 | "birthday",
143 | action
144 | );
145 | return lol;
146 | };
147 |
148 | const Cancle_Notif = async (id) => {
149 | await Notifications.cancelScheduledNotificationAsync(id)
150 | .then(() => {
151 | // all_notif();
152 | })
153 | .catch((e) => {
154 | console.error(e);
155 | });
156 | };
157 |
158 | const storeData = async (value) => {
159 | try {
160 | const jsonValue = JSON.stringify(value);
161 | await AsyncStorage.setItem("Birthday-Data", jsonValue);
162 | } catch (e) {
163 | console.log(e);
164 | }
165 | };
166 |
167 | const getData = async () => {
168 | try {
169 | const jsonValue = await AsyncStorage.getItem("Birthday-Data");
170 | return jsonValue != null ? JSON.parse(jsonValue) : null;
171 | } catch (e) {
172 | console.log(e);
173 | }
174 | };
175 |
--------------------------------------------------------------------------------
/Components/Swipablelist.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import SwipeableItem, { UnderlayParams } from "react-native-swipeable-item";
3 | import { FontAwesome } from "@expo/vector-icons";
4 | import { Text, View, StyleSheet, TouchableOpacity } from "react-native";
5 | import moment from "moment";
6 | const { multiply, sub } = Animated;
7 | import Animated from "react-native-reanimated";
8 | import { useTheme } from "react-native-paper";
9 |
10 | export default function renderItem({
11 | item,
12 | index,
13 | itemRefs,
14 | deleteItem,
15 | showmodel,
16 | }) {
17 | const { colors } = useTheme();
18 |
19 | const renderUnderlayLeft = ({ item, percentOpen }) => (
20 |
27 | deleteItem(item)}>
28 |
29 |
30 |
31 | );
32 |
33 | const renderUnderlayRight = ({ item, percentOpen, open, close }) => (
34 |
44 |
45 | CLOSE
46 |
47 |
48 | );
49 |
50 | return (
51 | {
55 | if (ref && !itemRefs.get(item.key)) {
56 | itemRefs.set(item.key, ref);
57 | }
58 | }}
59 | onChange={({ open }) => {
60 | if (open) {
61 | // Close all other open items
62 | [...itemRefs.entries()].forEach(([key, ref]) => {
63 | if (key !== item.key && ref) ref.close();
64 | });
65 | }
66 | }}
67 | overSwipe={30}
68 | renderUnderlayLeft={renderUnderlayLeft}
69 | renderUnderlayRight={renderUnderlayRight}
70 | snapPointsLeft={[150]}
71 | snapPointsRight={[175]}
72 | >
73 |
74 |
82 |
83 | showmodel(item)}>
84 |
85 | {item.text}
86 |
87 |
88 |
89 |
90 |
91 |
92 |
103 | {`${moment(item.Date).format("hh:mm a")}\n${
104 | moment(item.Date).format("Do ") +
105 | "," +
106 | moment(item.Date).format("MMM")
107 | }`}
108 |
109 |
110 |
111 |
112 |
113 | );
114 | }
115 |
116 | const styles = StyleSheet.create({
117 | container: {
118 | flex: 1,
119 | marginTop: 50,
120 | },
121 | TitleContainer: {
122 | flex: 0.2,
123 | justifyContent: "center",
124 | marginHorizontal: 7,
125 | },
126 | row: {
127 | flexDirection: "row",
128 | flex: 1,
129 | alignItems: "center",
130 | justifyContent: "flex-start",
131 | padding: 10,
132 | margin: 5,
133 | borderRadius: 10,
134 | backgroundColor: "white",
135 | borderWidth: 2,
136 | borderColor: "gray",
137 | },
138 | text: {
139 | fontWeight: "bold",
140 | fontSize: 24,
141 | },
142 | underlayRight: {
143 | flex: 1,
144 | justifyContent: "flex-start",
145 | borderWidth: 0,
146 | },
147 | underlayLeft: {
148 | flex: 1,
149 | justifyContent: "flex-end",
150 | borderWidth: 0,
151 | },
152 | sep: {
153 | borderWidth: 1,
154 | borderColor: "gray",
155 | marginHorizontal: 10,
156 | opacity: 0.5,
157 | alignSelf: "stretch",
158 | marginVertical: 10,
159 | },
160 | });
161 | //
162 | // seteditable(!editable)}>
163 | // seteditable(false)}
167 | // editable={editable}
168 | // onChangeText={(text) => change_text({ item, text })}
169 | // value={item.text}
170 | // style={[styles.text, { flex: 1 }]}
171 | // />
172 | //
173 | // ;
174 |
--------------------------------------------------------------------------------
/Components/model.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import moment from "moment";
3 | import DateTimePicker from "@react-native-community/datetimepicker";
4 | import { AntDesign } from "@expo/vector-icons";
5 | import { useTheme, Snackbar } from "react-native-paper";
6 |
7 | import {
8 | TextInput,
9 | Text,
10 | View,
11 | StyleSheet,
12 | TouchableOpacity,
13 | } from "react-native";
14 |
15 | export default function ({ selecteditem, hide_model, edit }) {
16 | const [text, settext] = useState(selecteditem.text);
17 | const [time, settime] = useState(new Date(selecteditem.Date));
18 | const [mode, setMode] = useState("date");
19 | const [show, setShow] = useState(false);
20 | const { colors } = useTheme();
21 | const [visible, setVisible] = useState(false);
22 |
23 | const onToggleSnackBar = () => setVisible(!visible);
24 |
25 | const onDismissSnackBar = () => setVisible(false);
26 | if (show) {
27 | return (
28 | {
34 | if (event.type == "dismissed") {
35 | setShow(false);
36 | return;
37 | }
38 | let tep = new Date(Date.now());
39 |
40 | if (tep.getTime() / 1000 - date.getTime() / 1000 > 1) {
41 | setShow(false);
42 | onToggleSnackBar();
43 | return;
44 | }
45 | settime(date);
46 | setShow(false);
47 | }}
48 | style={{ width: 320, backgroundColor: "gray" }} //add this
49 | />
50 | );
51 | }
52 | return (
53 |
59 | hide_model()}
61 | style={{
62 | alignSelf: "flex-end",
63 | marginHorizontal: 10,
64 | marginBottom: 10,
65 | }}
66 | >
67 |
68 |
69 |
70 |
78 |
85 | settext(text)}
91 | value={text}
92 | style={[styles.text, { color: colors.text }]}
93 | />
94 |
100 | {`${moment(time).format("hh:mm a")}, ${
101 | moment(time).format("Do ") + moment(time).format("MMM YYYY")
102 | }`}
103 |
104 |
105 |
106 |
107 |
113 | Tap to change
114 |
115 | {
118 | setMode("date");
119 | setShow(true);
120 | }}
121 | >
122 |
123 | Date
124 |
125 |
126 | {
129 | setMode("time");
130 | setShow(true);
131 | }}
132 | >
133 |
134 | Time
135 |
136 |
137 |
138 |
139 |
140 | {
142 | edit({ text, selecteditem, time: moment(time) });
143 | hide_model();
144 | }}
145 | style={styles.button}
146 | >
147 |
148 | Save
149 |
150 |
151 | {
157 | onToggleSnackBar();
158 | },
159 | }}
160 | >
161 | Invaild Date or Time
162 |
163 |
164 | );
165 | }
166 |
167 | const styles = StyleSheet.create({
168 | text: {
169 | fontWeight: "bold",
170 | color: "gray",
171 | fontSize: 24,
172 | },
173 | sep: {
174 | borderWidth: 1,
175 | borderColor: "gray",
176 | marginHorizontal: 10,
177 | opacity: 0.5,
178 | alignSelf: "stretch",
179 | marginVertical: 20,
180 | },
181 | model: {
182 | flexDirection: "row",
183 | alignItems: "center",
184 | justifyContent: "center",
185 | padding: 10,
186 | margin: 5,
187 | borderRadius: 10,
188 | backgroundColor: "white",
189 | borderWidth: 2,
190 | borderColor: "gray",
191 | },
192 | button: {
193 | alignSelf: "center",
194 | alignItems: "center",
195 | justifyContent: "center",
196 | paddingVertical: 5,
197 | padding: 10,
198 | margin: 5,
199 | borderRadius: 10,
200 | borderWidth: 2,
201 | borderColor: "gray",
202 | },
203 | });
204 |
--------------------------------------------------------------------------------
/Context/ReminderDataContext.js:
--------------------------------------------------------------------------------
1 | import createDataContext from "./createDataContext";
2 | import AsyncStorage from "@react-native-async-storage/async-storage";
3 | import { LayoutAnimation } from "react-native";
4 | import * as Notifications from "expo-notifications";
5 |
6 | const Reminder_reducer = (state, action) => {
7 | switch (action.type) {
8 | case "add_reminder":
9 | LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
10 | let data = [
11 | ...state,
12 | {
13 | text: `Tap to edit`,
14 | key: `key-${1 + Math.random() * 99}`,
15 | height: 75,
16 | Date: action.payload.time,
17 | notificationId: action.payload.value,
18 | },
19 | ];
20 | storeData(data);
21 | return data;
22 | case "init_data":
23 | if (action.payload === null) {
24 | return [];
25 | } else return action.payload;
26 | case "delete_reminder":
27 | LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
28 | data = state.filter((d) => d !== action.payload);
29 | storeData(data);
30 | return data;
31 | case "snooze":
32 | data = state.filter((d) => {
33 | if (d.notificationId == action.payload.id) {
34 | let tep = d;
35 | tep.Date = action.payload.time;
36 | tep.notificationId = action.payload.newid;
37 | return tep;
38 | } else return d;
39 | });
40 | storeData(data);
41 | return data;
42 | case "edit":
43 | data = state.filter((d) => {
44 | if (d == action.payload.selecteditem) {
45 | let tep = action.payload.selecteditem;
46 | tep.Date = action.payload.time;
47 | tep.text = action.payload.text;
48 | tep.notificationId = action.payload.id;
49 | return tep;
50 | } else return d;
51 | });
52 | storeData(data);
53 | return data;
54 | default:
55 | return state;
56 | }
57 | };
58 |
59 | const add_reminder = (dispatch) => {
60 | return () => {
61 | let time = new Date(Date.now() + 60 * 60 * 1000);
62 | let tep = new Date(Date.now());
63 | time.setSeconds(0, 0);
64 | let id = notif("Tap to edit", time.getTime() / 1000 - tep.getTime() / 1000);
65 | id.then((value) => {
66 | dispatch({ type: "add_reminder", payload: { time, value } });
67 | }).catch((e) => {
68 | console.error(e);
69 | });
70 | };
71 | };
72 | const delete_reminder = (dispatch) => {
73 | return (id) => {
74 | Cancle_Notif(id.notificationId);
75 | dispatch({ type: "delete_reminder", payload: id });
76 | };
77 | };
78 | const init_data = (dispatch) => {
79 | return () => {
80 | getData()
81 | .then((value) => {
82 | dispatch({ type: "init_data", payload: value });
83 | })
84 | .catch((e) => {
85 | console.log(e);
86 | });
87 | };
88 | };
89 |
90 | const snooze = (dispatch) => {
91 | return ({ val, text, snoozetime }) => {
92 | let tep = new Date(Date.now());
93 | let temp = new Date(Date.now() + 60 * 1000 * snoozetime);
94 | temp.setSeconds(0, 0);
95 | Cancle_Notif(val);
96 | // console.log(snoozetime);
97 | let id = notif(text, temp.getTime() / 1000 - tep.getTime() / 1000);
98 | id.then((value) => {
99 | dispatch({
100 | type: "snooze",
101 | payload: { time: temp, id: val, newid: value },
102 | });
103 | }).catch((e) => {
104 | console.error(e);
105 | });
106 | };
107 | };
108 |
109 | const edit = (dispatch) => {
110 | return ({ selecteditem, text, time }) => {
111 | let tep = new Date(Date.now());
112 | let temp = new Date(time);
113 | temp.setSeconds(0, 0);
114 | Cancle_Notif(selecteditem.notificationId);
115 | let id = notif(text, temp.getTime() / 1000 - tep.getTime() / 1000);
116 | id.then((value) => {
117 | dispatch({
118 | type: "edit",
119 | payload: { selecteditem, text, time, id: value },
120 | });
121 | }).catch((e) => {
122 | console.error(e);
123 | });
124 | };
125 | };
126 |
127 | export const { Context, Provider } = createDataContext(
128 | Reminder_reducer,
129 | { add_reminder, delete_reminder, edit, init_data, snooze },
130 | []
131 | );
132 |
133 | const notif = async (text, time) => {
134 | let lol = await Notifications.scheduleNotificationAsync({
135 | content: {
136 | title: "Reminder",
137 | body: text,
138 | categoryIdentifier: "reminder",
139 | },
140 | trigger: {
141 | seconds: time,
142 | },
143 | });
144 | let action = [
145 | {
146 | identifier: "Done",
147 | buttonTitle: "Done",
148 | options: {
149 | // isAuthenticationRequired?: boolean,
150 | opensAppToForeground: false,
151 | },
152 | },
153 | {
154 | identifier: "snooze",
155 | buttonTitle: "Snooze",
156 | options: {
157 | // isAuthenticationRequired?: boolean,
158 | opensAppToForeground: false,
159 | },
160 | },
161 | ];
162 |
163 | let blob = await Notifications.setNotificationCategoryAsync(
164 | "reminder",
165 | action
166 | );
167 | return lol;
168 | };
169 |
170 | // const Cancle_all_notif = async () => {
171 | // let lol = await Notifications.cancelAllScheduledNotificationsAsync();
172 | // console.log("cncled all " + lol);
173 | // };
174 |
175 | // const all_notif = async () => {
176 | // let lol = await Notifications.getAllScheduledNotificationsAsync();
177 | // console.log("-----ALL NOTIFICATIONS----");
178 | // console.log(lol);
179 | // };
180 |
181 | const Cancle_Notif = async (id) => {
182 | await Notifications.cancelScheduledNotificationAsync(id)
183 | .then(() => {})
184 | .catch((e) => {
185 | console.error(e);
186 | });
187 | };
188 |
189 | const storeData = async (value) => {
190 | try {
191 | const jsonValue = JSON.stringify(value);
192 | await AsyncStorage.setItem("Reminder-Data", jsonValue);
193 | } catch (e) {
194 | console.log(e);
195 | }
196 | };
197 |
198 | const getData = async () => {
199 | try {
200 | const jsonValue = await AsyncStorage.getItem("Reminder-Data");
201 | return jsonValue != null ? JSON.parse(jsonValue) : null;
202 | } catch (e) {
203 | console.log(e);
204 | }
205 | };
206 |
--------------------------------------------------------------------------------
/Components/Birthday/birthday_swipable.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import SwipeableItem, { UnderlayParams } from "react-native-swipeable-item";
3 | import { FontAwesome } from "@expo/vector-icons";
4 | import { Text, View, StyleSheet, TouchableOpacity } from "react-native";
5 | import moment from "moment";
6 | const { multiply, sub } = Animated;
7 | import Animated from "react-native-reanimated";
8 | import { useTheme } from "react-native-paper";
9 |
10 | export default function renderItem({
11 | item,
12 | index,
13 | itemRefs,
14 | deleteItem,
15 | showmodel,
16 | }) {
17 | const { colors } = useTheme();
18 |
19 | function Age() {
20 | let years = Math.floor(moment().diff(moment(item.Date), "years", true));
21 | let days = Math.floor(moment().diff(moment(item.Date), "days", true));
22 | let text = "";
23 | if (years == 0 && days == 0) {
24 | return null;
25 | } else if (days == 0) {
26 | text = `Happy Birthday, ${item.text} is ${years} old`;
27 | } else if (years == 0) {
28 | text = `Lived for ${days} days`;
29 | } else {
30 | text = "Lived for " + days + " Days, \n" + years + " Years old";
31 | }
32 | return (
33 |
39 | {text}
40 |
41 | );
42 | }
43 | const renderUnderlayLeft = ({ item, percentOpen }) => (
44 |
51 | deleteItem(item)}>
52 |
53 |
54 |
55 | );
56 |
57 | const renderUnderlayRight = ({ item, percentOpen, open, close }) => (
58 |
68 |
69 | CLOSE
70 |
71 |
72 | );
73 |
74 | return (
75 | {
79 | if (ref && !itemRefs.get(item.key)) {
80 | itemRefs.set(item.key, ref);
81 | }
82 | }}
83 | onChange={({ open }) => {
84 | if (open) {
85 | // Close all other open items
86 | [...itemRefs.entries()].forEach(([key, ref]) => {
87 | if (key !== item.key && ref) ref.close();
88 | });
89 | }
90 | }}
91 | overSwipe={30}
92 | renderUnderlayLeft={renderUnderlayLeft}
93 | renderUnderlayRight={renderUnderlayRight}
94 | snapPointsLeft={[150]}
95 | snapPointsRight={[175]}
96 | >
97 |
98 |
106 |
107 | showmodel(item)}>
108 |
109 | {item.text == "Tap to change the name"
110 | ? item.text
111 | : `${item.text}'s Birthday`}
112 |
113 | {Age()}
114 | {/*
120 | {Age()}
121 | */}
122 |
123 |
124 |
125 |
126 |
127 |
138 | {`${
139 | moment(item.Date).format("Do ") +
140 | "," +
141 | moment(item.Date).format("MMM")
142 | }`}
143 |
144 |
145 |
146 |
147 |
148 | );
149 | }
150 |
151 | const styles = StyleSheet.create({
152 | container: {
153 | flex: 1,
154 | marginTop: 50,
155 | },
156 | TitleContainer: {
157 | flex: 0.2,
158 | justifyContent: "center",
159 | marginHorizontal: 7,
160 | },
161 | row: {
162 | flexDirection: "row",
163 | flex: 1,
164 | alignItems: "center",
165 | justifyContent: "flex-start",
166 | padding: 10,
167 | margin: 5,
168 | borderRadius: 10,
169 | backgroundColor: "white",
170 | borderWidth: 2,
171 | borderColor: "gray",
172 | },
173 | text: {
174 | fontWeight: "bold",
175 | fontSize: 24,
176 | },
177 | underlayRight: {
178 | flex: 1,
179 | justifyContent: "flex-start",
180 | borderWidth: 0,
181 | },
182 | underlayLeft: {
183 | flex: 1,
184 | justifyContent: "flex-end",
185 | borderWidth: 0,
186 | },
187 | sep: {
188 | borderWidth: 1,
189 | borderColor: "gray",
190 | marginHorizontal: 10,
191 | opacity: 0.5,
192 | alignSelf: "stretch",
193 | marginVertical: 10,
194 | },
195 | });
196 | //
197 | // seteditable(!editable)}>
198 | // seteditable(false)}
202 | // editable={editable}
203 | // onChangeText={(text) => change_text({ item, text })}
204 | // value={item.text}
205 | // style={[styles.text, { flex: 1 }]}
206 | // />
207 | //
208 | // ;
209 |
--------------------------------------------------------------------------------