├── .babelrc ├── .buckconfig ├── .editorconfig ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .solidarity ├── .watchmanconfig ├── README.md ├── android ├── app │ ├── BUCK │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── fonts │ │ │ ├── Entypo.ttf │ │ │ ├── EvilIcons.ttf │ │ │ ├── FontAwesome.ttf │ │ │ ├── Foundation.ttf │ │ │ ├── Ionicons.ttf │ │ │ ├── MaterialCommunityIcons.ttf │ │ │ ├── MaterialIcons.ttf │ │ │ ├── Montserrat-Black.ttf │ │ │ ├── Montserrat-BlackItalic.ttf │ │ │ ├── Montserrat-Bold.ttf │ │ │ ├── Montserrat-BoldItalic.ttf │ │ │ ├── Montserrat-ExtraBold.ttf │ │ │ ├── Montserrat-ExtraBoldItalic.ttf │ │ │ ├── Montserrat-ExtraLight.ttf │ │ │ ├── Montserrat-ExtraLightItalic.ttf │ │ │ ├── Montserrat-Italic.ttf │ │ │ ├── Montserrat-Light.ttf │ │ │ ├── Montserrat-LightItalic.ttf │ │ │ ├── Montserrat-Medium.ttf │ │ │ ├── Montserrat-MediumItalic.ttf │ │ │ ├── Montserrat-Regular.ttf │ │ │ ├── Montserrat-SemiBold.ttf │ │ │ ├── Montserrat-SemiBoldItalic.ttf │ │ │ ├── Montserrat-Thin.ttf │ │ │ ├── Montserrat-ThinItalic.ttf │ │ │ ├── Octicons.ttf │ │ │ ├── SimpleLineIcons.ttf │ │ │ └── Zocial.ttf │ │ ├── java │ │ └── com │ │ │ └── equationsolver │ │ │ ├── MainActivity.java │ │ │ └── MainApplication.java │ │ └── res │ │ ├── drawable-hdpi │ │ └── launch_screen.png │ │ ├── drawable-ldpi │ │ └── launch_screen.png │ │ ├── drawable-mdpi │ │ └── launch_screen.png │ │ ├── drawable-xhdpi │ │ └── launch_screen.png │ │ ├── drawable-xxhdpi │ │ └── launch_screen.png │ │ ├── drawable-xxxhdpi │ │ └── launch_screen.png │ │ ├── drawable │ │ └── launch_screen.png │ │ ├── layout │ │ └── launch_screen.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystores │ ├── BUCK │ └── debug.keystore.properties └── settings.gradle ├── app.json ├── ignite ├── Examples │ └── Components │ │ └── vectorExample.js ├── ignite.json └── plugins │ └── .gitkeep ├── index.js ├── ios ├── EquationSolver-tvOS │ └── Info.plist ├── EquationSolver-tvOSTests │ └── Info.plist ├── EquationSolver.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── EquationSolver-tvOS.xcscheme │ │ └── EquationSolver.xcscheme ├── EquationSolver │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── LaunchImage.launchimage │ │ │ ├── Contents.json │ │ │ ├── LaunchImage-1242x2208@3x.png │ │ │ ├── LaunchImage-640x1136@2x.png │ │ │ ├── LaunchImage-640x960.png │ │ │ └── LaunchImage-750x1334@2x.png │ ├── Info.plist │ └── main.m └── EquationSolverTests │ ├── EquationSolverTests.m │ └── Info.plist ├── package.json ├── patches └── @types │ └── react-native+0.55.12.patch ├── rn-cli.config.js ├── src ├── app │ ├── environment-variables.ts │ ├── environment.ts │ ├── main.tsx │ ├── root-component.tsx │ ├── root-store.ts │ └── setup-root-store.ts ├── i18n │ ├── en.json │ ├── i18n.ts │ ├── index.ts │ ├── ja.json │ └── translate.ts ├── images │ ├── cubic.png │ ├── cubic@2x.png │ ├── cubic@3x.png │ ├── linear.png │ ├── linear@2x.png │ ├── linear@3x.png │ ├── quadratic.png │ ├── quadratic@2x.png │ └── quadratic@3x.png ├── lib │ ├── cubic.ts │ ├── delay.ts │ ├── isValid.ts │ ├── keychain.ts │ ├── quadratic.ts │ ├── storage │ │ ├── index.ts │ │ ├── storage.test.ts │ │ └── storage.ts │ ├── threeVariables.ts │ ├── twoVariables.ts │ └── validate.ts ├── navigation │ ├── back-button-handler.tsx │ ├── index.ts │ ├── navigation-config.ts │ ├── navigation-events.ts │ ├── navigation-store.ts │ ├── root-navigator.ts │ └── stateful-navigator.tsx ├── services │ ├── api │ │ ├── api-config.ts │ │ ├── api-problem.ts │ │ ├── api.ts │ │ ├── api.types.ts │ │ └── index.ts │ └── reactotron │ │ ├── command-middleware.ts │ │ ├── index.ts │ │ ├── reactotron-config.ts │ │ └── reactotron.ts ├── theme │ ├── color.ts │ ├── fonts │ │ ├── Montserrat-Black.ttf │ │ ├── Montserrat-BlackItalic.ttf │ │ ├── Montserrat-Bold.ttf │ │ ├── Montserrat-BoldItalic.ttf │ │ ├── Montserrat-ExtraBold.ttf │ │ ├── Montserrat-ExtraBoldItalic.ttf │ │ ├── Montserrat-ExtraLight.ttf │ │ ├── Montserrat-ExtraLightItalic.ttf │ │ ├── Montserrat-Italic.ttf │ │ ├── Montserrat-Light.ttf │ │ ├── Montserrat-LightItalic.ttf │ │ ├── Montserrat-Medium.ttf │ │ ├── Montserrat-MediumItalic.ttf │ │ ├── Montserrat-Regular.ttf │ │ ├── Montserrat-SemiBold.ttf │ │ ├── Montserrat-SemiBoldItalic.ttf │ │ ├── Montserrat-Thin.ttf │ │ └── Montserrat-ThinItalic.ttf │ ├── index.ts │ ├── palette.ts │ ├── spacing.ts │ ├── timing.ts │ └── typography.ts └── views │ ├── screens │ ├── cubic-equation │ │ ├── cubic-equation-screen.tsx │ │ └── index.ts │ ├── home │ │ ├── home-screen.tsx │ │ └── index.ts │ ├── linear-equation │ │ ├── index.ts │ │ └── linear-equation-screen.tsx │ ├── quadratic-equation │ │ ├── index.ts │ │ └── quadratic-equation-screen.tsx │ ├── three-linear-equation │ │ ├── index.ts │ │ └── three-linear-equation-screen.tsx │ └── two-linear-equation │ │ ├── index.ts │ │ └── two-linear-equation-screen.tsx │ └── shared │ ├── button │ ├── button.presets.ts │ ├── button.props.ts │ ├── button.story.tsx │ ├── button.tsx │ └── index.ts │ ├── checkbox │ ├── checkbox.props.ts │ ├── checkbox.story.tsx │ ├── checkbox.tsx │ └── index.ts │ ├── equation-input │ ├── equation-input.presets.ts │ ├── equation-input.props.ts │ ├── equation-input.story.tsx │ ├── equation-input.tsx │ └── index.ts │ ├── form-row │ ├── form-row.presets.ts │ ├── form-row.props.tsx │ ├── form-row.story.tsx │ ├── form-row.tsx │ └── index.ts │ ├── header │ ├── header.props.ts │ ├── header.story.tsx │ ├── header.tsx │ └── index.ts │ ├── icon │ ├── icon.props.ts │ ├── icon.story.tsx │ ├── icon.tsx │ ├── icons │ │ ├── arrow-left.png │ │ ├── arrow-left@2x.png │ │ ├── bullet.png │ │ ├── bullet@2x.png │ │ └── index.ts │ └── index.ts │ ├── screen │ ├── index.ts │ ├── screen.presets.ts │ ├── screen.props.ts │ └── screen.tsx │ ├── switch │ ├── index.ts │ ├── switch.props.ts │ ├── switch.story.tsx │ └── switch.tsx │ ├── text-field │ ├── index.ts │ ├── text-field.props.ts │ ├── text-field.story.tsx │ └── text-field.tsx │ ├── text │ ├── index.ts │ ├── text.presets.ts │ ├── text.props.ts │ ├── text.story.tsx │ └── text.tsx │ └── wallpaper │ ├── BG.png │ ├── bg@2x.png │ ├── index.ts │ ├── wallpaper.presets.ts │ ├── wallpaper.props.ts │ ├── wallpaper.story.tsx │ └── wallpaper.tsx ├── storybook ├── index.ts ├── storybook-registry.ts ├── storybook.tsx └── views │ ├── index.ts │ ├── story-screen.tsx │ ├── story.tsx │ └── use-case.tsx ├── test ├── __snapshots__ │ └── storyshots.test.ts.snap ├── mock-i18n.ts ├── mock-reactotron.ts ├── setup.ts └── storyshots.test.ts ├── tsconfig.json ├── tslint.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"], 3 | "env": { 4 | "production": { 5 | } 6 | }, 7 | "plugins": [ 8 | [ 9 | "transform-inline-environment-variables", 10 | { 11 | "include": ["NODE_ENV", "API"] 12 | } 13 | ] 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | indent_style = space 7 | tab_width = 2 8 | indent_size = 2 9 | max_line_length = 100 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | 16 | ; Ignore polyfills 17 | .*/Libraries/polyfills/.* 18 | 19 | ; Ignore metro 20 | .*/node_modules/metro/.* 21 | 22 | [include] 23 | 24 | [libs] 25 | node_modules/react-native/Libraries/react-native/react-native-interface.js 26 | node_modules/react-native/flow/ 27 | node_modules/react-native/flow-github/ 28 | 29 | [options] 30 | emoji=true 31 | 32 | module.system=haste 33 | 34 | munge_underscores=true 35 | 36 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 37 | 38 | module.file_ext=.js 39 | module.file_ext=.jsx 40 | module.file_ext=.json 41 | module.file_ext=.native.js 42 | 43 | suppress_type=$FlowIssue 44 | suppress_type=$FlowFixMe 45 | suppress_type=$FlowFixMeProps 46 | suppress_type=$FlowFixMeState 47 | 48 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 50 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 51 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 52 | 53 | [version] 54 | ^0.67.0 55 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | *.bat text eol=crlf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | ios 3 | android 4 | .vscode 5 | package.json 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "semi": false, 4 | "singleQuote": false, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /.solidarity: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/solidaritySchema", 3 | "requirements": { 4 | "Yarn": [{ "rule": "cli", "binary": "yarn", "semver": "^1.3.2" }], 5 | "Node": [{ "rule": "cli", "binary": "node", "semver": ">=8.6.0" }], 6 | "React Native": [ 7 | { 8 | "rule": "cli", 9 | "binary": "react-native", 10 | "semver": ">=2.0.1" 11 | } 12 | ], 13 | "Xcode": [ 14 | { 15 | "rule": "cli", 16 | "binary": "xcodebuild", 17 | "version": "-version", 18 | "semver": ">=9.2.0", 19 | "platform": "darwin" 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EquationSolver 2 | 3 | 4 | # Installation 5 | 1. git clone https://github.com/ebouJ/Equation-Solver 6 | 2. cd Equation-Solver 7 | 3. yarn install or npm install 8 | 4. react-native run-ios 9 | 10 | 11 | ## Appstore URL 12 | [Equation Solver](https://itunes.apple.com/us/app/equation-solver/id1420956198?mt=8) 13 | ## Screenshots 14 | ![1](https://user-images.githubusercontent.com/22877561/48787265-753dfd80-ecb6-11e8-80d7-4ecd26da8847.jpg) 15 | ![2](https://user-images.githubusercontent.com/22877561/48787759-6dcb2400-ecb7-11e8-910f-58a6fa093522.jpg) 16 | ![3](https://user-images.githubusercontent.com/22877561/48787763-6f94e780-ecb7-11e8-886c-2119181e0897.jpg) 17 | ![4](https://user-images.githubusercontent.com/22877561/48787767-70c61480-ecb7-11e8-9f28-c49393fe4c38.jpg) 18 | 19 | -------------------------------------------------------------------------------- /android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.equationsolver", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.equationsolver", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout. 54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. 55 | -dontwarn android.text.StaticLayout 56 | 57 | # okhttp 58 | 59 | -keepattributes Signature 60 | -keepattributes *Annotation* 61 | -keep class okhttp3.** { *; } 62 | -keep interface okhttp3.** { *; } 63 | -dontwarn okhttp3.** 64 | 65 | # okio 66 | 67 | -keep class sun.misc.Unsafe { *; } 68 | -dontwarn java.nio.file.* 69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 70 | -dontwarn okio.** 71 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Entypo.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Foundation.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Ionicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-Black.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-BlackItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-BoldItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-ExtraBold.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-ExtraLight.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-Italic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-Light.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-LightItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-Medium.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-MediumItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-Regular.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-SemiBold.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-Thin.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Montserrat-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Montserrat-ThinItalic.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Octicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/SimpleLineIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/SimpleLineIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/assets/fonts/Zocial.ttf -------------------------------------------------------------------------------- /android/app/src/main/java/com/equationsolver/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.equationsolver; 2 | 3 | import android.os.Bundle; 4 | import com.facebook.react.ReactActivity; 5 | import com.oblador.vectoricons.VectorIconsPackage; 6 | import org.devio.rn.splashscreen.SplashScreen; 7 | 8 | public class MainActivity extends ReactActivity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | SplashScreen.show(this); 13 | super.onCreate(savedInstanceState); 14 | } 15 | 16 | /** 17 | * Returns the name of the main component registered from JavaScript. 18 | * This is used to schedule rendering of the component. 19 | */ 20 | @Override 21 | protected String getMainComponentName() { 22 | return "EquationSolver"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/equationsolver/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.equationsolver; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import org.devio.rn.splashscreen.SplashScreenReactPackage; 7 | import com.oblador.keychain.KeychainPackage; 8 | import com.AlexanderZaytsev.RNI18n.RNI18nPackage; 9 | import com.facebook.react.ReactNativeHost; 10 | import com.facebook.react.ReactPackage; 11 | import com.facebook.react.shell.MainReactPackage; 12 | import com.facebook.soloader.SoLoader; 13 | 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | public class MainApplication extends Application implements ReactApplication { 18 | 19 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 20 | @Override 21 | public boolean getUseDeveloperSupport() { 22 | return BuildConfig.DEBUG; 23 | } 24 | 25 | @Override 26 | protected List getPackages() { 27 | return Arrays.asList( 28 | new MainReactPackage(), 29 | new SplashScreenReactPackage(), 30 | new KeychainPackage(), 31 | new RNI18nPackage() 32 | ); 33 | } 34 | 35 | @Override 36 | protected String getJSMainModuleName() { 37 | return "index"; 38 | } 39 | }; 40 | 41 | @Override 42 | public ReactNativeHost getReactNativeHost() { 43 | return mReactNativeHost; 44 | } 45 | 46 | @Override 47 | public void onCreate() { 48 | super.onCreate(); 49 | SoLoader.init(this, /* native exopackage */ false); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/drawable-hdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-ldpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/drawable-ldpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/drawable-mdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/drawable-xhdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/drawable-xxhdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/drawable-xxxhdpi/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/drawable/launch_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/layout/launch_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #660B0B0B 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | EquationSolver 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'EquationSolver' 2 | include ':react-native-splash-screen' 3 | project(':react-native-splash-screen').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-splash-screen/android') 4 | include ':react-native-keychain' 5 | project(':react-native-keychain').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keychain/android') 6 | include ':react-native-i18n' 7 | project(':react-native-i18n').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-i18n/android') 8 | 9 | include ':app' 10 | include ':react-native-vector-icons' 11 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') 12 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EquationSolver", 3 | "displayName": "EquationSolver" 4 | } -------------------------------------------------------------------------------- /ignite/Examples/Components/vectorExample.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React from 'react' 4 | import { View } from 'react-native' 5 | import ExamplesRegistry from '../../../App/Services/ExamplesRegistry' 6 | import Icon from 'react-native-vector-icons/FontAwesome' 7 | 8 | // Example 9 | ExamplesRegistry.addPluginExample('Vector Icons', () => 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ) 18 | -------------------------------------------------------------------------------- /ignite/ignite.json: -------------------------------------------------------------------------------- 1 | { 2 | "createdWith": "2.1.0", 3 | "examples": "classic", 4 | "navigation": "react-navigation", 5 | "askToOverwrite": true, 6 | "generators": { 7 | "component": "ignite-ir-boilerplate-bowser", 8 | "model": "ignite-ir-boilerplate-bowser", 9 | "screen": "ignite-ir-boilerplate-bowser" 10 | } 11 | } -------------------------------------------------------------------------------- /ignite/plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/ignite/plugins/.gitkeep -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // This is the first file that ReactNative will run when it starts up. 2 | // 3 | // We jump out of here immediately and into our main entry point instead. 4 | // 5 | // It is possible to have React Native load our main module first, but we'd have to 6 | // change that in both AppDelegate.m and MainApplication.java. This would have the 7 | // side effect of breaking other tooling like mobile-center and react-native-rename. 8 | // 9 | // It's easier just to leave it here. 10 | 11 | import "./src/app/main" 12 | -------------------------------------------------------------------------------- /ios/EquationSolver-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /ios/EquationSolver-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/EquationSolver.xcodeproj/xcshareddata/xcschemes/EquationSolver-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/EquationSolver.xcodeproj/xcshareddata/xcschemes/EquationSolver.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 61 | 67 | 68 | 69 | 70 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 92 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 111 | 113 | 119 | 120 | 121 | 122 | 124 | 125 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /ios/EquationSolver/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | 10 | @interface AppDelegate : UIResponder 11 | 12 | @property (nonatomic, strong) UIWindow *window; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /ios/EquationSolver/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import "AppDelegate.h" 9 | #import "SplashScreen.h" 10 | 11 | #import 12 | #import 13 | 14 | @implementation AppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | NSURL *jsCodeLocation; 19 | 20 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 21 | 22 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 23 | moduleName:@"EquationSolver" 24 | initialProperties:nil 25 | launchOptions:launchOptions]; 26 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 27 | 28 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 29 | UIViewController *rootViewController = [UIViewController new]; 30 | rootViewController.view = rootView; 31 | self.window.rootViewController = rootViewController; 32 | [self.window makeKeyAndVisible]; 33 | [SplashScreen show]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ios/EquationSolver/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ios/EquationSolver/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /ios/EquationSolver/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ios/EquationSolver/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "LaunchImage-1242x2208@3x.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "667h", 16 | "filename" : "LaunchImage-750x1334@2x.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "portrait", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "orientation" : "portrait", 23 | "idiom" : "iphone", 24 | "filename" : "LaunchImage-640x960.png", 25 | "extent" : "full-screen", 26 | "minimum-system-version" : "7.0", 27 | "scale" : "2x" 28 | }, 29 | { 30 | "extent" : "full-screen", 31 | "idiom" : "iphone", 32 | "subtype" : "retina4", 33 | "filename" : "LaunchImage-640x1136@2x.png", 34 | "minimum-system-version" : "7.0", 35 | "orientation" : "portrait", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "orientation" : "portrait", 40 | "idiom" : "iphone", 41 | "filename" : "LaunchImage-640x960.png", 42 | "extent" : "full-screen", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "orientation" : "portrait", 47 | "idiom" : "iphone", 48 | "filename" : "LaunchImage-640x1136@2x.png", 49 | "extent" : "full-screen", 50 | "subtype" : "retina4", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /ios/EquationSolver/Images.xcassets/LaunchImage.launchimage/LaunchImage-1242x2208@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/ios/EquationSolver/Images.xcassets/LaunchImage.launchimage/LaunchImage-1242x2208@3x.png -------------------------------------------------------------------------------- /ios/EquationSolver/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x1136@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/ios/EquationSolver/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x1136@2x.png -------------------------------------------------------------------------------- /ios/EquationSolver/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x960.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/ios/EquationSolver/Images.xcassets/LaunchImage.launchimage/LaunchImage-640x960.png -------------------------------------------------------------------------------- /ios/EquationSolver/Images.xcassets/LaunchImage.launchimage/LaunchImage-750x1334@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/ios/EquationSolver/Images.xcassets/LaunchImage.launchimage/LaunchImage-750x1334@2x.png -------------------------------------------------------------------------------- /ios/EquationSolver/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | EquationSolver 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSExceptionDomains 30 | 31 | localhost 32 | 33 | NSExceptionAllowsInsecureHTTPLoads 34 | 35 | 36 | 37 | 38 | NSLocationWhenInUseUsageDescription 39 | 40 | UIAppFonts 41 | 42 | Montserrat-Black.ttf 43 | Montserrat-BlackItalic.ttf 44 | Montserrat-Bold.ttf 45 | Montserrat-BoldItalic.ttf 46 | Montserrat-ExtraBold.ttf 47 | Montserrat-ExtraBoldItalic.ttf 48 | Montserrat-ExtraLight.ttf 49 | Montserrat-ExtraLightItalic.ttf 50 | Montserrat-Italic.ttf 51 | Montserrat-Light.ttf 52 | Montserrat-LightItalic.ttf 53 | Montserrat-Medium.ttf 54 | Montserrat-MediumItalic.ttf 55 | Montserrat-Regular.ttf 56 | Montserrat-SemiBold.ttf 57 | Montserrat-SemiBoldItalic.ttf 58 | Montserrat-Thin.ttf 59 | Montserrat-ThinItalic.ttf 60 | Entypo.ttf 61 | EvilIcons.ttf 62 | FontAwesome.ttf 63 | Foundation.ttf 64 | Ionicons.ttf 65 | MaterialCommunityIcons.ttf 66 | MaterialIcons.ttf 67 | Octicons.ttf 68 | SimpleLineIcons.ttf 69 | Zocial.ttf 70 | 71 | UIRequiredDeviceCapabilities 72 | 73 | armv7 74 | 75 | UIStatusBarStyle 76 | UIStatusBarStyleLightContent 77 | UISupportedInterfaceOrientations 78 | 79 | UIInterfaceOrientationPortrait 80 | UIInterfaceOrientationLandscapeLeft 81 | UIInterfaceOrientationLandscapeRight 82 | 83 | UIViewControllerBasedStatusBarAppearance 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /ios/EquationSolver/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ios/EquationSolverTests/EquationSolverTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | #import 12 | #import 13 | 14 | #define TIMEOUT_SECONDS 600 15 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 16 | 17 | @interface EquationSolverTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation EquationSolverTests 22 | 23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 24 | { 25 | if (test(view)) { 26 | return YES; 27 | } 28 | for (UIView *subview in [view subviews]) { 29 | if ([self findSubviewInView:subview matching:test]) { 30 | return YES; 31 | } 32 | } 33 | return NO; 34 | } 35 | 36 | - (void)testRendersWelcomeScreen 37 | { 38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 40 | BOOL foundElement = NO; 41 | 42 | __block NSString *redboxError = nil; 43 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 44 | if (level >= RCTLogLevelError) { 45 | redboxError = message; 46 | } 47 | }); 48 | 49 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 50 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 51 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 52 | 53 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 54 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 55 | return YES; 56 | } 57 | return NO; 58 | }]; 59 | } 60 | 61 | RCTSetLogFunction(RCTDefaultLogFunction); 62 | 63 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 64 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 65 | } 66 | 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /ios/EquationSolverTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EquationSolver", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "test": "jest", 8 | "compile": "tsc --noEmit -p . --pretty", 9 | "format": "npm-run-all format:*", 10 | "format:js": "prettier --write {.,**}/*.js", 11 | "format:json": "prettier --write {.,**}/*.json", 12 | "format:md": "prettier --write {.,**}/*.md", 13 | "format:ts": "prettier --write {.,**}/*.{ts,tsx} && tslint --fix -p .", 14 | "lint": "npm-run-all lint:*", 15 | "lint:ts": "tslint -p .", 16 | "postinstall": "solidarity", 17 | "hack:types-react-navigation": "rimraf node_modules/@types/react-navigation/node_modules/@types", 18 | "hack:types-react-native": "rimraf node_modules/@types/react-native/node_modules/@types", 19 | "hack:types-react-test-renderer": "rimraf node_modules/@types/react-test-renderer/node_modules/@types", 20 | "patch": "patch-package", 21 | "prepare": "npm-run-all patch hack:*", 22 | "storybook": "storybook start -p 9001 --skip-packager" 23 | }, 24 | "dependencies": { 25 | "@types/react-native-vector-icons": "^4.6.1", 26 | "apisauce": "0.14.3", 27 | "lodash.throttle": "4.1.1", 28 | "mobx": "4.2.1", 29 | "mobx-react": "5.1.2", 30 | "mobx-state-tree": "2.0.5", 31 | "ramda": "0.25.0", 32 | "react": "16.3.1", 33 | "react-mathjax2": "^0.0.1", 34 | "react-native": "0.55.4", 35 | "react-native-i18n": "2.0.12", 36 | "react-native-keyboard-aware-scroll-view": "^0.6.0", 37 | "react-native-keyboard-aware-view": "^0.0.14", 38 | "react-native-keychain": "3.0.0-rc.3", 39 | "react-native-simple-toast": "^0.0.8", 40 | "react-native-splash-screen": "3.0.6", 41 | "react-native-vector-icons": "4.3.0", 42 | "react-navigation": "2.0.4", 43 | "reactotron-mst": "2.0.0-beta.2", 44 | "reactotron-react-native": "2.0.0-beta.2", 45 | "validate.js": "0.12.0" 46 | }, 47 | "devDependencies": { 48 | "@storybook/addon-storyshots": "github:infinitered/addon-storyshots", 49 | "@storybook/react-native": "3.4.3", 50 | "@types/jest": "22.2.3", 51 | "@types/ramda": "0.25.28", 52 | "@types/react": "16.0.40", 53 | "@types/react-native": "0.55.12", 54 | "@types/react-navigation": "1.5.2", 55 | "@types/react-test-renderer": "16.0.1", 56 | "@types/validate.js": "0.11.0", 57 | "babel-jest": "23.4.2", 58 | "babel-plugin-transform-inline-environment-variables": "0.4.1", 59 | "babel-preset-react-native": "4.0.0", 60 | "ignite-ir-boilerplate-bowser": "^1.0.0-beta.1", 61 | "ignite-vector-icons": "^1.1.0", 62 | "jest": "23.4.2", 63 | "jest-preset-ignite": "0.5.0", 64 | "npm-run-all": "4.1.3", 65 | "patch-package": "5.1.1", 66 | "postinstall-prepare": "1.0.1", 67 | "prettier": "1.12.1", 68 | "react-dom": "16.2.0", 69 | "react-native-typescript-transformer": "1.2.5", 70 | "react-powerplug": "0.1.5", 71 | "react-test-renderer": "16.3.1", 72 | "rimraf": "2.6.2", 73 | "solidarity": "2.1.0", 74 | "tslint": "5.10.0", 75 | "tslint-config-prettier": "1.12.0", 76 | "typescript": "2.8.3" 77 | }, 78 | "jest": { 79 | "preset": "jest-preset-ignite" 80 | }, 81 | "rnpm": { 82 | "assets": [ 83 | "./src/theme/fonts/" 84 | ] 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /patches/@types/react-native+0.55.12.patch: -------------------------------------------------------------------------------- 1 | patch-package 2 | --- a/node_modules/@types/react-native/index.d.ts 3 | +++ b/node_modules/@types/react-native/index.d.ts 4 | @@ -8739,7 +8739,7 @@ declare global { 5 | ignoredYellowBox: string[]; 6 | } 7 | 8 | - const console: Console; 9 | + // const console: Console; 10 | 11 | /** 12 | * Navigator object for accessing location API 13 | @@ -8747,10 +8747,11 @@ declare global { 14 | */ 15 | interface Navigator { 16 | readonly product: string; 17 | + // @ts-ignore 18 | readonly geolocation: Geolocation; 19 | } 20 | 21 | - const navigator: Navigator; 22 | + // const navigator: Navigator; 23 | 24 | /** 25 | * This contains the non-native `XMLHttpRequest` object, which you can use if you want to route network requests 26 | -------------------------------------------------------------------------------- /rn-cli.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | getTransformModulePath () { 3 | return require.resolve('react-native-typescript-transformer') 4 | }, 5 | getSourceExts () { 6 | return ['ts', 'tsx'] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/app/environment-variables.ts: -------------------------------------------------------------------------------- 1 | // 2 | // Load environment variables in. 3 | // 4 | // IMPORTANT: 5 | // 6 | // 1. These might be null, so fallback to sane defaults accordingly where you 7 | // make use of these. 8 | // 9 | // 2. You must use this syntax: process.env.NAME_OF_ENV_VAR. No funny stuff 10 | // or the babel plugin won't work. 11 | // 12 | // 3. You must whitelist each one in your `.babelrc` file. 13 | // 14 | // GOTCHA: 15 | // 16 | // Babel will cache things extensively. In dev, to bust this cache to pick up 17 | // new environment variable values, just change this file and resave it. 18 | // 19 | // Or run `yarn start --reset-cache` to nuke babel's cache entirely 20 | // (overkill). 21 | // 22 | // ---------------------------------------------------------------------------- 23 | 24 | // tell typescript that there will be a the `node.js` process global variable used 25 | declare var process: any 26 | 27 | /** 28 | * An example importing an environment variable. 29 | */ 30 | export const API: string | undefined = process.env.API 31 | -------------------------------------------------------------------------------- /src/app/environment.ts: -------------------------------------------------------------------------------- 1 | import { Reactotron } from "../services/reactotron" 2 | import { Api } from "../services/api" 3 | 4 | /** 5 | * The environment is a place where services and shared dependencies between 6 | * models live. They are made available to every model via dependency injection. 7 | */ 8 | export class Environment { 9 | /** 10 | * Reactotron is only available in dev. 11 | */ 12 | reactotron: Reactotron 13 | 14 | /** 15 | * Our api. 16 | */ 17 | api: Api 18 | } 19 | -------------------------------------------------------------------------------- /src/app/main.tsx: -------------------------------------------------------------------------------- 1 | // Welcome to the main entry point. 2 | // 3 | // In this file, we'll be kicking off our app or storybook. 4 | 5 | import { AppRegistry } from "react-native" 6 | import { RootComponent } from "./root-component" 7 | import { StorybookUIRoot } from "../../storybook" 8 | 9 | /** 10 | * This needs to match what's found in your app_delegate.m and MainActivity.java. 11 | */ 12 | const APP_NAME = "EquationSolver" 13 | 14 | // Should we show storybook instead of our app? 15 | // 16 | // ⚠️ Leave this as `false` when checking into git. 17 | const SHOW_STORYBOOK = false 18 | 19 | // appease the typescript overlords 20 | declare global { 21 | var module 22 | } 23 | 24 | if (SHOW_STORYBOOK && __DEV__) { 25 | // 🎗 REMINDER: Storybook has a server you need to run from a terminal window. 26 | // 27 | // $> yarn run storybook 28 | // 29 | AppRegistry.registerComponent(APP_NAME, () => StorybookUIRoot) 30 | } else { 31 | // load our app 32 | AppRegistry.registerComponent(APP_NAME, () => RootComponent) 33 | } 34 | -------------------------------------------------------------------------------- /src/app/root-component.tsx: -------------------------------------------------------------------------------- 1 | import "../i18n" 2 | import * as React from "react" 3 | import { setupRootStore } from "./setup-root-store" 4 | import { StatefulNavigator } from "../navigation" 5 | import { RootStore } from "../app/root-store" 6 | import { Provider } from "mobx-react" 7 | import { BackButtonHandler } from "../navigation/back-button-handler" 8 | import { contains } from "ramda" 9 | import { DEFAULT_NAVIGATION_CONFIG } from "../navigation/navigation-config" 10 | import SplashScreen from "react-native-splash-screen" 11 | 12 | interface RootComponentState { 13 | rootStore?: RootStore 14 | } 15 | 16 | /** 17 | * This is the root component of our app. 18 | */ 19 | export class RootComponent extends React.Component<{}, RootComponentState> { 20 | /** 21 | * When the component is mounted. This happens asynchronously and simply 22 | * re-renders when we're good to go. 23 | */ 24 | async componentDidMount() { 25 | SplashScreen.hide() 26 | this.setState({ 27 | rootStore: await setupRootStore(), 28 | }) 29 | } 30 | 31 | /** 32 | * Are we allowed to exit the app? This is called when the back button 33 | * is pressed on android. 34 | * 35 | * @param routeName The currently active route name. 36 | */ 37 | canExit(routeName: string) { 38 | return contains(routeName, DEFAULT_NAVIGATION_CONFIG.exitRoutes) 39 | } 40 | 41 | render() { 42 | const rootStore = this.state && this.state.rootStore 43 | 44 | // Before we show the app, we have to wait for out state to be ready. 45 | // In the meantime, don't render anything. This will be the background 46 | // color set in native by rootView's background color. 47 | // 48 | // This step should be completely covered over by the splash screen though. 49 | // 50 | // You're welcome to swap in your own component to render if your boot up 51 | // sequence is too slow though. 52 | if (!rootStore) { 53 | return null 54 | } 55 | 56 | // otherwise, we're ready to render the app 57 | 58 | // --- am: begin list of stores --- 59 | const otherStores = {} 60 | // --- am: end list of stores --- 61 | 62 | return ( 63 | 64 | 65 | 66 | 67 | 68 | ) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/app/root-store.ts: -------------------------------------------------------------------------------- 1 | import { types } from "mobx-state-tree" 2 | import { NavigationStoreModel } from "../navigation/navigation-store" 3 | 4 | /** 5 | * An RootStore model. 6 | */ 7 | export const RootStoreModel = types.model("RootStore").props({ 8 | navigationStore: types.optional(NavigationStoreModel, {}), 9 | }) 10 | 11 | /** 12 | * The RootStore instance. 13 | */ 14 | export type RootStore = typeof RootStoreModel.Type 15 | 16 | /** 17 | * The data of an RootStore. 18 | */ 19 | export type RootStoreSnapshot = typeof RootStoreModel.SnapshotType 20 | -------------------------------------------------------------------------------- /src/app/setup-root-store.ts: -------------------------------------------------------------------------------- 1 | import { onSnapshot } from "mobx-state-tree" 2 | import { RootStoreModel, RootStore } from "./root-store" 3 | import { Environment } from "./environment" 4 | import * as storage from "../lib/storage" 5 | import { Reactotron } from "../services/reactotron" 6 | import { Api } from "../services/api" 7 | 8 | /** 9 | * The key we'll be saving our state as within async storage. 10 | */ 11 | const ROOT_STATE_STORAGE_KEY = "root" 12 | 13 | /** 14 | * Setup the root state. 15 | */ 16 | export async function setupRootStore() { 17 | let rootStore: RootStore 18 | let data: any 19 | 20 | // prepare the environment that will be associated with the RootStore. 21 | const env = await createEnvironment() 22 | try { 23 | // load data from storage 24 | data = (await storage.load(ROOT_STATE_STORAGE_KEY)) || {} 25 | rootStore = RootStoreModel.create(data, env) 26 | } catch { 27 | // if there's any problems loading, then let's at least fallback to an empty state 28 | // instead of crashing. 29 | rootStore = RootStoreModel.create({}, env) 30 | } 31 | 32 | // reactotron logging 33 | if (__DEV__) { 34 | env.reactotron.setRootStore(rootStore, data) 35 | } 36 | 37 | // track changes & save to storage 38 | onSnapshot(rootStore, snapshot => storage.save(ROOT_STATE_STORAGE_KEY, snapshot)) 39 | 40 | return rootStore 41 | } 42 | 43 | /** 44 | * Setup the environment that all the models will be sharing. 45 | * 46 | * The environment includes other functions that will be picked from some 47 | * of the models that get created later. This is how we loosly couple things 48 | * like events between models. 49 | */ 50 | export async function createEnvironment() { 51 | const env = new Environment() 52 | 53 | // create each service 54 | env.reactotron = new Reactotron() 55 | env.api = new Api() 56 | 57 | // allow each service to setup 58 | await env.reactotron.setup() 59 | await env.api.setup() 60 | 61 | return env 62 | } 63 | -------------------------------------------------------------------------------- /src/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "common": { 3 | "ok": "OK!", 4 | "cancel": "Cancel", 5 | "back": "Back" 6 | }, 7 | "home": { 8 | "header": "Equation Solver", 9 | "systems": "Systems of Equation", 10 | "two": "Two Variables", 11 | "three": "Three Variables", 12 | "linear": "Linear Equation", 13 | "quadratic": "Quadratic Equation", 14 | "cubic": "Cubic Equation", 15 | "polynomials": "Polynomials" 16 | }, 17 | "linear": { 18 | "header": "Linear Equation" 19 | }, 20 | "quadratic": { 21 | "header": "Quadratic Equation" 22 | }, 23 | "cubic": { 24 | "header": "Cubic Equation" 25 | }, 26 | "three": { 27 | "header": "3 Variable Equations" 28 | }, 29 | "two": { 30 | "header": "2 Variable Equations" 31 | }, 32 | "errors": { 33 | "invalidEmail": "Invalid email address." 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/i18n/i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from "react-native-i18n" 2 | 3 | const en = require("./en") 4 | const ja = require("./ja") 5 | 6 | I18n.fallbacks = true 7 | I18n.translations = { en, ja } 8 | -------------------------------------------------------------------------------- /src/i18n/index.ts: -------------------------------------------------------------------------------- 1 | import "./i18n" 2 | export * from "./translate" 3 | -------------------------------------------------------------------------------- /src/i18n/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "common": { 3 | "ok": "OK 🇯🇵", 4 | "cancel": "Cancel 🇯🇵", 5 | "back": "Back 🇯🇵" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/i18n/translate.ts: -------------------------------------------------------------------------------- 1 | import I18n from "react-native-i18n" 2 | 3 | /** 4 | * Translates text. 5 | * 6 | * @param key The i18n key. 7 | */ 8 | export function translate(key: string) { 9 | return key ? I18n.t(key) : null 10 | } 11 | 12 | /** 13 | * Translates with variables. 14 | * 15 | * @param key The i18n key 16 | * @param vars Additional values sure to replace. 17 | */ 18 | export function translateWithVars(key: string, vars: object) { 19 | return key ? I18n.t(key, vars) : null 20 | } 21 | -------------------------------------------------------------------------------- /src/images/cubic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/images/cubic.png -------------------------------------------------------------------------------- /src/images/cubic@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/images/cubic@2x.png -------------------------------------------------------------------------------- /src/images/cubic@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/images/cubic@3x.png -------------------------------------------------------------------------------- /src/images/linear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/images/linear.png -------------------------------------------------------------------------------- /src/images/linear@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/images/linear@2x.png -------------------------------------------------------------------------------- /src/images/linear@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/images/linear@3x.png -------------------------------------------------------------------------------- /src/images/quadratic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/images/quadratic.png -------------------------------------------------------------------------------- /src/images/quadratic@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/images/quadratic@2x.png -------------------------------------------------------------------------------- /src/images/quadratic@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/images/quadratic@3x.png -------------------------------------------------------------------------------- /src/lib/cubic.ts: -------------------------------------------------------------------------------- 1 | export default (a: number, b: number,c: number,d: number) => { 2 | if (Math.abs(a) < 1e-8) { // Quadratic case, ax^2+bx+c=0 3 | a = b; b = c; c = d 4 | if (Math.abs(a) < 1e-8) { // Linear case, ax+b=0 5 | a = b; b = c 6 | if (Math.abs(a) < 1e-8) // Degenerate case 7 | return [] 8 | return [-b/a] 9 | } 10 | 11 | let D = b*b - 4*a*c; 12 | if (Math.abs(D) < 1e-8) 13 | return [-b/(2*a)] 14 | else if (D > 0) 15 | return [(-b+Math.sqrt(D))/(2*a), (-b-Math.sqrt(D))/(2*a)] 16 | return [] 17 | } 18 | 19 | // Convert to depressed cubic t^3+pt+q = 0 (subst x = t - b/3a) 20 | let p = (3*a*c - b*b)/(3*a*a) 21 | let q = (2*b*b*b - 9*a*b*c + 27*a*a*d)/(27*a*a*a) 22 | let roots 23 | 24 | if (Math.abs(p) < 1e-8) { // p = 0 -> t^3 = -q -> t = -q^1/3 25 | roots = [cuberoot(-q)] 26 | } else if (Math.abs(q) < 1e-8) { // q = 0 -> t^3 + pt = 0 -> t(t^2+p)=0 27 | roots = [0].concat(p < 0 ? [Math.sqrt(-p), -Math.sqrt(-p)] : []) 28 | } else { 29 | let D = q*q/4 + p*p*p/27 30 | if (Math.abs(D) < 1e-8) { // D = 0 -> two roots 31 | roots = [-1.5*q/p, 3*q/p] 32 | } else if (D > 0) { // Only one real root 33 | let u = cuberoot(-q/2 - Math.sqrt(D)) 34 | roots = [u - p/(3*u)] 35 | } else { // D < 0, three roots, but needs to use complex numbers/trigonometric solution 36 | let u = 2*Math.sqrt(-p/3) 37 | let t = Math.acos(3*q/p/u)/3 // D < 0 implies p < 0 and acos argument in [-1..1] 38 | let k = 2*Math.PI/3 39 | roots = [u*Math.cos(t), u*Math.cos(t-k), u*Math.cos(t-2*k)] 40 | } 41 | } 42 | 43 | // Convert back from depressed cubic 44 | for (var i = 0; i < roots.length; i++) 45 | roots[i] -= b/(3*a) 46 | 47 | return roots 48 | } 49 | 50 | 51 | function cuberoot(x: number) { 52 | const y = Math.pow(Math.abs(x), 1/3) 53 | return x < 0 ? -y : y 54 | } -------------------------------------------------------------------------------- /src/lib/delay.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A "modern" sleep statement. 3 | * 4 | * @param ms The number of milliseconds to wait. 5 | */ 6 | export const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) 7 | -------------------------------------------------------------------------------- /src/lib/isValid.ts: -------------------------------------------------------------------------------- 1 | export default (a) => { 2 | return !( a && !isNaN(a)) 3 | } -------------------------------------------------------------------------------- /src/lib/keychain.ts: -------------------------------------------------------------------------------- 1 | import * as ReactNativeKeychain from "react-native-keychain" 2 | 3 | /** 4 | * Saves some credentials securely. 5 | * 6 | * @param username The username 7 | * @param password The password 8 | * @param server The server these creds are for. 9 | */ 10 | export async function save(username: string, password: string, server?: string) { 11 | if (server) { 12 | await ReactNativeKeychain.setInternetCredentials(server, username, password) 13 | return true 14 | } else { 15 | return ReactNativeKeychain.setGenericPassword(username, password) 16 | } 17 | } 18 | 19 | /** 20 | * Loads credentials that were already saved. 21 | * 22 | * @param server The server that these creds are for 23 | */ 24 | export async function load(server?: string) { 25 | if (server) { 26 | const creds = await ReactNativeKeychain.getInternetCredentials(server) 27 | return { 28 | username: creds.username, 29 | password: creds.password, 30 | server, 31 | } 32 | } else { 33 | const creds = await ReactNativeKeychain.getGenericPassword() 34 | if (typeof creds === "object") { 35 | return { 36 | username: creds.username, 37 | password: creds.password, 38 | server: null, 39 | } 40 | } else { 41 | return { 42 | username: null, 43 | password: null, 44 | server: null, 45 | } 46 | } 47 | } 48 | } 49 | 50 | /** 51 | * Resets any existing credentials for the given server. 52 | * 53 | * @param server The server which has these creds 54 | */ 55 | export async function reset(server?: string) { 56 | if (server) { 57 | await ReactNativeKeychain.resetInternetCredentials(server) 58 | return true 59 | } else { 60 | return await ReactNativeKeychain.resetGenericPassword() 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/lib/quadratic.ts: -------------------------------------------------------------------------------- 1 | import Toast from 'react-native-simple-toast' 2 | export default (a: number, b: number, c: number) => { 3 | const D = b * b - 4 * a * c 4 | const root = D >= 0 ? Math.sqrt(D): Math.sqrt(D*-1) 5 | const roots = [] 6 | 7 | if( a === 0 ) { // edge case 8 | if(b === 0){ 9 | Toast.showWithGravity('The input is not a quadratic equation.', Toast.SHORT, Toast.CENTER) 10 | } else { 11 | roots.push((-c/b)) 12 | } 13 | 14 | return roots 15 | } 16 | 17 | if( D < 0){ // complex roots 18 | roots.push(( -b )/ ( 2 * a) + "+" + (( root ) / ( 2 * a)).toFixed(2) + "i" ) 19 | roots.push(( -b )/ ( 2 * a) + "-" + (( root ) / ( 2 * a)).toFixed(2) + "i" ) 20 | } else { // two real roots 21 | roots.push((( -b + root ) / ( 2 * a)).toFixed(3)) 22 | roots.push((( -b - root ) / ( 2 * a)).toFixed(3)) 23 | } 24 | 25 | 26 | return roots 27 | } -------------------------------------------------------------------------------- /src/lib/storage/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./storage" 2 | -------------------------------------------------------------------------------- /src/lib/storage/storage.test.ts: -------------------------------------------------------------------------------- 1 | import { load, loadString, save, saveString, clear, remove } from "./storage" 2 | 3 | // fixtures 4 | const VALUE_OBJECT = { x: 1 } 5 | const VALUE_STRING = JSON.stringify(VALUE_OBJECT) 6 | 7 | // mocks 8 | const mockGetItem = jest.fn().mockReturnValue(Promise.resolve(VALUE_STRING)) 9 | const mockSetItem = jest.fn() 10 | const mockRemoveItem = jest.fn() 11 | const mockClear = jest.fn() 12 | 13 | // replace AsyncStorage 14 | jest.mock("AsyncStorage", () => ({ 15 | getItem: mockGetItem, 16 | setItem: mockSetItem, 17 | removeItem: mockRemoveItem, 18 | clear: mockClear, 19 | })) 20 | 21 | // reset mocks after each test 22 | afterEach(() => jest.clearAllMocks()) 23 | 24 | test("load", async () => { 25 | const value = await load("something") 26 | expect(value).toEqual(JSON.parse(VALUE_STRING)) 27 | }) 28 | 29 | test("loadString", async () => { 30 | const value = await loadString("something") 31 | expect(value).toEqual(VALUE_STRING) 32 | }) 33 | 34 | test("save", async () => { 35 | await save("something", VALUE_OBJECT) 36 | expect(mockSetItem).toHaveBeenCalledWith("something", VALUE_STRING) 37 | }) 38 | 39 | test("saveString", async () => { 40 | await saveString("something", VALUE_STRING) 41 | expect(mockSetItem).toHaveBeenCalledWith("something", VALUE_STRING) 42 | }) 43 | 44 | test("remove", async () => { 45 | await remove("something") 46 | expect(mockRemoveItem).toHaveBeenCalledWith("something") 47 | }) 48 | 49 | test("clear", async () => { 50 | await clear() 51 | expect(mockClear).toHaveBeenCalledWith() 52 | }) 53 | -------------------------------------------------------------------------------- /src/lib/storage/storage.ts: -------------------------------------------------------------------------------- 1 | import { AsyncStorage } from "react-native" 2 | 3 | /** 4 | * Loads a string from storage. 5 | * 6 | * @param key The key to fetch. 7 | */ 8 | export async function loadString(key: string): Promise { 9 | try { 10 | return await AsyncStorage.getItem(key) 11 | } catch { 12 | // not sure why this would fail... even reading the RN docs I'm unclear 13 | return null 14 | } 15 | } 16 | 17 | /** 18 | * Saves a string to storage. 19 | * 20 | * @param key The key to fetch. 21 | * @param value The value to store. 22 | */ 23 | export async function saveString(key: string, value: string): Promise { 24 | try { 25 | await AsyncStorage.setItem(key, value) 26 | return true 27 | } catch { 28 | return false 29 | } 30 | } 31 | 32 | /** 33 | * Loads something from storage and runs it thru JSON.parse. 34 | * 35 | * @param key The key to fetch. 36 | */ 37 | export async function load(key: string): Promise { 38 | try { 39 | const almostThere = await AsyncStorage.getItem(key) 40 | return JSON.parse(almostThere) 41 | } catch { 42 | return null 43 | } 44 | } 45 | 46 | /** 47 | * Saves an object to storage. 48 | * 49 | * @param key The key to fetch. 50 | * @param value The value to store. 51 | */ 52 | export async function save(key: string, value: any): Promise { 53 | try { 54 | if (typeof value === "object") { 55 | await AsyncStorage.setItem(key, JSON.stringify(value)) 56 | } else { 57 | await AsyncStorage.setItem(key, value) 58 | } 59 | return true 60 | } catch { 61 | return false 62 | } 63 | } 64 | 65 | /** 66 | * Removes something from storage. 67 | * 68 | * @param key The key to kill. 69 | */ 70 | export async function remove(key: string): Promise { 71 | try { 72 | await AsyncStorage.removeItem(key) 73 | } catch {} 74 | } 75 | 76 | /** 77 | * Burn it all to the ground. 78 | */ 79 | export async function clear(): Promise { 80 | try { 81 | await AsyncStorage.clear() 82 | } catch {} 83 | } 84 | -------------------------------------------------------------------------------- /src/lib/threeVariables.ts: -------------------------------------------------------------------------------- 1 | import Toast from 'react-native-simple-toast' 2 | export default (matrix: number[]) => { 3 | const roots = [] 4 | 5 | // replace the respective column 6 | const xMatrix = formMatrixColumn(matrix,0) 7 | const yMatrix = formMatrixColumn(matrix,1) 8 | const zMatrix = formMatrixColumn(matrix,2) 9 | 10 | const determinant = Determinant(matrix) 11 | const xdeterminant = Determinant(xMatrix) 12 | const ydeterminant = Determinant(yMatrix) 13 | const zdeterminant = Determinant(zMatrix) 14 | 15 | if( determinant == 0) { 16 | Toast.showWithGravity('There is no solution.', Toast.SHORT, Toast.CENTER) 17 | } else { 18 | roots.push(xdeterminant/determinant) 19 | roots.push(ydeterminant/determinant) 20 | roots.push(zdeterminant/determinant) 21 | } 22 | return roots 23 | } 24 | 25 | function Determinant(matrix: number[]) { 26 | return ( (matrix[0][0] * matrix[1][1] * matrix[2][2]) + (matrix[0][1] * matrix[1][2] * matrix[2][0]) + (matrix[0][2] * matrix[1][0] * matrix[2][1])) 27 | - ( (matrix[2][0] * matrix[1][1] * matrix[0][2]) + (matrix[2][1] * matrix[1][2] * matrix[0][0]) + (matrix[2][2] * matrix[1][0] * matrix[0][1])) 28 | } 29 | 30 | function formMatrixColumn(matrix: number[], index: number){ 31 | let clone = JSON.parse(JSON.stringify(matrix)) 32 | 33 | clone.forEach(item => { 34 | item[index] = item[3] 35 | }) 36 | 37 | console.log(clone) 38 | 39 | 40 | return clone 41 | } -------------------------------------------------------------------------------- /src/lib/twoVariables.ts: -------------------------------------------------------------------------------- 1 | import Toast from 'react-native-simple-toast' 2 | export default (x1: number, y1: number, z1: number, x2: number, y2: number, z2: number) => { 3 | const roots = [] 4 | 5 | const determinant = ( x1 * y2) - ( x2 * y1) 6 | const determinantXMatrix = ( z1 * y2) - ( z2 * y1) 7 | const determinantYMatrix = ( x1 * z2) - ( x2 * z1) 8 | 9 | if(determinant == 0){ 10 | Toast.showWithGravity('There is no solution.', Toast.SHORT, Toast.CENTER) 11 | } else { 12 | roots.push(determinantXMatrix/determinant) 13 | roots.push(determinantYMatrix/determinant) 14 | } 15 | return roots 16 | } -------------------------------------------------------------------------------- /src/lib/validate.ts: -------------------------------------------------------------------------------- 1 | const ValidateJS = require("validate.js") 2 | import { contains } from "ramda" 3 | 4 | // HACK(steve): wierd typescript situation because of strange typings 5 | const Validate: any = ValidateJS.default ? ValidateJS.default : ValidateJS 6 | 7 | /** 8 | * Validates that 1 attribute doesn't appear in another's attributes content. 9 | */ 10 | Validate.validators.excludes = function custom(value, options, key, attributes) { 11 | const list = attributes[options.attribute] || [] 12 | if (value && contains(value, list)) { 13 | return options.message || `${value} is in the list` 14 | } 15 | } 16 | 17 | /** 18 | * Validates that another attribute isn't true. 19 | */ 20 | Validate.validators.tripped = function custom(value, options, key, attributes) { 21 | if (value && attributes[options.attribute] === true) { 22 | return options.message || `${options.attribute} is true` 23 | } 24 | } 25 | 26 | /** 27 | * Defines the rules for validating. 28 | * 29 | * Example: 30 | * ```ts 31 | * const RULES = { 32 | * favoriteBand: { 33 | * inclusion: { ['Weezer', 'Other'], message: 'Pick wisely.' } 34 | * }, 35 | * name: { 36 | * presence: { message: 'A developer has no name?' } 37 | * } 38 | * } 39 | * validate(RULES, {}) 40 | * ``` 41 | * 42 | * See https://validatejs.org/#validators for more examples. 43 | * 44 | */ 45 | export interface ValidationRules { 46 | [key: string]: {} 47 | } 48 | 49 | /** 50 | * An object containing any errors found. 51 | * 52 | * Example: 53 | * ```js 54 | * { 55 | * email: ['Invalid email address.'], 56 | * password: [ 57 | * 'Password must be 6 characters.', 58 | * 'Password must have at least 1 digit.' 59 | * ] 60 | * } 61 | * ``` 62 | */ 63 | export interface ValidationErrors { 64 | [key: string]: {} 65 | } 66 | 67 | /** 68 | * Runs the given rules against the data object. 69 | * 70 | * @param rules The rules to apply. 71 | * @param data The object to validate. 72 | */ 73 | export function validate(rules: ValidationRules, data: {}): ValidationErrors { 74 | if (typeof data !== "object") { 75 | return {} 76 | } 77 | return Validate(data, rules, { fullMessages: false }) || {} 78 | } 79 | -------------------------------------------------------------------------------- /src/navigation/back-button-handler.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { BackHandler } from "react-native" 3 | import { inject, observer } from "mobx-react" 4 | import { NavigationActions } from "react-navigation" 5 | import { NavigationStore } from "../navigation/navigation-store" 6 | 7 | interface BackButtonHandlerProps { 8 | navigationStore?: NavigationStore 9 | /** 10 | * Are we allowed to exit? 11 | */ 12 | canExit(routeName: string): Boolean 13 | } 14 | 15 | @inject("navigationStore") 16 | @observer 17 | export class BackButtonHandler extends React.Component { 18 | /** 19 | * Subscribe when we come to life. 20 | */ 21 | componentDidMount() { 22 | BackHandler.addEventListener("hardwareBackPress", this.onBackPress) 23 | } 24 | 25 | /** 26 | * Unsubscribe when we're done. 27 | */ 28 | componentWillUnmount() { 29 | BackHandler.removeEventListener("hardwareBackPress", this.onBackPress) 30 | } 31 | 32 | /** 33 | * Fires when the back button is pressed on android. 34 | */ 35 | onBackPress = () => { 36 | // grab the current route 37 | const routeName = this.props.navigationStore.findCurrentRoute().routeName 38 | 39 | // are we allowed to exit? 40 | if (this.props.canExit(routeName)) { 41 | // let the system know we've not handled this event 42 | return false 43 | } else { 44 | // we can't exit, so let's turn this into a back action 45 | this.props.navigationStore.dispatch(NavigationActions.back()) 46 | // let the system know we've handled this event 47 | return true 48 | } 49 | } 50 | 51 | /** 52 | * Renders the children or nothing if they weren't passed. 53 | */ 54 | render() { 55 | return this.props.children 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/navigation/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./stateful-navigator" 2 | -------------------------------------------------------------------------------- /src/navigation/navigation-config.ts: -------------------------------------------------------------------------------- 1 | export interface NavigationConfig { 2 | /** 3 | * A list of routes from which we're allowed to leave the app when 4 | * the user presses the back button on Android. 5 | * 6 | * Anything not on this list will be a standard `back` action in 7 | * react-navigation. 8 | */ 9 | exitRoutes: string[] 10 | } 11 | 12 | /** 13 | * The default navigation config for this app. You'd only really need 14 | * to override this for testing. 15 | */ 16 | export const DEFAULT_NAVIGATION_CONFIG: NavigationConfig = { 17 | exitRoutes: ["firstExample"], 18 | } 19 | -------------------------------------------------------------------------------- /src/navigation/navigation-events.ts: -------------------------------------------------------------------------------- 1 | import { types } from "mobx-state-tree" 2 | import { EventType, NavigationEventCallback } from "react-navigation" 3 | 4 | /** 5 | * This mobx-state-tree model bestows a few events for working with `react-navigation` 6 | * events. 7 | * 8 | * You use can `compose` or build directly off this to mixin these features. 9 | */ 10 | export const NavigationEvents = types.model("NavigationEvents").volatile(self => { 11 | // who is currently subscribed to react-navigation events 12 | const subs = new Set() 13 | 14 | /** 15 | * Fires after we change our state. You call this from the dispatch 16 | * to ensure any subscribers are told about state changes. 17 | * 18 | * @param action The react-navigation action which triggered this update. 19 | * @param oldState The previous navigation state. 20 | * @param newState The next navigation state. 21 | */ 22 | const fireSubscribers = (action: any, oldState: any, newState: any) => { 23 | // tell each subscriber out this 24 | subs.forEach(subscriber => { 25 | subscriber({ 26 | type: "action", 27 | action, 28 | state: newState, 29 | lastState: oldState, 30 | }) 31 | }) 32 | } 33 | 34 | /** 35 | * Provides a way from screens (for example) to subscribe to `react-navigation` 36 | * events. 37 | * 38 | * @param eventName The event. 39 | * @param handler Some strange handler 40 | */ 41 | const addListener = (eventName: EventType, handler: NavigationEventCallback) => { 42 | if (eventName !== "action") { 43 | return { remove: () => {} } 44 | } 45 | 46 | // subscribe 47 | subs.add(handler) 48 | 49 | // return the instructions on how to unsubscribe 50 | return { 51 | remove: () => subs.delete(handler), 52 | } 53 | } 54 | 55 | return { addListener, fireSubscribers } 56 | }) 57 | -------------------------------------------------------------------------------- /src/navigation/navigation-store.ts: -------------------------------------------------------------------------------- 1 | import { types } from "mobx-state-tree" 2 | import { RootNavigator } from "./root-navigator" 3 | import { NavigationActions, NavigationAction } from "react-navigation" 4 | import { NavigationEvents } from "./navigation-events" 5 | 6 | const DEFAULT_STATE = RootNavigator.router.getStateForAction(NavigationActions.init(), null) 7 | 8 | /** 9 | * Finds the current route. 10 | * 11 | * @param navState the current nav state 12 | */ 13 | function findCurrentRoute(navState) { 14 | const route = navState.routes[navState.index] 15 | if (route.routes) { 16 | return findCurrentRoute(route) 17 | } 18 | return route 19 | } 20 | 21 | /** 22 | * Tracks the navigation state for `react-navigation` as well as providers 23 | * the actions for changing that state. 24 | */ 25 | export const NavigationStoreModel = NavigationEvents.named("NavigationStore") 26 | .props({ 27 | /** 28 | * the navigation state tree (Frozen here means it is immutable.) 29 | */ 30 | state: types.optional(types.frozen, DEFAULT_STATE), 31 | }) 32 | .actions(self => ({ 33 | /** 34 | * Fires when navigation happens. 35 | * 36 | * Our job is to update the state for this new navigation action. 37 | * 38 | * @param action The new navigation action to perform 39 | * @param shouldPush Should we push or replace the whole stack? 40 | */ 41 | dispatch(action: NavigationAction, shouldPush: boolean = true) { 42 | const previousNavState = shouldPush ? self.state : null 43 | self.state = RootNavigator.router.getStateForAction(action, previousNavState) || self.state 44 | self.fireSubscribers(action, previousNavState, self.state) 45 | return true 46 | }, 47 | 48 | /** 49 | * Resets the navigation back to the start. 50 | */ 51 | reset() { 52 | self.state = DEFAULT_STATE 53 | }, 54 | 55 | /** 56 | * Finds the current route. 57 | */ 58 | findCurrentRoute() { 59 | return findCurrentRoute(self.state) 60 | }, 61 | })) 62 | .actions(self => ({ 63 | /** 64 | * Navigate to another place. 65 | * 66 | * @param routeName The route name. 67 | */ 68 | navigateTo (routeName: string) { 69 | self.dispatch(NavigationActions.navigate({ routeName })) 70 | }, 71 | })) 72 | 73 | export type NavigationStore = typeof NavigationStoreModel.Type 74 | -------------------------------------------------------------------------------- /src/navigation/root-navigator.ts: -------------------------------------------------------------------------------- 1 | import { createStackNavigator } from "react-navigation" 2 | import { Home } from "../views/screens/home/home-screen" 3 | import { ThreeLinearEquation } from "../views/screens/three-linear-equation/three-linear-equation-screen" 4 | import { TwoLinearEquation } from "../views/screens/two-linear-equation/two-linear-equation-screen" 5 | import { CubicEquation } from "../views/screens/cubic-equation/cubic-equation-screen" 6 | import { QuadraticEquation } from "../views/screens/quadratic-equation/quadratic-equation-screen" 7 | import { LinearEquation } from "../views/screens/linear-equation/linear-equation-screen" 8 | 9 | export const RootNavigator = createStackNavigator( 10 | { 11 | home: { screen: Home }, 12 | threeLinearEquation: { screen: ThreeLinearEquation }, 13 | twoLinearEquation: { screen: TwoLinearEquation }, 14 | cubicEquation: { screen: CubicEquation }, 15 | quadraticEquation: { screen: QuadraticEquation }, 16 | linearEquation: { screen: LinearEquation }, 17 | }, 18 | { 19 | headerMode: "none", 20 | navigationOptions: { gesturesEnabled: false }, 21 | }, 22 | ) 23 | -------------------------------------------------------------------------------- /src/navigation/stateful-navigator.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { inject, observer } from "mobx-react" 3 | import { RootNavigator } from "./root-navigator" 4 | import { NavigationStore } from "../navigation/navigation-store" 5 | 6 | interface StatefulNavigatorProps { 7 | navigationStore?: NavigationStore 8 | } 9 | 10 | @inject("navigationStore") 11 | @observer 12 | export class StatefulNavigator extends React.Component { 13 | render() { 14 | // grab our state & dispatch from our navigation store 15 | const { state, dispatch, addListener } = this.props.navigationStore 16 | 17 | // create a custom navigation implementation 18 | const navigation = { 19 | dispatch, 20 | state, 21 | addListener, 22 | } 23 | 24 | return 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/services/api/api-config.ts: -------------------------------------------------------------------------------- 1 | import * as env from "../../app/environment-variables" 2 | 3 | /** 4 | * The options used to configure the API. 5 | */ 6 | export interface ApiConfig { 7 | /** 8 | * The URL of the api. 9 | */ 10 | url: string 11 | 12 | /** 13 | * Milliseconds before we timeout the request. 14 | */ 15 | timeout: number 16 | } 17 | 18 | /** 19 | * The default configuration for the app. 20 | */ 21 | export const DEFAULT_API_CONFIG: ApiConfig = { 22 | url: env.API || "https://api.github.com", 23 | timeout: 10000, 24 | } 25 | -------------------------------------------------------------------------------- /src/services/api/api-problem.ts: -------------------------------------------------------------------------------- 1 | import { ApiResponse } from "apisauce" 2 | 3 | export type GeneralApiProblem = 4 | /** 5 | * Times up. 6 | */ 7 | | { kind: "timeout"; temporary: true } 8 | /** 9 | * Cannot connect to the server for some reason. 10 | */ 11 | | { kind: "cannot-connect"; temporary: true } 12 | /** 13 | * The server experienced a problem. Any 5xx error. 14 | */ 15 | | { kind: "server" } 16 | /** 17 | * We're not allowed because we haven't identified ourself. This is 401. 18 | */ 19 | | { kind: "unauthorized" } 20 | /** 21 | * We don't have access to perform that request. This is 403. 22 | */ 23 | | { kind: "forbidden" } 24 | /** 25 | * Unable to find that resource. This is a 404. 26 | */ 27 | | { kind: "not-found" } 28 | /** 29 | * All other 4xx series errors. 30 | */ 31 | | { kind: "rejected" } 32 | /** 33 | * Something truly unexpected happened. Most likely can try again. This is a catch all. 34 | */ 35 | | { kind: "unknown"; temporary: true } 36 | /** 37 | * The data we received is not in the expected format. 38 | */ 39 | | { kind: "bad-data" } 40 | 41 | /** 42 | * Attempts to get a common cause of problems from an api response. 43 | * 44 | * @param response The api response. 45 | */ 46 | export function getGeneralApiProblem(response: ApiResponse): GeneralApiProblem | void { 47 | switch (response.problem) { 48 | case "CONNECTION_ERROR": 49 | return { kind: "cannot-connect", temporary: true } 50 | case "NETWORK_ERROR": 51 | return { kind: "cannot-connect", temporary: true } 52 | case "TIMEOUT_ERROR": 53 | return { kind: "timeout", temporary: true } 54 | case "SERVER_ERROR": 55 | return { kind: "server" } 56 | case "UNKNOWN_ERROR": 57 | return { kind: "unknown", temporary: true } 58 | case "CLIENT_ERROR": 59 | switch (response.status) { 60 | case 401: 61 | return { kind: "unauthorized" } 62 | case 403: 63 | return { kind: "forbidden" } 64 | default: 65 | return { kind: "rejected" } 66 | } 67 | case "CANCEL_ERROR": 68 | return null 69 | } 70 | 71 | return null 72 | } 73 | -------------------------------------------------------------------------------- /src/services/api/api.ts: -------------------------------------------------------------------------------- 1 | import { ApisauceInstance, create, ApiResponse } from "apisauce" 2 | import { getGeneralApiProblem } from "./api-problem" 3 | import { ApiConfig, DEFAULT_API_CONFIG } from "./api-config" 4 | import * as Types from "./api.types" 5 | 6 | /** 7 | * Manages all requests to the API. 8 | */ 9 | export class Api { 10 | /** 11 | * The underlying apisauce instance which performs the requests. 12 | */ 13 | apisauce: ApisauceInstance 14 | 15 | /** 16 | * Configurable options. 17 | */ 18 | config: ApiConfig 19 | 20 | /** 21 | * Creates the api. 22 | * 23 | * @param config The configuration to use. 24 | */ 25 | constructor(config: ApiConfig = DEFAULT_API_CONFIG) { 26 | this.config = config 27 | } 28 | 29 | /** 30 | * Sets up the API. This will be called during the bootup 31 | * sequence and will happen before the first React component 32 | * is mounted. 33 | * 34 | * Be as quick as possible in here. 35 | */ 36 | setup() { 37 | // construct the apisauce instance 38 | this.apisauce = create({ 39 | baseURL: this.config.url, 40 | timeout: this.config.timeout, 41 | headers: { 42 | Accept: "application/vnd.github.v3+json", 43 | }, 44 | }) 45 | } 46 | 47 | /** 48 | * Gets a list of repos. 49 | */ 50 | async getRepo(repo: string): Promise { 51 | // make the api call 52 | const response: ApiResponse = await this.apisauce.get(`/repos/${repo}`) 53 | 54 | // the typical ways to die when calling an api 55 | if (!response.ok) { 56 | const problem = getGeneralApiProblem(response) 57 | if (problem) return problem 58 | } 59 | 60 | // transform the data into the format we are expecting 61 | try { 62 | const resultRepo: Types.Repo = { 63 | id: response.data.id, 64 | name: response.data.name, 65 | owner: response.data.owner.login, 66 | } 67 | return { kind: "ok", repo: resultRepo } 68 | } catch { 69 | return { kind: "bad-data" } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/services/api/api.types.ts: -------------------------------------------------------------------------------- 1 | import { GeneralApiProblem } from "./api-problem" 2 | 3 | export interface Repo { 4 | id: number 5 | name: string 6 | owner: string 7 | } 8 | 9 | export type GetRepoResult = { kind: "ok"; repo: Repo } | GeneralApiProblem 10 | -------------------------------------------------------------------------------- /src/services/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./api" 2 | export * from "./api.types" 3 | -------------------------------------------------------------------------------- /src/services/reactotron/command-middleware.ts: -------------------------------------------------------------------------------- 1 | import { clear } from "../../lib/storage" 2 | import { RootStore } from "../../app/root-store" 3 | 4 | export type GetRootStore = () => RootStore 5 | 6 | export const commandMiddleware = (getRootStore: GetRootStore) => { 7 | return tron => { 8 | return { 9 | onCommand: async command => { 10 | if (command.type !== "custom") return 11 | switch (command.payload) { 12 | case "resetStore": 13 | console.tron.log("resetting store") 14 | clear() 15 | break 16 | case "resetNavigation": 17 | console.tron.log("resetting navigation store") 18 | getRootStore().navigationStore.reset() 19 | break 20 | } 21 | }, 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/services/reactotron/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./reactotron" 2 | -------------------------------------------------------------------------------- /src/services/reactotron/reactotron-config.ts: -------------------------------------------------------------------------------- 1 | export interface ReactotronConfig { 2 | /** The name of the app. */ 3 | name?: string 4 | /** The host to connect to: default 'localhost'. */ 5 | host?: string 6 | /** Should we use async storage */ 7 | useAsyncStorage?: boolean 8 | /** Should we clear Reactotron when load? */ 9 | clearOnLoad?: boolean 10 | /** Root state logging. */ 11 | state?: { 12 | /** log the initial data that we put into the state on startup? */ 13 | initial?: boolean 14 | /** log snapshot changes. */ 15 | snapshots?: boolean, 16 | } 17 | } 18 | 19 | /** 20 | * The default Reactotron configuration. 21 | */ 22 | export const DEFAULT_REACTOTRON_CONFIG: ReactotronConfig = { 23 | clearOnLoad: true, 24 | host: "localhost", 25 | useAsyncStorage: true, 26 | state: { 27 | initial: true, 28 | snapshots: false, 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /src/services/reactotron/reactotron.ts: -------------------------------------------------------------------------------- 1 | import Tron from "reactotron-react-native" 2 | import { RootStore } from "../../app/root-store" 3 | import { onSnapshot } from "mobx-state-tree" 4 | import { ReactotronConfig, DEFAULT_REACTOTRON_CONFIG } from "./reactotron-config" 5 | import { mst } from "reactotron-mst" 6 | import { commandMiddleware } from "./command-middleware" 7 | 8 | // Teach TypeScript about the bad things we want to do. 9 | declare global { 10 | interface Console { 11 | /** 12 | * Hey, it's Reactotron if we're in dev, and no-ops if we're in prod. 13 | */ 14 | tron: typeof Tron 15 | } 16 | } 17 | 18 | /** Do Nothing. */ 19 | const noop = () => undefined 20 | 21 | // in dev, we attach Reactotron, in prod we attach a interface-compatible mock. 22 | if (__DEV__) { 23 | console.tron = Tron // attach reactotron to `console.tron` 24 | } else { 25 | // attach a mock so if things sneaky by our __DEV__ guards, we won't crash. 26 | console.tron = { 27 | configure: noop, 28 | connect: noop, 29 | use: noop, 30 | useReactNative: noop, 31 | clear: noop, 32 | log: noop, 33 | logImportant: noop, 34 | display: noop, 35 | error: noop, 36 | image: noop, 37 | reportError: noop, 38 | } 39 | } 40 | 41 | /** 42 | * You'll probably never use the service like this since we hang the Reactotron 43 | * instance off of `console.tron`. This is only to be consistent with the other 44 | * services. 45 | */ 46 | export class Reactotron { 47 | config: ReactotronConfig 48 | rootStore: any 49 | 50 | /** 51 | * Create the Reactotron service. 52 | * 53 | * @param config the configuration 54 | */ 55 | constructor(config: ReactotronConfig = DEFAULT_REACTOTRON_CONFIG) { 56 | // merge the passed in config with some defaults 57 | this.config = { 58 | host: "localhost", 59 | useAsyncStorage: true, 60 | clearOnLoad: true, 61 | ...config, 62 | state: { 63 | initial: false, 64 | snapshots: false, 65 | ...(config && config.state), 66 | }, 67 | } 68 | } 69 | 70 | /** 71 | * Hook into the root store for doing awesome state-related things. 72 | * 73 | * @param rootStore The root store 74 | */ 75 | setRootStore(rootStore: any, initialData: any) { 76 | if (__DEV__) { 77 | rootStore = rootStore as RootStore // typescript hack 78 | this.rootStore = rootStore 79 | 80 | const { initial, snapshots } = this.config.state 81 | const name = "ROOT STORE" 82 | 83 | // logging features 84 | if (initial) { 85 | console.tron.display({ name, value: initialData, preview: "Initial State" }) 86 | } 87 | // log state changes? 88 | if (snapshots) { 89 | onSnapshot(rootStore, snapshot => { 90 | console.tron.display({ name, value: snapshot, preview: "New State" }) 91 | }) 92 | } 93 | 94 | // @ts-ignore 95 | console.tron.trackMstNode(rootStore) 96 | } 97 | } 98 | 99 | /** 100 | * Configure reactotron based on the the config settings passed in, then connect if we need to. 101 | */ 102 | async setup() { 103 | // only run this in dev... metro bundler will ignore this block: 🎉 104 | if (__DEV__) { 105 | // configure reactotron 106 | Tron.configure({ 107 | name: this.config.name || require("../../../package.json").name, 108 | host: this.config.host, 109 | }) 110 | 111 | // hookup middleware 112 | Tron.useReactNative({ 113 | asyncStorage: this.config.useAsyncStorage ? undefined : false, 114 | }) 115 | 116 | // ignore some chatty `mobx-state-tree` actions 117 | const RX = /postProcessSnapshot|@APPLY_SNAPSHOT/ 118 | 119 | // hookup mobx-state-tree middleware 120 | Tron.use( 121 | mst({ 122 | filter: event => RX.test(event.name) === false, 123 | }), 124 | ) 125 | 126 | // hookup custom command middleware 127 | Tron.use(commandMiddleware(() => this.rootStore)) 128 | 129 | // connect to the app 130 | Tron.connect() 131 | 132 | // clear if we should 133 | if (this.config.clearOnLoad) { 134 | Tron.clear() 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/theme/color.ts: -------------------------------------------------------------------------------- 1 | import { palette } from "./palette" 2 | 3 | /** 4 | * Roles for colors. Prefer using these over the palette. It makes it easier 5 | * to change things. 6 | * 7 | * The only roles we need to place in here are the ones that span through the app. 8 | * 9 | * If you have a specific use-case, like a spinner color. It makes more sense to 10 | * put that in the component. 11 | */ 12 | export const color = { 13 | /** 14 | * The palette is available to use, but prefer using the name. 15 | */ 16 | palette, 17 | /** 18 | * A helper for making something see-thru. Use sparingly as many layers of transparency 19 | * can cause older Android devices to slow down due to the excessive compositing required 20 | * by their under-powered GPUs. 21 | */ 22 | transparent: "rgba(0, 0, 0, 0)", 23 | /** 24 | * The screen background. 25 | */ 26 | background: palette.white, 27 | /** 28 | * The main tinting color. 29 | */ 30 | primary: palette.orange, 31 | /** 32 | * The main tinting color, but darker. 33 | */ 34 | primaryDarker: palette.orangeDarker, 35 | /** 36 | * A subtle color used for borders and lines. 37 | */ 38 | line: palette.offWhite, 39 | /** 40 | * The default color of text in many components. 41 | */ 42 | text: palette.white, 43 | /** 44 | * Secondary information. 45 | */ 46 | dim: palette.lightGrey, 47 | /** 48 | * Error messages and icons. 49 | */ 50 | error: palette.angry, 51 | } 52 | -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-Black.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-BlackItalic.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-BoldItalic.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-ExtraBold.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-ExtraBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-ExtraBoldItalic.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-ExtraLight.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-Italic.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-Light.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-LightItalic.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-Medium.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-MediumItalic.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-Regular.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-SemiBold.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-Thin.ttf -------------------------------------------------------------------------------- /src/theme/fonts/Montserrat-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/theme/fonts/Montserrat-ThinItalic.ttf -------------------------------------------------------------------------------- /src/theme/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./color" 2 | export * from "./spacing" 3 | export * from "./typography" 4 | export * from "./timing" 5 | -------------------------------------------------------------------------------- /src/theme/palette.ts: -------------------------------------------------------------------------------- 1 | export const palette = { 2 | black: "#1d1d1d", 3 | white: "#ffffff", 4 | offWhite: "#e6e6e6", 5 | orange: "#FBA928", 6 | orangeDarker: "#EB9918", 7 | lightGrey: "#939AA4", 8 | lighterGrey: "#CDD4DA", 9 | angry: "#dd3333", 10 | } 11 | -------------------------------------------------------------------------------- /src/theme/spacing.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * NOTE TO DEVS: 3 | * 4 | * Spacing should consistent and whitespace thought of as a first class technique up 5 | * there with color and typefaces. 6 | * 7 | * Which type of scale you use is based on the design. 8 | * 9 | * If you've got simpler app, you may only need 6 items. Or maybe you want a spacing scale 10 | * to be named: 11 | * 12 | * export const spacing = { 13 | * tiny: 4, 14 | * small: 8, 15 | * medium: 12, 16 | * large: 24, 17 | * huge: 64 18 | * } 19 | * 20 | * Whatever you choose, try to stick with these, and not freestyle it everywhere. 21 | * 22 | * Feel free to delete this block. 23 | */ 24 | 25 | /** 26 | * The available spacing. 27 | * 28 | * Here's the rough guideline. Customize this for you usage. It's ok to put exceptions 29 | * within the components themselves if they are truly exceptions. 30 | * 31 | * 0 = none - nothing. only here to bust out of a zero-based array. 32 | * 1 = tiny - elements contextually close to each other 33 | * 2 = smaller - for groups of closely related items or perhaps borders 34 | * 3 = small - ? 35 | * 4 = medium - ? 36 | * 5 = medium+ - ? 37 | * 6 = large - between groups of content that aren't related? 38 | * 7 = huge - ? 39 | * 8 = massive - an uncomfortable amount of whitespace 40 | */ 41 | export const spacing = [0, 4, 8, 12, 16, 24, 32, 48, 64] 42 | -------------------------------------------------------------------------------- /src/theme/timing.ts: -------------------------------------------------------------------------------- 1 | export const timing = { 2 | /** 3 | * The duration (ms) for quick animations. 4 | */ 5 | quick: 300, 6 | } 7 | -------------------------------------------------------------------------------- /src/theme/typography.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from "react-native" 2 | 3 | /** 4 | * Just the font names. 5 | * 6 | * The various styles of fonts are defined in the component. 7 | */ 8 | export const typography = { 9 | /** 10 | * The primary font. Used in most places. 11 | */ 12 | primary: Platform.select({ ios: "Montserrat", android: "Montserrat" }), 13 | 14 | /** 15 | * An alternate font used for perhaps titles and stuff. 16 | */ 17 | secondary: Platform.select({ ios: "Montserrat", android: "Montserrat" }), 18 | } 19 | -------------------------------------------------------------------------------- /src/views/screens/cubic-equation/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./cubic-equation-screen" 2 | -------------------------------------------------------------------------------- /src/views/screens/home/home-screen.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { ViewStyle , TextStyle, View } from "react-native" 3 | import { color } from "../../../theme" 4 | import { Header } from '../../shared/header' 5 | import { Text } from "../../shared/text" 6 | import { Button } from '../../shared/button' 7 | import { NavigationScreenProps } from "react-navigation" 8 | 9 | export interface HomeScreenProps extends NavigationScreenProps<{}> { 10 | } 11 | 12 | const ROOT: ViewStyle = { 13 | backgroundColor: color.palette.black, 14 | flex: 1 15 | } 16 | 17 | const FirstView: ViewStyle = { 18 | flex: .6, 19 | marginLeft: 20, 20 | marginTop: 20 21 | } 22 | 23 | const SecondView: ViewStyle = { 24 | flex: .4, 25 | marginLeft: 20, 26 | } 27 | 28 | const TextStyle: TextStyle = { 29 | fontSize: 20 30 | } 31 | const HeaderStyle: ViewStyle = { 32 | backgroundColor: color.primaryDarker, 33 | } 34 | 35 | const ButtonStyle: ViewStyle = { 36 | marginTop: 20, 37 | marginLeft: 10 38 | } 39 | 40 | export class Home extends React.Component { 41 | 42 | navigate = screen => { 43 | const { navigate } = this.props.navigation 44 | screen && navigate(screen) 45 | } 46 | 47 | render () { 48 | return ( 49 | 50 |
51 | 52 | 53 | 48 | ) : ( 49 | 50 | )} 51 | 52 | 53 | 54 | {rightIcon ? ( 55 | 58 | ) : ( 59 | 60 | )} 61 | 62 | ) 63 | } 64 | } -------------------------------------------------------------------------------- /src/views/shared/header/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./header" -------------------------------------------------------------------------------- /src/views/shared/icon/icon.props.ts: -------------------------------------------------------------------------------- 1 | import { ImageStyle, ViewStyle } from "react-native" 2 | import { IconTypes } from "./icons" 3 | 4 | export interface IconProps { 5 | /** 6 | * Style overrides for the icon image 7 | */ 8 | style?: ImageStyle 9 | 10 | /** 11 | * Style overrides for the icon container 12 | */ 13 | containerStyle?: ViewStyle 14 | 15 | /** 16 | * The name of the icon 17 | */ 18 | icon?: IconTypes 19 | } -------------------------------------------------------------------------------- /src/views/shared/icon/icon.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { storiesOf } from "@storybook/react-native" 3 | import { StoryScreen, Story, UseCase } from "../../../../storybook/views" 4 | import { Icon } from "./icon" 5 | 6 | storiesOf("Icon", module) 7 | .addDecorator(fn => {fn()}) 8 | .add("Names", () => ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | )) 18 | -------------------------------------------------------------------------------- /src/views/shared/icon/icon.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { View, Image, ImageStyle } from "react-native" 3 | import { IconProps } from "./icon.props" 4 | import { icons } from "./icons" 5 | 6 | const ROOT: ImageStyle = { 7 | resizeMode: "contain", 8 | } 9 | 10 | export function Icon(props: IconProps) { 11 | const { style: styleOverride, icon, containerStyle } = props 12 | const style: ImageStyle = { ...ROOT, ...styleOverride} 13 | 14 | return ( 15 | 16 | 17 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /src/views/shared/icon/icons/arrow-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/views/shared/icon/icons/arrow-left.png -------------------------------------------------------------------------------- /src/views/shared/icon/icons/arrow-left@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/views/shared/icon/icons/arrow-left@2x.png -------------------------------------------------------------------------------- /src/views/shared/icon/icons/bullet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/views/shared/icon/icons/bullet.png -------------------------------------------------------------------------------- /src/views/shared/icon/icons/bullet@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/views/shared/icon/icons/bullet@2x.png -------------------------------------------------------------------------------- /src/views/shared/icon/icons/index.ts: -------------------------------------------------------------------------------- 1 | export const icons = { 2 | back: require("./arrow-left.png"), 3 | bullet: require("./bullet.png"), 4 | } 5 | 6 | export type IconTypes = keyof typeof icons -------------------------------------------------------------------------------- /src/views/shared/icon/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./icon" 2 | export * from "./icons" 3 | -------------------------------------------------------------------------------- /src/views/shared/screen/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./screen" 2 | -------------------------------------------------------------------------------- /src/views/shared/screen/screen.presets.ts: -------------------------------------------------------------------------------- 1 | import { ViewStyle, ScrollViewStyle } from "react-native" 2 | import { color } from "../../../theme" 3 | import { isEmpty, isNil } from "ramda" 4 | 5 | /** 6 | * The base shape & color. 7 | */ 8 | const SHAPE: ScrollViewStyle = { backgroundColor: color.background, flex: 1 } 9 | 10 | /** 11 | * Governs the default child layout. 12 | */ 13 | const CONTENTS: ViewStyle = { justifyContent: "flex-start", alignItems: "flex-start" } 14 | 15 | /** 16 | * Glues the shape & child layout together since there's no restrictions on view style. 17 | */ 18 | const DOES_NOT_SCROLL: ViewStyle = { ...SHAPE, ...CONTENTS } 19 | 20 | // a style-safe value when a preset's sub-style isn't defined 21 | const NOPE = {} 22 | 23 | /** 24 | * All the variations of screens. 25 | */ 26 | export const presets = { 27 | /** 28 | * No scrolling. Suitable for full-screen carousels and components 29 | * which have built-in scrolling like FlatList. 30 | */ 31 | fixed: { 32 | nonScroll: DOES_NOT_SCROLL, 33 | scrollOuter: NOPE, 34 | scrollInner: NOPE, 35 | }, 36 | 37 | /** 38 | * No scrolling. Children are stretched to full width. 39 | */ 40 | fixedStack: { 41 | nonScroll: { ...DOES_NOT_SCROLL, alignItems: "stretch" } as ViewStyle, 42 | scrollOuter: NOPE, 43 | scrollInner: NOPE, 44 | }, 45 | 46 | /** 47 | * No scrolling. Content is centered on the screen. 48 | */ 49 | fixedCenter: { 50 | nonScroll: { ...DOES_NOT_SCROLL, justifyContent: "center", alignItems: "center" } as ViewStyle, 51 | scrollOuter: NOPE, 52 | scrollInner: NOPE, 53 | }, 54 | 55 | /** 56 | * Scrolls. Suitable for forms or other things requiring a keyboard. 57 | * 58 | * Pick this one if you don't know which one you want yet. 59 | */ 60 | scroll: { 61 | nonScroll: NOPE, 62 | scrollOuter: SHAPE, 63 | scrollInner: { ...CONTENTS } as ViewStyle, 64 | }, 65 | 66 | /** 67 | * Like scroll, but children are stretched to full width. 68 | */ 69 | scrollStack: { 70 | nonScroll: NOPE, 71 | scrollOuter: SHAPE, 72 | scrollInner: { ...CONTENTS, alignItems: "stretch" } as ViewStyle, 73 | }, 74 | } 75 | 76 | /** 77 | * The variations of screens. 78 | */ 79 | export type ScreenPresets = keyof typeof presets 80 | 81 | /** 82 | * Is this preset a non-scrolling one? 83 | * 84 | * @param preset The preset to check 85 | */ 86 | export function isNonScrolling(preset: ScreenPresets) { 87 | // any of these things will make you scroll 88 | return !( 89 | isNil(preset) || 90 | isEmpty(preset) || 91 | isNil(presets[preset]) || 92 | presets[preset].nonScroll === NOPE 93 | ) 94 | } 95 | -------------------------------------------------------------------------------- /src/views/shared/screen/screen.props.ts: -------------------------------------------------------------------------------- 1 | import { ViewStyle } from "react-native" 2 | import { ScreenPresets } from "./screen.presets" 3 | 4 | export interface ScreenProps { 5 | /** 6 | * Children components. 7 | */ 8 | children?: React.ReactNode 9 | 10 | /** 11 | * An optional style override useful for padding & margin. 12 | */ 13 | style?: ViewStyle 14 | 15 | /** 16 | * One of the different types of presets. 17 | */ 18 | preset?: ScreenPresets 19 | 20 | /** 21 | * An optional background color 22 | */ 23 | backgroundColor?: string 24 | } 25 | -------------------------------------------------------------------------------- /src/views/shared/screen/screen.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { ScrollView, View, ViewStyle } from "react-native" 3 | import { ScreenProps } from "./screen.props" 4 | import { presets, isNonScrolling } from "./screen.presets" 5 | 6 | /** 7 | * This screen does not scroll. 8 | * 9 | * @param props The screen props 10 | */ 11 | function ScreenWithoutScrolling(props: ScreenProps) { 12 | const preset = presets[props.preset] || presets["fixed"] 13 | const style = { ...preset.nonScroll, ...props.style } 14 | const backgroundStyle = props.backgroundColor ? { backgroundColor: props.backgroundColor } : {} 15 | 16 | return {props.children} 17 | } 18 | 19 | /** 20 | * This screen scrolls. 21 | * 22 | * @param props The screen props 23 | */ 24 | function ScreenWithScrolling(props: ScreenProps) { 25 | const preset = presets[props.preset] || presets["scroll"] 26 | const outerStyle = preset.scrollOuter 27 | const backgroundStyle = props.backgroundColor ? { backgroundColor: props.backgroundColor } : {} 28 | const innerStyle = { ...preset.scrollInner, ...props.style } as ViewStyle 29 | 30 | return ( 31 | 32 | {props.children} 33 | 34 | ) 35 | } 36 | 37 | /** 38 | * The starting component on every screen in the app. 39 | * 40 | * @param props The screen props 41 | */ 42 | export function Screen(props: ScreenProps) { 43 | if (isNonScrolling(props.preset)) { 44 | return 45 | } else { 46 | return 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/views/shared/switch/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./switch" 2 | -------------------------------------------------------------------------------- /src/views/shared/switch/switch.props.ts: -------------------------------------------------------------------------------- 1 | import { ViewStyle } from "react-native" 2 | 3 | export interface SwitchProps { 4 | /** 5 | * On or off. 6 | */ 7 | value?: boolean 8 | /** 9 | * Fires when the on/off switch triggers. 10 | * 11 | * @param newValue The new value we're switching to. 12 | */ 13 | onToggle?: (newValue: boolean) => void 14 | 15 | /** 16 | * A style override to apply to the container. Useful for margins and paddings. 17 | */ 18 | style?: ViewStyle 19 | 20 | /** 21 | * Additional track styling when on. 22 | */ 23 | trackOnStyle?: ViewStyle 24 | 25 | /** 26 | * Additional track styling when off. 27 | */ 28 | trackOffStyle?: ViewStyle 29 | 30 | /** 31 | * Additional thumb styling when on. 32 | */ 33 | thumbOnStyle?: ViewStyle 34 | 35 | /** 36 | * Additional thumb styling when off. 37 | */ 38 | thumbOffStyle?: ViewStyle 39 | } 40 | -------------------------------------------------------------------------------- /src/views/shared/switch/switch.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { View } from "react-native" 3 | import { storiesOf } from "@storybook/react-native" 4 | import { StoryScreen, Story, UseCase } from "../../../../storybook/views" 5 | import { Toggle } from "react-powerplug" 6 | import { Switch } from "." 7 | 8 | storiesOf("Switch", module) 9 | .addDecorator(fn => {fn()}) 10 | .add("Behaviour", () => ( 11 | 12 | 13 | 14 | {({ on, toggle }) => } 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | )) 25 | .add("Styling", () => ( 26 | 27 | 28 | 29 | {({ on, toggle }) => ( 30 | 31 | 39 | 40 | )} 41 | 42 | 43 | 44 | )) 45 | -------------------------------------------------------------------------------- /src/views/shared/switch/switch.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { ViewStyle, Animated, Easing, TouchableWithoutFeedback } from "react-native" 3 | import { color } from "../../../theme" 4 | import { SwitchProps } from "./switch.props" 5 | 6 | // dimensions 7 | const THUMB_SIZE = 30 8 | const WIDTH = 56 9 | const MARGIN = 2 10 | const OFF_POSITION = -0.5 11 | const ON_POSITION = WIDTH - THUMB_SIZE - MARGIN 12 | const BORDER_RADIUS = THUMB_SIZE * 3 / 4 13 | 14 | // colors 15 | const ON_COLOR = color.primary 16 | const OFF_COLOR = color.palette.offWhite 17 | const BORDER_ON_COLOR = ON_COLOR 18 | const BORDER_OFF_COLOR = "rgba(0, 0, 0, 0.1)" 19 | 20 | // animation 21 | const DURATION = 250 22 | 23 | // the track always has these props 24 | const TRACK = { 25 | height: THUMB_SIZE + MARGIN, 26 | width: WIDTH, 27 | borderRadius: BORDER_RADIUS, 28 | borderWidth: MARGIN / 2, 29 | backgroundColor: color.background, 30 | } 31 | 32 | // the thumb always has these props 33 | const THUMB: ViewStyle = { 34 | position: "absolute", 35 | width: THUMB_SIZE, 36 | height: THUMB_SIZE, 37 | borderColor: BORDER_OFF_COLOR, 38 | borderRadius: THUMB_SIZE / 2, 39 | borderWidth: MARGIN / 2, 40 | backgroundColor: color.background, 41 | shadowColor: BORDER_OFF_COLOR, 42 | shadowOffset: { width: 1, height: 2 }, 43 | shadowOpacity: 1, 44 | shadowRadius: 2, 45 | elevation: 2, 46 | } 47 | 48 | interface SwitchState { 49 | timer: Animated.Value 50 | } 51 | 52 | export class Switch extends React.PureComponent { 53 | state = { 54 | timer: new Animated.Value(this.props.value ? 1 : 0), 55 | } 56 | 57 | startAnimation(newValue: boolean) { 58 | const toValue = newValue ? 1 : 0 59 | const easing = Easing.out(Easing.circle) 60 | Animated.timing(this.state.timer, { 61 | toValue, 62 | duration: DURATION, 63 | easing, 64 | useNativeDriver: true, 65 | }).start() 66 | } 67 | 68 | componentWillReceiveProps(newProps: SwitchProps) { 69 | if (newProps.value !== this.props.value) { 70 | this.startAnimation(newProps.value) 71 | } 72 | } 73 | 74 | /** 75 | * Fires when we tap the touchable. 76 | */ 77 | handlePress = () => this.props.onToggle && this.props.onToggle(!this.props.value) 78 | 79 | /** 80 | * Render the component. 81 | */ 82 | render() { 83 | const translateX = this.state.timer.interpolate({ 84 | inputRange: [0, 1], 85 | outputRange: [OFF_POSITION, ON_POSITION], 86 | }) 87 | 88 | const trackStyle = { 89 | ...TRACK, 90 | ...{ 91 | backgroundColor: this.props.value ? ON_COLOR : OFF_COLOR, 92 | borderColor: this.props.value ? BORDER_ON_COLOR : BORDER_OFF_COLOR, 93 | }, 94 | ...this.props.value ? this.props.trackOnStyle : this.props.trackOffStyle, 95 | } 96 | 97 | const thumbStyle = { 98 | ...THUMB, 99 | ...{ transform: [{ translateX }] }, 100 | ...this.props.value ? this.props.thumbOnStyle : this.props.thumbOffStyle, 101 | } 102 | 103 | return ( 104 | 105 | 106 | 107 | 108 | 109 | ) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/views/shared/text-field/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./text-field" 2 | -------------------------------------------------------------------------------- /src/views/shared/text-field/text-field.props.ts: -------------------------------------------------------------------------------- 1 | import { TextInputProperties, TextStyle, ViewStyle } from "react-native" 2 | 3 | export interface TextFieldProps extends TextInputProperties { 4 | /** 5 | * The placeholder i18n key. 6 | */ 7 | placeholderTx?: string 8 | 9 | /** 10 | * The Placeholder text if no placeholderTx is provided. 11 | */ 12 | placeholder?: string 13 | 14 | /** 15 | * The label i18n key. 16 | */ 17 | labelTx?: string 18 | 19 | /** 20 | * The label text if no labelTx is provided. 21 | */ 22 | label?: string 23 | 24 | /** 25 | * Optional container style overrides useful for margins & padding. 26 | */ 27 | style?: ViewStyle 28 | 29 | /** 30 | * Optional style overrides for the input. 31 | */ 32 | inputStyle?: TextStyle 33 | 34 | /** 35 | * Various look & feels. 36 | */ 37 | preset?: "default" 38 | } 39 | -------------------------------------------------------------------------------- /src/views/shared/text-field/text-field.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { storiesOf } from "@storybook/react-native" 3 | import { StoryScreen, Story, UseCase } from "../../../../storybook/views" 4 | import { Text } from "../text" 5 | import { TextField } from "./" 6 | import { State } from "react-powerplug" 7 | 8 | storiesOf("TextField", module) 9 | .addDecorator(fn => {fn()}) 10 | .add("Labelling", () => ( 11 | 12 | 13 | 14 | {({ state, setState }) => ( 15 | setState({ value })} 17 | value={state.value} 18 | label="Name" 19 | placeholder="omg your name" 20 | /> 21 | )} 22 | 23 | 24 | 25 | 26 | 27 | {({ state, setState }) => ( 28 | setState({ value })} 30 | value={state.value} 31 | placeholderTx="storybook.placeholder" 32 | labelTx="storybook.field" 33 | /> 34 | )} 35 | 36 | 37 | 38 | )) 39 | .add("Style Overrides", () => ( 40 | 41 | 46 | 47 | {({ state, setState }) => ( 48 | setState({ value })} 50 | value={state.value} 51 | label="First Name" 52 | style={{ paddingTop: 0, paddingHorizontal: 40 }} 53 | /> 54 | )} 55 | 56 | 57 | {({ state, setState }) => ( 58 | setState({ value })} 60 | value={state.value} 61 | label="Last Name" 62 | style={{ paddingBottom: 0 }} 63 | /> 64 | )} 65 | 66 | 67 | 71 | 72 | {({ state, setState }) => ( 73 | setState({ value })} 75 | value={state.value} 76 | label="Name" 77 | inputStyle={{ 78 | backgroundColor: "rebeccapurple", 79 | color: "white", 80 | padding: 40, 81 | borderWidth: 10, 82 | borderRadius: 4, 83 | borderColor: "hotpink", 84 | }} 85 | /> 86 | )} 87 | 88 | 89 | 90 | 91 | )) 92 | -------------------------------------------------------------------------------- /src/views/shared/text-field/text-field.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { View, TextInput, TextStyle, ViewStyle, Platform } from "react-native" 3 | import { color, spacing, typography } from "../../../theme" 4 | import { translate } from "../../../i18n" 5 | import { Text } from "../text" 6 | import { TextFieldProps } from "./text-field.props" 7 | 8 | // the base styling for the container 9 | const CONTAINER: ViewStyle = { 10 | paddingVertical: spacing[3], 11 | } 12 | 13 | // the base styling for the TextInput 14 | const INPUT: TextStyle = { 15 | fontFamily: typography.primary, 16 | color: color.text, 17 | minHeight: 44, 18 | fontSize: 18, 19 | backgroundColor: color.palette.white, 20 | } 21 | 22 | // currently we have no presets, but that changes quickly when you build your app. 23 | const PRESETS: { [name: string]: ViewStyle } = { 24 | default: {}, 25 | } 26 | 27 | /** 28 | * A component which has a label and an input together. 29 | */ 30 | export class TextField extends React.Component { 31 | render() { 32 | const { 33 | placeholderTx, 34 | placeholder, 35 | labelTx, 36 | label, 37 | preset = "default", 38 | style: styleOverride, 39 | inputStyle: inputStyleOverride, 40 | ...rest, 41 | } = this.props 42 | const containerStyle: ViewStyle = { ...CONTAINER, ...PRESETS[preset], ...styleOverride } 43 | const inputStyle: TextStyle = { ...INPUT, ...inputStyleOverride } 44 | const actualPlaceholder = placeholderTx ? translate(placeholderTx) : placeholder 45 | const keyboardType = Platform.OS === 'ios' ? 'numbers-and-punctuation' : 'default' 46 | 47 | return ( 48 | 49 | 50 | 59 | 60 | ) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/views/shared/text/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./text" 2 | -------------------------------------------------------------------------------- /src/views/shared/text/text.presets.ts: -------------------------------------------------------------------------------- 1 | import { TextStyle } from "react-native" 2 | import { typography } from "../../../theme/typography" 3 | import { color } from "../../../theme/color" 4 | 5 | /** 6 | * All text will start off looking like this. 7 | */ 8 | const BASE: TextStyle = { 9 | fontFamily: typography.primary, 10 | color: color.text, 11 | fontSize: 18, 12 | } 13 | 14 | /** 15 | * All the variations of text styling within the app. 16 | * 17 | * You want to customize these to whatever you need in your app. 18 | */ 19 | export const presets = { 20 | /** 21 | * The default text styles. 22 | */ 23 | default: BASE, 24 | 25 | /** 26 | * A bold version of the default text. 27 | */ 28 | bold: { ...BASE, fontWeight: "bold" } as TextStyle, 29 | 30 | /** 31 | * Large headers. 32 | */ 33 | header: { ...BASE, fontSize: 24, fontWeight: "bold" } as TextStyle, 34 | 35 | /** 36 | * Field labels that appear on forms above the inputs. 37 | */ 38 | fieldLabel: { ...BASE, fontSize: 13, color: color.dim } as TextStyle, 39 | 40 | /** 41 | * A smaller piece of secondard information. 42 | */ 43 | secondary: { ...BASE, fontSize: 9, color: color.dim } as TextStyle, 44 | } 45 | 46 | /** 47 | * A list of preset names. 48 | */ 49 | export type TextPresets = keyof typeof presets 50 | -------------------------------------------------------------------------------- /src/views/shared/text/text.props.ts: -------------------------------------------------------------------------------- 1 | import { TextStyle, TextProperties } from "react-native" 2 | import { TextPresets } from "./text.presets" 3 | 4 | export interface TextProps extends TextProperties { 5 | /** 6 | * Children components. 7 | */ 8 | children?: React.ReactNode 9 | 10 | /** 11 | * Text which is looked up via i18n. 12 | */ 13 | tx?: string 14 | 15 | /** 16 | * The text to display if not using `tx` or nested components. 17 | */ 18 | text?: string 19 | 20 | /** 21 | * An optional style override useful for padding & margin. 22 | */ 23 | style?: TextStyle 24 | 25 | /** 26 | * One of the different types of text presets. 27 | */ 28 | preset?: TextPresets 29 | } 30 | -------------------------------------------------------------------------------- /src/views/shared/text/text.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { storiesOf } from "@storybook/react-native" 3 | import { StoryScreen, Story, UseCase } from "../../../../storybook/views" 4 | import { Text } from "./text" 5 | 6 | storiesOf("Text", module) 7 | .addDecorator(fn => {fn()}) 8 | .add("Style Presets", () => ( 9 | 10 | 11 | Hello! 12 | 13 | Check out{"\n"} 14 | my{"\n"} 15 | line height 16 | 17 | The quick brown fox jumped over the slow lazy dog. 18 | $123,456,789.00 19 | 20 | 21 | Osnap! I'm puffy. 22 | 23 | 24 | Behold! 25 | 26 | 27 | )) 28 | .add("Passing Content", () => ( 29 | 30 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 44 | Passing strings as children. 45 | 46 | 47 | 48 | {" "} 49 | Hello bolded World. 50 | 51 | 52 | 53 | )) 54 | -------------------------------------------------------------------------------- /src/views/shared/text/text.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Text as ReactNativeText } from "react-native" 3 | import { presets } from "./text.presets" 4 | import { TextProps } from "./text.props" 5 | import { translate } from "../../../i18n" 6 | 7 | /** 8 | * For your text displaying needs. 9 | * 10 | * This component is a HOC over the built-in React Native one. 11 | */ 12 | export function Text(props: TextProps) { 13 | // grab the props 14 | const { preset = "default", tx, text, children, style: styleOverride, ...rest } = props 15 | 16 | // figure out which content to use 17 | const i18nText = tx && translate(tx) 18 | const content = i18nText || text || children 19 | 20 | // assemble the style 21 | const presetToUse = presets[preset] || presets.default 22 | const style = { ...presetToUse, ...styleOverride } 23 | 24 | return ( 25 | 26 | {content} 27 | 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /src/views/shared/wallpaper/BG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/views/shared/wallpaper/BG.png -------------------------------------------------------------------------------- /src/views/shared/wallpaper/bg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ebouJ/Equation-Solver/be164da4f1df40dd54d8fbd48933776a7088e459/src/views/shared/wallpaper/bg@2x.png -------------------------------------------------------------------------------- /src/views/shared/wallpaper/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./wallpaper" 2 | -------------------------------------------------------------------------------- /src/views/shared/wallpaper/wallpaper.presets.ts: -------------------------------------------------------------------------------- 1 | import { ImageStyle } from "react-native" 2 | 3 | /** 4 | * All wallpaper will start off looking like this. 5 | */ 6 | const BASE: ImageStyle = { 7 | position: "absolute", 8 | top: 0, 9 | left: 0, 10 | bottom: 0, 11 | right: 0, 12 | } 13 | 14 | /** 15 | * All the variations of wallpaper styling within the app. 16 | * 17 | * You want to customize these to whatever you need in your app. 18 | */ 19 | export const presets = { 20 | /** 21 | * The default wallpaper styles. 22 | */ 23 | stretch: { 24 | ...BASE, 25 | resizeMode: "stretch", 26 | width: null, // Have to set these to null because android ¯\_(ツ)_/¯ 27 | height: null, 28 | } as ImageStyle, 29 | } 30 | 31 | /** 32 | * A list of preset names. 33 | */ 34 | export type WallpaperPresets = keyof typeof presets 35 | -------------------------------------------------------------------------------- /src/views/shared/wallpaper/wallpaper.props.ts: -------------------------------------------------------------------------------- 1 | import { ImageStyle } from "react-native" 2 | import { WallpaperPresets } from "./wallpaper.presets" 3 | 4 | export interface WallpaperProps { 5 | /** 6 | * An optional style override useful for padding & margin. 7 | */ 8 | style?: ImageStyle 9 | 10 | /** 11 | * An optional background image to override the default image. 12 | */ 13 | backgroundImage?: string 14 | 15 | /** 16 | * One of the different types of wallpaper presets. 17 | */ 18 | preset?: WallpaperPresets 19 | } 20 | -------------------------------------------------------------------------------- /src/views/shared/wallpaper/wallpaper.story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { storiesOf } from "@storybook/react-native" 3 | import { StoryScreen, Story, UseCase } from "../../../../storybook/views" 4 | import { Wallpaper } from "./wallpaper" 5 | 6 | storiesOf("Wallpaper", module) 7 | .addDecorator(fn => {fn()}) 8 | .add("Style Presets", () => ( 9 | 10 | 11 | 12 | 13 | 14 | )) 15 | -------------------------------------------------------------------------------- /src/views/shared/wallpaper/wallpaper.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Image } from "react-native" 3 | import { presets } from "./wallpaper.presets" 4 | import { WallpaperProps } from "./wallpaper.props" 5 | 6 | const defaultImage = require("./bg.png") 7 | 8 | /** 9 | * For your text displaying needs. 10 | * 11 | * This component is a HOC over the built-in React Native one. 12 | */ 13 | export function Wallpaper(props: WallpaperProps) { 14 | // grab the props 15 | const { preset = "stretch", style: styleOverride, backgroundImage } = props 16 | 17 | // assemble the style 18 | const presetToUse = presets[preset] || presets.stretch 19 | const style = { ...presetToUse, ...styleOverride } 20 | 21 | // figure out which image to use 22 | const source = backgroundImage || defaultImage 23 | 24 | return ( 25 | 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /storybook/index.ts: -------------------------------------------------------------------------------- 1 | // this is the native storybook entry point 2 | // import { StorybookUI } from "./config" 3 | 4 | export * from "./storybook" 5 | -------------------------------------------------------------------------------- /storybook/storybook-registry.ts: -------------------------------------------------------------------------------- 1 | require("../src/views/shared/text/text.story") 2 | require("../src/views/shared/button/button.story") 3 | require("../src/views/shared/equation-input/equation-input.story") 4 | require("../src/views/shared/form-row/form-row.story") 5 | require("../src/views/shared/switch/switch.story") 6 | require("../src/views/shared/text-field/text-field.story") 7 | require("../src/views/shared/checkbox/checkbox.story") 8 | require("../src/views/shared/wallpaper/wallpaper.story") 9 | require("../src/views/shared/icon/icon.story") 10 | require("../src/views/shared/header/header.story") 11 | -------------------------------------------------------------------------------- /storybook/storybook.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { getStorybookUI, configure } from "@storybook/react-native" 3 | import SplashScreen from "react-native-splash-screen" 4 | 5 | configure(() => { 6 | require("./storybook-registry") 7 | }) 8 | 9 | const StorybookUI = getStorybookUI({ port: 9001, host: "localhost", onDeviceUI: true }) 10 | 11 | // RN hot module must be in a class for HMR 12 | export class StorybookUIRoot extends React.Component { 13 | componentDidMount() { 14 | SplashScreen.hide() 15 | } 16 | render() { 17 | return 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /storybook/views/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./story-screen" 2 | export * from "./story" 3 | export * from "./use-case" 4 | -------------------------------------------------------------------------------- /storybook/views/story-screen.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { ViewStyle, KeyboardAvoidingView, Platform } from "react-native" 3 | 4 | const ROOT: ViewStyle = { backgroundColor: "#f0f0f0", flex: 1 } 5 | 6 | export interface StoryScreenProps { 7 | children?: React.ReactNode 8 | } 9 | 10 | const behavior = Platform.OS === "ios" ? "padding" : null 11 | export const StoryScreen = props => ( 12 | 13 | {props.children} 14 | 15 | ) 16 | -------------------------------------------------------------------------------- /storybook/views/story.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { ScrollView, View, ViewStyle } from "react-native" 3 | 4 | export interface StoryProps { 5 | children?: React.ReactNode 6 | } 7 | 8 | const ROOT: ViewStyle = { flex: 1 } 9 | 10 | export function Story(props: StoryProps) { 11 | return ( 12 | 13 | {props.children} 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /storybook/views/use-case.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { View, Text, TextStyle, ViewStyle } from "react-native" 3 | 4 | const ROOT: ViewStyle = { backgroundColor: "#eee" } 5 | const TITLE: TextStyle = { fontWeight: "600", color: "#3d3d3d" } 6 | const TITLE_WRAPPER: ViewStyle = {} 7 | const USE_CASE_WRAPPER: ViewStyle = { 8 | position: "absolute", 9 | top: 0, 10 | left: 0, 11 | right: 0, 12 | borderTopColor: "#e6e6e6", 13 | borderTopWidth: 1, 14 | flexDirection: "row", 15 | } 16 | const USE_CASE: TextStyle = { 17 | fontSize: 10, 18 | color: "#666", 19 | paddingHorizontal: 4, 20 | paddingBottom: 2, 21 | } 22 | const USAGE: TextStyle = { color: "#666", fontSize: 10, paddingTop: 0 } 23 | const HEADER: ViewStyle = { 24 | paddingTop: 20, 25 | paddingBottom: 10, 26 | paddingHorizontal: 10, 27 | borderBottomColor: "#e6e6e6", 28 | borderBottomWidth: 1, 29 | } 30 | const COMPONENT: ViewStyle = { backgroundColor: "#fff" } 31 | 32 | export interface UseCaseProps { 33 | /** The title. */ 34 | text: string 35 | /** When should we be using this? */ 36 | usage?: string 37 | /** The component use case. */ 38 | children: React.ReactNode 39 | /** A style override. Rarely used. */ 40 | style?: ViewStyle 41 | /** Don't use any padding because it's important to see the spacing. */ 42 | noPad?: boolean 43 | /** Don't use background color because it's important to see the color. */ 44 | noBackground?: boolean 45 | } 46 | 47 | export function UseCase(props: UseCaseProps) { 48 | const style = { 49 | ...COMPONENT, 50 | ...{ padding: props.noPad ? 0 : 10 }, 51 | ...{ backgroundColor: props.noBackground ? "rgba(0,0,0,0)" : COMPONENT.backgroundColor }, 52 | ...props.style, 53 | } 54 | return ( 55 | 56 | 57 | 58 | Use Case 59 | 60 | 61 | {props.text} 62 | 63 | {props.usage && {props.usage}} 64 | 65 | {props.children} 66 | 67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /test/mock-i18n.ts: -------------------------------------------------------------------------------- 1 | jest.mock("react-native-i18n", () => { 2 | return { 3 | t: key => `${key}.test`, 4 | } 5 | }) 6 | -------------------------------------------------------------------------------- /test/mock-reactotron.ts: -------------------------------------------------------------------------------- 1 | declare var tron 2 | tron = null 3 | -------------------------------------------------------------------------------- /test/setup.ts: -------------------------------------------------------------------------------- 1 | // we always make sure 'react-native' gets included first 2 | import "react-native" 3 | 4 | // libraries to mock 5 | import "./mock-i18n" 6 | import "./mock-reactotron" 7 | -------------------------------------------------------------------------------- /test/storyshots.test.ts: -------------------------------------------------------------------------------- 1 | import initStoryshots from "@storybook/addon-storyshots" 2 | 3 | initStoryshots({ 4 | configPath: "./storybook", 5 | framework: "react-native", 6 | }) 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "allowSyntheticDefaultImports": true, 5 | "experimentalDecorators": true, 6 | "jsx": "react-native", 7 | "module": "es2015", 8 | "moduleResolution": "node", 9 | "noImplicitAny": false, 10 | "noImplicitReturns": true, 11 | "noImplicitThis": true, 12 | "noUnusedLocals": true, 13 | "sourceMap": true, 14 | "target": "es2015" 15 | }, 16 | "exclude": ["node_modules"], 17 | "include": ["src", "test", "storybook"] 18 | } 19 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint-config-prettier", 3 | "rules": { 4 | "quotemark": [true, "double", "jsx-double", "avoid-escape"], 5 | "semicolon": [true, "never"], 6 | "trailing-comma": [ 7 | true, 8 | { 9 | "multiline": "always", 10 | "singleline": "never" 11 | } 12 | ] 13 | } 14 | } 15 | --------------------------------------------------------------------------------