├── .eslintrc.js ├── .gitignore ├── .watchmanconfig ├── App.js ├── README.md ├── app.json ├── assets ├── fonts │ └── NotoSans-Regular.ttf ├── icon.png └── splash.png ├── babel.config.js ├── components └── Button.js └── package.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "extends": "airbnb" 3 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | *.jks 5 | *.p12 6 | *.key 7 | *.mobileprovision 8 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, Text, View, TouchableOpacity } from "react-native"; 3 | import Btn from "./components/Button"; 4 | import { LinearGradient } from "expo"; 5 | import { Feather } from "@expo/vector-icons"; 6 | 7 | export default class App extends React.Component { 8 | state = { 9 | value: null, 10 | displayValue: "0", 11 | colorView: true, 12 | waitingForOperand: false, 13 | operator: null, 14 | bts: " " 15 | }; 16 | 17 | inputDigit = digit => { 18 | const { displayValue, waitingForOperand } = this.state; 19 | 20 | if (waitingForOperand) { 21 | this.setState({ 22 | displayValue: String(digit), 23 | waitingForOperand: false 24 | }); 25 | } else { 26 | this.setState({ 27 | displayValue: 28 | displayValue === "0" ? String(digit) : displayValue + digit 29 | }); 30 | } 31 | }; 32 | 33 | inputDot = () => { 34 | const { displayValue, waitingForOperand } = this.state; 35 | 36 | if (waitingForOperand) { 37 | this.setState({ 38 | displayValue: ".", 39 | waitingForOperand: false 40 | }); 41 | } else if (displayValue.indexOf(".") === -1) { 42 | this.setState({ 43 | displayValue: displayValue + ".", 44 | waitingForOperand: false 45 | }); 46 | } 47 | }; 48 | 49 | toggleColor = () => { 50 | this.setState({ 51 | colorView: !this.state.colorView 52 | }); 53 | }; 54 | 55 | clearDisplay = () => { 56 | this.setState({ 57 | displayValue: "0", 58 | bts: " " 59 | }); 60 | }; 61 | 62 | toggleSign = () => { 63 | const { displayValue } = this.state; 64 | 65 | this.setState({ 66 | displayValue: 67 | displayValue.charAt(0) === "-" 68 | ? displayValue.substr(1) 69 | : "-" + displayValue 70 | }); 71 | }; 72 | 73 | inputPercent = () => { 74 | const { displayValue } = this.state; 75 | const value = parseFloat(displayValue); 76 | this.setState({ 77 | displayValue: String(value / 100) 78 | }); 79 | }; 80 | 81 | performOperation = nextOperator => { 82 | const { displayValue, operator, value } = this.state; 83 | 84 | const nextValue = parseFloat(displayValue); 85 | 86 | const operations = { 87 | "/": (prevValue, nextValue) => prevValue / nextValue, 88 | x: (prevValue, nextValue) => prevValue * nextValue, 89 | "+": (prevValue, nextValue) => prevValue + nextValue, 90 | "-": (prevValue, nextValue) => prevValue - nextValue, 91 | "=": (prevValue, nextValue) => nextValue 92 | }; 93 | 94 | if (value == null) { 95 | this.setState({ 96 | value: nextValue 97 | }); 98 | } else if (operator) { 99 | const currentValue = value || 0; 100 | const computedValue = operations[operator](currentValue, nextValue); 101 | 102 | this.setState({ 103 | value: computedValue, 104 | displayValue: String(computedValue), 105 | bts: operator === "=" ? " " : `${currentValue} ${operator} ${nextValue}` 106 | }); 107 | } 108 | 109 | this.setState({ 110 | waitingForOperand: true, 111 | operator: nextOperator 112 | }); 113 | }; 114 | 115 | render() { 116 | const { displayValue } = this.state; 117 | return ( 118 | 119 | 128 | 129 | {this.state.colorView ? ( 130 | 138 | ) : ( 139 | 147 | )} 148 | 153 | {this.state.bts} 154 | 155 | {displayValue} 156 | 157 | 158 | 159 | 167 | 168 | 173 | 178 | 183 | this.performOperation("/")} 187 | /> 188 | 189 | 190 | 191 | this.inputDigit(7)} 194 | colorText={this.state.colorView} 195 | /> 196 | this.inputDigit(8)} 199 | colorText={this.state.colorView} 200 | /> 201 | this.inputDigit(9)} 204 | colorText={this.state.colorView} 205 | /> 206 | this.performOperation("x")} 210 | /> 211 | 212 | 213 | this.inputDigit(4)} 216 | colorText={this.state.colorView} 217 | /> 218 | this.inputDigit(5)} 221 | colorText={this.state.colorView} 222 | /> 223 | this.inputDigit(6)} 226 | colorText={this.state.colorView} 227 | /> 228 | this.performOperation("-")} 232 | /> 233 | 234 | 235 | this.inputDigit(1)} 238 | colorText={this.state.colorView} 239 | /> 240 | this.inputDigit(2)} 243 | colorText={this.state.colorView} 244 | /> 245 | this.inputDigit(3)} 248 | colorText={this.state.colorView} 249 | /> 250 | this.performOperation("+")} 254 | /> 255 | 256 | 257 | 258 | this.inputDigit(0)} 262 | zero 263 | /> 264 | 265 | 270 | 280 | this.performOperation("=")} 283 | > 284 | 288 | {"="} 289 | 290 | 291 | 292 | 293 | 294 | 295 | ); 296 | } 297 | } 298 | 299 | const styles = StyleSheet.create({ 300 | container: { 301 | flex: 1 302 | }, 303 | number: { 304 | color: "#fff", 305 | textAlign: "right", 306 | padding: 10, 307 | fontSize: 36 308 | // borderBottomWidth: 0.5, 309 | // borderColor: "#19153E" 310 | }, 311 | top: { 312 | paddingTop: 120 313 | }, 314 | bottom: { 315 | flex: 1 316 | }, 317 | row: { 318 | flex: 1, 319 | flexDirection: "row", 320 | borderBottomWidth: 0.2, 321 | borderColor: "#19153E" 322 | }, 323 | button: { 324 | flex: 1, 325 | alignItems: "center", 326 | justifyContent: "center" 327 | }, 328 | numberBTS: { 329 | color: "#6191FF", 330 | textAlign: "right", 331 | padding: 10, 332 | fontSize: 26 333 | }, 334 | numberBTSL: { 335 | color: "#FDFCFC", 336 | textAlign: "right", 337 | padding: 10, 338 | fontSize: 26 339 | } 340 | }); 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Modern Twin Calculator w/React Native 2 | 3 | 4 | Modern Calculator with Day/Night Switch help stand out in dark and light area 5 | 6 | Scan the QR code from the above link with your Expo App with Android/Iphone 7 | 8 | ### How to Load the App 9 | ``` 10 | git clone https://github.com/oliver-gomes/react-native-calculator-new.git 11 | npm install 12 | npm start 13 | ``` 14 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "Calculator App", 4 | "slug": "calculator", 5 | "privacy": "public", 6 | "sdkVersion": "32.0.0", 7 | "platforms": [ 8 | "ios", 9 | "android" 10 | ], 11 | "version": "1.0.0", 12 | "orientation": "portrait", 13 | "icon": "./assets/icon.png", 14 | "splash": { 15 | "image": "./assets/splash.png", 16 | "resizeMode": "contain", 17 | "backgroundColor": "#ffffff" 18 | }, 19 | "updates": { 20 | "fallbackToCacheTimeout": 0 21 | }, 22 | "assetBundlePatterns": [ 23 | "**/*" 24 | ], 25 | "ios": { 26 | "supportsTablet": true 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /assets/fonts/NotoSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanBinu007/react-native-calculator-new/486e5c5585cd43bc9144c13fcee5e53651840512/assets/fonts/NotoSans-Regular.ttf -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanBinu007/react-native-calculator-new/486e5c5585cd43bc9144c13fcee5e53651840512/assets/icon.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlanBinu007/react-native-calculator-new/486e5c5585cd43bc9144c13fcee5e53651840512/assets/splash.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /components/Button.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { View, Text, StyleSheet, TouchableOpacity } from "react-native"; 3 | 4 | const Btn = ({ text, colorText, onPress, zero }) => { 5 | return ( 6 | 10 | {text} 11 | 12 | ); 13 | }; 14 | const styles = StyleSheet.create({ 15 | container: { 16 | flex: 1, 17 | alignItems: "center", 18 | justifyContent: "center", 19 | borderRightWidth: 0.5, 20 | borderColor: "#19153E" 21 | }, 22 | zeroContainer: { 23 | flex: 2, 24 | alignItems: "center", 25 | justifyContent: "center", 26 | borderRightWidth: 0.5, 27 | borderColor: "#19153E" 28 | }, 29 | textLight: { 30 | fontSize: 34, 31 | color: "#fff" 32 | }, 33 | textDark: { 34 | fontSize: 34, 35 | color: "#575757" 36 | } 37 | }); 38 | export default Btn; 39 | -------------------------------------------------------------------------------- /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 | "eject": "expo eject" 8 | }, 9 | "name": "Calculator App", 10 | "dependencies": { 11 | "eslint": "^5.13.0", 12 | "expo": "^32.0.0", 13 | "react": "16.5.0", 14 | "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz", 15 | "react-redux": "^6.0.0", 16 | "redux": "^4.0.1" 17 | }, 18 | "devDependencies": { 19 | "babel-preset-expo": "^5.0.0", 20 | "eslint": "^5.13.0", 21 | "eslint-config-airbnb": "^17.1.0", 22 | "eslint-plugin-import": "^2.16.0", 23 | "eslint-plugin-jsx-a11y": "^6.2.0", 24 | "eslint-plugin-react": "^7.12.4" 25 | }, 26 | "private": true 27 | } 28 | --------------------------------------------------------------------------------