diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..a9ce1369 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["react-native"] +} diff --git a/.editorconfig b/.editorconfig index 881e55e5..192641a7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,7 +3,7 @@ root = true [*] indent_style = space -indent_size = 4 +indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true diff --git a/.eslintrc b/.eslintrc index 9d061b2c..7aced55a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,379 +1,84 @@ { - "parser": "babel-eslint", - "ecmaFeatures": { - "jsx": true - }, - "env": { - "es6": true, - "jasmine": true, - }, - "plugins": [ - "react" - ], - // Map from global var to bool specifying if it can be redefined - "globals": { - "__DEV__": true, - "__dirname": false, - "__fbBatchedBridgeConfig": false, - "cancelAnimationFrame": false, - "clearImmediate": true, - "clearInterval": false, - "clearTimeout": false, - "console": false, - "document": false, - "escape": false, - "exports": false, - "fetch": false, - "global": false, - "jest": false, - "Map": true, - "module": false, - "navigator": false, - "process": false, - "Promise": true, - "requestAnimationFrame": true, - "require": false, - "Set": true, - "setImmediate": true, - "setInterval": false, - "setTimeout": false, - "window": false, - "XMLHttpRequest": false, - "pit": false - }, - "rules": { - "comma-dangle": 0, - // disallow trailing commas in object literals - "no-cond-assign": 1, - // disallow assignment in conditional expressions - "no-console": 0, - // disallow use of console (off by default in the node environment) - "no-constant-condition": 0, - // disallow use of constant expressions in conditions - "no-control-regex": 1, - // disallow control characters in regular expressions - "no-debugger": 1, - // disallow use of debugger - "no-dupe-keys": 1, - // disallow duplicate keys when creating object literals - "no-empty": 0, - // disallow empty statements - "no-empty-class": 1, - // disallow the use of empty character classes in regular expressions - "no-ex-assign": 1, - // disallow assigning to the exception in a catch block - "no-extra-boolean-cast": 1, - // disallow double-negation boolean casts in a boolean context - "no-extra-parens": 0, - // disallow unnecessary parentheses (off by default) - "no-extra-semi": 1, - // disallow unnecessary semicolons - "no-func-assign": 1, - // disallow overwriting functions written as function declarations - "no-inner-declarations": 0, - // disallow function or variable declarations in nested blocks - "no-invalid-regexp": 1, - // disallow invalid regular expression strings in the RegExp constructor - "no-negated-in-lhs": 1, - // disallow negation of the left operand of an in expression - "no-obj-calls": 1, - // disallow the use of object properties of the global object (Math and JSON) as functions - "no-regex-spaces": 1, - // disallow multiple spaces in a regular expression literal - "no-reserved-keys": 0, - // disallow reserved words being used as object literal keys (off by default) - "no-sparse-arrays": 1, - // disallow sparse arrays - "no-unreachable": 1, - // disallow unreachable statements after a return, throw, continue, or break statement - "use-isnan": 1, - // disallow comparisons with the value NaN - "valid-jsdoc": 0, - // Ensure JSDoc comments are valid (off by default) - "valid-typeof": 1, - // Ensure that the results of typeof are compared against a valid string + "extends": ["standard", "standard-react"], + "parser": "babel-eslint", + "globals": { + "__DEV__": true, + "__dirname": false, + "__fbBatchedBridgeConfig": false, + "alert": false, + "cancelAnimationFrame": false, + "cancelIdleCallback": false, + "clearImmediate": true, + "clearInterval": false, + "clearTimeout": false, + "console": false, + "document": false, + "escape": false, + "Event": false, + "EventTarget": false, + "exports": false, + "fetch": false, + "FormData": false, + "global": false, + "jest": false, + "Map": true, + "module": false, + "navigator": false, + "process": false, + "Promise": true, + "requestAnimationFrame": true, + "requestIdleCallback": true, + "require": false, + "Set": true, + "setImmediate": true, + "setInterval": false, + "setTimeout": false, + "window": false, + "XMLHttpRequest": false, + "pit": false, - // Best Practices - // These are rules designed to prevent you from making mistakes. They either prescribe a better way of doing something or help you avoid footguns. - - "block-scoped-var": 0, - // treat var statements as if they were block scoped (off by default) - "complexity": 0, - // specify the maximum cyclomatic complexity allowed in a program (off by default) - "consistent-return": 0, - // require return statements to either always or never specify values - "curly": 1, - // specify curly brace conventions for all control statements - "default-case": 0, - // require default case in switch statements (off by default) - "dot-notation": 1, - // encourages use of dot notation whenever possible - "eqeqeq": 1, - // require the use of === and !== - "guard-for-in": 0, - // make sure for-in loops have an if statement (off by default) - "no-alert": 1, - // disallow the use of alert, confirm, and prompt - "no-caller": 1, - // disallow use of arguments.caller or arguments.callee - "no-div-regex": 1, - // disallow division operators explicitly at beginning of regular expression (off by default) - "no-else-return": 0, - // disallow else after a return in an if (off by default) - "no-empty-label": 1, - // disallow use of labels for anything other then loops and switches - "no-eq-null": 0, - // disallow comparisons to null without a type-checking operator (off by default) - "no-eval": 1, - // disallow use of eval() - "no-extend-native": 1, - // disallow adding to native types - "no-extra-bind": 1, - // disallow unnecessary function binding - "no-fallthrough": 1, - // disallow fallthrough of case statements - "no-floating-decimal": 1, - // disallow the use of leading or trailing decimal points in numeric literals (off by default) - "no-implied-eval": 1, - // disallow use of eval()-like methods - "no-labels": 1, - // disallow use of labeled statements - "no-iterator": 1, - // disallow usage of __iterator__ property - "no-lone-blocks": 1, - // disallow unnecessary nested blocks - "no-loop-func": 0, - // disallow creation of functions within loops - "no-multi-str": 0, - // disallow use of multiline strings - "no-native-reassign": 0, - // disallow reassignments of native objects - "no-new": 1, - // disallow use of new operator when not part of the assignment or comparison - "no-new-func": 1, - // disallow use of new operator for Function object - "no-new-wrappers": 1, - // disallows creating new instances of String,Number, and Boolean - "no-octal": 1, - // disallow use of octal literals - "no-octal-escape": 1, - // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251"; - "no-proto": 1, - // disallow usage of __proto__ property - "no-redeclare": 0, - // disallow declaring the same variable more then once - "no-return-assign": 1, - // disallow use of assignment in return statement - "no-script-url": 1, - // disallow use of javascript: urls. - "no-self-compare": 1, - // disallow comparisons where both sides are exactly the same (off by default) - "no-sequences": 1, - // disallow use of comma operator - "no-unused-expressions": 0, - // disallow usage of expressions in statement position - "no-void": 1, - // disallow use of void operator (off by default) - "no-warning-comments": 0, - // disallow usage of configurable warning terms in comments": 1, // e.g. TODO or FIXME (off by default) - "no-with": 1, - // disallow use of the with statement - "radix": 1, - // require use of the second argument for parseInt() (off by default) - "semi-spacing": 1, - // require a space after a semi-colon - "vars-on-top": 0, - // requires to declare all vars on top of their containing scope (off by default) - "wrap-iife": 0, - // require immediate function invocation to be wrapped in parentheses (off by default) - "yoda": 1, - // require or disallow Yoda conditions - - // Strict Mode - // These rules relate to using strict mode. - - "global-strict": [ - 2, - "always" - ], - // require or disallow the "use strict" pragma in the global scope (off by default in the node environment) - "no-extra-strict": 1, - // disallow unnecessary use of "use strict"; when already in strict mode - "strict": 0, - // require that all functions are run in strict mode - - // Variables - // These rules have to do with variable declarations. - - "no-catch-shadow": 1, - // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment) - "no-delete-var": 1, - // disallow deletion of variables - "no-label-var": 1, - // disallow labels that share a name with a variable - "no-shadow": 1, - // disallow declaration of variables already declared in the outer scope - "no-shadow-restricted-names": 1, - // disallow shadowing of names such as arguments - "no-undef": 2, - // disallow use of undeclared variables unless mentioned in a /*global */ block - "no-undefined": 0, - // disallow use of undefined variable (off by default) - "no-undef-init": 1, - // disallow use of undefined when initializing variables - "no-unused-vars": [ - 1, - { - "vars": "all", - "args": "none" - } - ], - // disallow declaration of variables that are not used in the code - "no-use-before-define": 0, - // disallow use of variables before they are defined - - // Node.js - // These rules are specific to JavaScript running on Node.js. - - "handle-callback-err": 1, - // enforces error handling in callbacks (off by default) (on by default in the node environment) - "no-mixed-requires": 1, - // disallow mixing regular variable and require declarations (off by default) (on by default in the node environment) - "no-new-require": 1, - // disallow use of new operator with the require function (off by default) (on by default in the node environment) - "no-path-concat": 1, - // disallow string concatenation with __dirname and __filename (off by default) (on by default in the node environment) - "no-process-exit": 0, - // disallow process.exit() (on by default in the node environment) - "no-restricted-modules": 1, - // restrict usage of specified node modules (off by default) - "no-sync": 0, - // disallow use of synchronous methods (off by default) - - // Stylistic Issues - // These rules are purely matters of style and are quite subjective. - - "key-spacing": 0, - "comma-spacing": 0, - "no-multi-spaces": 0, - "brace-style": 0, - // enforce one true brace style (off by default) - "camelcase": 0, - // require camel case names - "consistent-this": [ - 1, - "self" - ], - // enforces consistent naming when capturing the current execution context (off by default) - "eol-last": 1, - // enforce newline at the end of file, with no multiple empty lines - "func-names": 0, - // require function expressions to have a name (off by default) - "func-style": 0, - // enforces use of function declarations or expressions (off by default) - "new-cap": 0, - // require a capital letter for constructors - "new-parens": 1, - // disallow the omission of parentheses when invoking a constructor with no arguments - "no-nested-ternary": 0, - // disallow nested ternary expressions (off by default) - "no-array-constructor": 1, - // disallow use of the Array constructor - "no-lonely-if": 0, - // disallow if as the only statement in an else block (off by default) - "no-new-object": 1, - // disallow use of the Object constructor - "no-spaced-func": 1, - // disallow space between function identifier and application - "no-space-before-semi": 1, - // disallow space before semicolon - "no-ternary": 0, - // disallow the use of ternary operators (off by default) - "no-trailing-spaces": 1, - // disallow trailing whitespace at the end of lines - "no-underscore-dangle": 0, - // disallow dangling underscores in identifiers - "no-wrap-func": 1, - // disallow wrapping of non-IIFE statements in parens - "no-mixed-spaces-and-tabs": 1, - // disallow mixed spaces and tabs for indentation - "quotes": [ - 1, - "single", - "avoid-escape" - ], - // specify whether double or single quotes should be used - "quote-props": 0, - // require quotes around object literal property names (off by default) - "semi": 1, - // require or disallow use of semicolons instead of ASI - "sort-vars": 0, - // sort variables within the same declaration block (off by default) - "space-after-keywords": 1, - // require a space after certain keywords (off by default) - "space-in-brackets": 0, - // require or disallow spaces inside brackets (off by default) - "space-in-parens": 0, - // require or disallow spaces inside parentheses (off by default) - "space-infix-ops": 1, - // require spaces around operators - "space-return-throw-case": 1, - // require a space after return, throw, and case - "space-unary-ops": [ - 1, - { - "words": true, - "nonwords": false - } - ], - // require or disallow spaces before/after unary operators (words on by default, nonwords off by default) - "max-nested-callbacks": 0, - // specify the maximum depth callbacks can be nested (off by default) - "one-var": 0, - // allow just one var statement per function (off by default) - "wrap-regex": 0, - // require regex literals to be wrapped in parentheses (off by default) - - // Legacy - // The following rules are included for compatibility with JSHint and JSLint. While the names of the rules may not match up with the JSHint/JSLint counterpart, the functionality is the same. - - "max-depth": 0, - // specify the maximum depth that blocks can be nested (off by default) - "max-len": 0, - // specify the maximum length of a line in your program (off by default) - "max-params": 0, - // limits the number of parameters that can be used in the function declaration. (off by default) - "max-statements": 0, - // specify the maximum number of statement allowed in a function (off by default) - "no-bitwise": 1, - // disallow use of bitwise operators (off by default) - "no-plusplus": 0, - // disallow use of unary operators, ++ and -- (off by default) - - "react/display-name": 0, - "react/jsx-boolean-value": 0, - "react/jsx-quotes": [ - 1, - "double", - "avoid-escape" - ], - "react/jsx-no-undef": 1, - "react/jsx-sort-props": 0, - "react/jsx-uses-react": 0, - "react/jsx-uses-vars": 1, - "react/no-did-mount-set-state": [ - 1, - "allow-in-func" - ], - "react/no-did-update-set-state": [ - 1, - "allow-in-func" - ], - "react/no-multi-comp": 0, - "react/no-unknown-property": 0, - "react/prop-types": 0, - "react/react-in-jsx-scope": 0, - "react/self-closing-comp": 1, - "react/wrap-multilines": 0 - } + // Flow global types. + "ReactComponent": false, + "ReactClass": false, + "ReactElement": false, + "ReactPropsCheckType": false, + "ReactPropsChainableTypeChecker": false, + "ReactPropTypes": false, + "SyntheticEvent": false, + "$Either": false, + "$All": false, + "$ArrayBufferView": false, + "$Tuple": false, + "$Supertype": false, + "$Subtype": false, + "$Shape": false, + "$Diff": false, + "$Keys": false, + "$Enum": false, + "$Exports": false, + "$FlowIssue": false, + "$FlowFixMe": false, + "$FixMe": false + }, + "rules": { + "eqeqeq": "warn", + "indent": "warn", + "no-mixed-spaces-and-tabs": "warn", + "no-multi-spaces": "warn", + "no-return-assign": "warn", + "no-return-await": "warn", + "no-tabs": "warn", + "no-unused-vars": [ + "warn", + { + "vars": "all", + "args": "none", + "varsIgnorePattern": "React" + } + ], + "react/no-unused-prop-types": "warn", + "react/prop-types": 0, + "standard/array-bracket-even-spacing": "warn", + "standard/object-curly-even-spacing": "warn" + } } diff --git a/.flowconfig b/.flowconfig index 9d4fb361..2f133248 100755 --- a/.flowconfig +++ b/.flowconfig @@ -1,33 +1,48 @@ [ignore] +; We fork some components by platform +.*/*[.]android.js -# We fork some components by platform. -.*/*.web.js -.*/*.android.js +; Ignore "BUCK" generated dirs +/\.buckd/ -# Some modules have their own node_modules with overlap -.*/node_modules/node-haste/.* +; Ignore unexpected extra "@providesModule" +.*/node_modules/.*/node_modules/fbjs/.* -# Ignore react-tools where there are overlaps, but don't ignore anything that -# react-native relies on -.*/node_modules/react-tools/src/vendor/core/ExecutionEnvironment.js -.*/node_modules/react-tools/src/browser/eventPlugins/ResponderEventPlugin.js -.*/node_modules/react-tools/src/browser/ui/React.js -.*/node_modules/react-tools/src/core/ReactInstanceHandles.js -.*/node_modules/react-tools/src/event/EventPropagators.js +; Ignore duplicate module providers +; For RN Apps installed via npm, "Libraries" folder is inside +; "node_modules/react-native" but in the source repo it is in the root +.*/Libraries/react-native/React.js -# Ignore commoner tests -.*/node_modules/react-tools/node_modules/commoner/test/.* - -# See https://github.com/facebook/flow/issues/442 -.*/react-tools/node_modules/commoner/lib/reader.js - -# Ignore jest -.*/react-native/node_modules/jest-cli/.* +; Ignore polyfills +.*/Libraries/polyfills/.* [include] [libs] node_modules/react-native/Libraries/react-native/react-native-interface.js +node_modules/react-native/flow/ [options] +emoji=true + module.system=haste + +munge_underscores=true + +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' + +suppress_type=$FlowIssue +suppress_type=$FlowFixMe +suppress_type=$FlowFixMeProps +suppress_type=$FlowFixMeState +suppress_type=$FixMe + +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-7]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-7]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy +suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError + +unsafe.enable_getters_and_setters=true + +[version] +^0.57.0 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..d42ff183 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.pbxproj -text diff --git a/.gitignore b/.gitignore index c3ea306e..54cd1169 100755 --- a/.gitignore +++ b/.gitignore @@ -22,19 +22,40 @@ DerivedData *.xcuserstate project.xcworkspace +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml + +# Web +# +/web/output/ + # node.js # node_modules/ npm-debug.log +yarn-error.log -.idea - -app/mocks/user.js +# BUCK +buck-out/ +\.buckd/ +*.keystore -react-packager-cache** -.rnplay -tmp -iOS/main.jsbundle -test.js +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ +*/fastlane/report.xml +*/fastlane/Preview.html +*/fastlane/screenshots +# other +e2e/output/ +*.sublime-* diff --git a/.watchmanconfig b/.watchmanconfig new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/.watchmanconfig @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/README.md b/README.md index 19082486..f95d8dbc 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,101 @@ # Noder - A React-Native Client for [cnodejs.org](http://cnodejs.org) - -> A new [cnodejs.org](http://cnodejs.org) mobile app powered by [React-Native](http://facebook.github.io/react-native/) and [Redux](https://github.com/gaearon/redux). +> A new [cnodejs.org](http://cnodejs.org) mobile & web app powered by [react-native](http://facebook.github.io/react-native/) and [react-web](https://github.com/flyskywhy/react-web) and [CodeceptJS](https://github.com/Codeception/CodeceptJS) . +## Install + +**微信浏览器中若无法打开安装链接,请复制链接到系统浏览器中打开** + +* iOS: https://itunes.apple.com/cn/app/noder/id1106775857 +* android(v1.0.0-alpha2): https://www.pgyer.com/noder + ## Develop -If you want to run it on you local simulator, you should: +For local development you need to follow the below commands: ``` -git clone https://github.com/soliury/noder-react-native.git -npm install -react-native bundle +git clone https://github.com/soliury/noder-react-native.git noder +cd noder +yarn install ``` -Then click run in Xcode, if failed, you should rebuild all package that this project used in Xcode(Just choose the package and **command+B** to run compile) -If you want to run on you local iPhone app, you should follow the [doc](http://facebook.github.io/react-native/docs/runningondevice.html#content). -If you don't want to update the ip by hand, you can use this: +Click the run button in Xcode, if something went wrong, you need to rebuild all packages that be used in this project with Xcode (Just select the package and press **command+B** to run compile). + +If you want to run it on your iPhone, please follow the [Offical Doc](http://facebook.github.io/react-native/docs/running-on-device). + +If you want to run it on your Android, please run: +``` +npm run android +npm start +``` +If you want to run it on your Browser (localhost:3000), please run: ``` -gulp replace +npm run web ``` -Although, there is a good command, just run: +## e2e test +JS app code in `src/`write once run on Android, iOS and Web by react-native and react-web, now JS test case in `e2e/` with locator ~ write once run on them too with [CodeceptJS](https://github.com/Codeception/CodeceptJS) . +### Web test +After install server side of test by `npm run e2e-update-server-web`, please run: +``` +npm run web +npm run e2e-server-web +``` +Then run client side of test by `npm run e2e-web`, thus a web page will be opened in firefox automatically and complete the test. + +### Android test +After install server side of test by `npm install -g appium`, please run: ``` +npm run android npm start +npm run e2e-server-native ``` +Then run client side of test by `npm run e2e-android`, thus an apk will be installed to android automatically and complete the test. -This will auto replace the ip, and then run the react-native packager. +If `npm install -g appium` is unavailable in china, ref to [node_modules-appium](https://github.com/flyskywhy/node_modules-appium) . -## ScreenShots +## Screenshots ![noder](http://7lrzfj.com1.z0.glb.clouddn.com/soliurynoder-v1.0.0.gif) +## React-Native Modules In Using -## React-Native Modules Used - +* [redux](https://github.com/gaearon/redux) * [react-native-button](https://github.com/ide/react-native-button) +* [react-native-barcodescanner](https://github.com/ideacreation/react-native-barcodescanner) +* [react-native-blur](https://github.com/react-native-fellowship/react-native-blur) * [react-native-camera](https://github.com/lwansbrough/react-native-camera) -* [react-native-icons](https://github.com/corymsmith/react-native-icons) -* [react-native-keyboardevents](https://github.com/johanneslumpe/react-native-keyboardevents) -* [react-native-modal](https://github.com/brentvatne/react-native-modal) -* [react-native-overlay](https://github.com/brentvatne/react-native-overlay) +* [react-native-html-render](https://github.com/soliury/react-native-html-render) * [react-native-scrollable-tab-view](https://github.com/brentvatne/react-native-scrollable-tab-view) +* [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons) -Thanks All above. +This project is heavily influenced by the above modules. ## ToDo List -* Add Push Notification -* Refactor code -* Solve the big bug - * ***In ListView, sometime scroll on the bottom it can't refresh*** +* Push Notification +* Fix the below bugs + * In ListView, sometime items on the bottom can't be refreshed * ListView **take too much memory** - * HTML to native View render take too much **memory and time** -* Push to App Store -* Add test + * HTML to native View render take too much **memory and CPU time** +* Add Unit testing ## Change log -See [CHANGELOG]() +Please read [CHANGELOG](https://github.com/soliury/noder-react-native/releases) ## Contribute -If you find any bugs, just solve it and submit a PR. +If you find any issues, just solve it and make a PR. -About the code style, Please use the ES6 JSX. +This project is under the ES6 JSX. ## License [MIT License](http://en.wikipedia.org/wiki/MIT_License) - - - - - - - - - diff --git a/Source/logo/IOS/noder-Icon.png b/Source/logo/IOS/noder-Icon.png deleted file mode 100644 index fb12b90d..00000000 Binary files a/Source/logo/IOS/noder-Icon.png and /dev/null differ diff --git a/__tests__/App.js b/__tests__/App.js new file mode 100644 index 00000000..c826d921 --- /dev/null +++ b/__tests__/App.js @@ -0,0 +1,12 @@ +import 'react-native'; +import React from 'react'; +import App from '../src'; + +// Note: test renderer must be required after react-native. +import renderer from 'react-test-renderer'; + +it('renders correctly', () => { + const tree = renderer.create( + + ); +}); diff --git a/android/app/BUCK b/android/app/BUCK new file mode 100644 index 00000000..a5889233 --- /dev/null +++ b/android/app/BUCK @@ -0,0 +1,65 @@ +# To learn about Buck see [Docs](https://buckbuild.com/). +# To run your application with Buck: +# - install Buck +# - `npm start` - to start the packager +# - `cd android` +# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` +# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck +# - `buck install -r android/app` - compile, install and run application +# + +lib_deps = [] + +for jarfile in glob(['libs/*.jar']): + name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] + lib_deps.append(':' + name) + prebuilt_jar( + name = name, + binary_jar = jarfile, + ) + +for aarfile in glob(['libs/*.aar']): + name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] + lib_deps.append(':' + name) + android_prebuilt_aar( + name = name, + aar = aarfile, + ) + +android_library( + name = "all-libs", + exported_deps = lib_deps, +) + +android_library( + name = "app-code", + srcs = glob([ + "src/main/java/**/*.java", + ]), + deps = [ + ":all-libs", + ":build_config", + ":res", + ], +) + +android_build_config( + name = "build_config", + package = "com.noder", +) + +android_resource( + name = "res", + package = "com.noder", + res = "src/main/res", +) + +android_binary( + name = "app", + keystore = "//android/keystores:debug", + manifest = "src/main/AndroidManifest.xml", + package_type = "debug", + deps = [ + ":app-code", + ], +) diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 00000000..b4a91423 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,180 @@ +apply plugin: "com.android.application" + +import com.android.build.OutputFile + +/** + * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets + * and bundleReleaseJsAndAssets). + * These basically call `react-native bundle` with the correct arguments during the Android build + * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the + * bundle directly from the development server. Below you can see all the possible configurations + * and their defaults. If you decide to add a configuration block, make sure to add it before the + * `apply from: "../../node_modules/react-native/react.gradle"` line. + * + * project.ext.react = [ + * // the name of the generated asset file containing your JS bundle + * bundleAssetName: "index.android.bundle", + * + * // the entry file for bundle generation + * entryFile: "index.android.js", + * + * // whether to bundle JS and assets in debug mode + * bundleInDebug: false, + * + * // whether to bundle JS and assets in release mode + * bundleInRelease: true, + * + * // whether to bundle JS and assets in another build variant (if configured). + * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants + * // The configuration property can be in the following formats + * // 'bundleIn${productFlavor}${buildType}' + * // 'bundleIn${buildType}' + * // bundleInFreeDebug: true, + * // bundleInPaidRelease: true, + * // bundleInBeta: true, + * + * // whether to disable dev mode in custom build variants (by default only disabled in release) + * // for example: to disable dev mode in the staging build type (if configured) + * devDisabledInStaging: true, + * // The configuration property can be in the following formats + * // 'devDisabledIn${productFlavor}${buildType}' + * // 'devDisabledIn${buildType}' + * + * // the root of your project, i.e. where "package.json" lives + * root: "../../", + * + * // where to put the JS bundle asset in debug mode + * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", + * + * // where to put the JS bundle asset in release mode + * jsBundleDirRelease: "$buildDir/intermediates/assets/release", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in debug mode + * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", + * + * // where to put drawable resources / React Native assets, e.g. the ones you use via + * // require('./image.png')), in release mode + * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", + * + * // by default the gradle tasks are skipped if none of the JS files or assets change; this means + * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to + * // date; if you have any other folders that you want to ignore for performance reasons (gradle + * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ + * // for example, you might want to remove it from here. + * inputExcludes: ["android/**", "ios/**"], + * + * // override which node gets called and with what additional arguments + * nodeExecutableAndArgs: ["node"], + * + * // supply additional arguments to the packager + * extraPackagerArgs: [] + * ] + */ + +project.ext.react = [ + entryFile: "index.android.js" +] + +apply from: "../../node_modules/react-native/react.gradle" +apply from: "../../node_modules/react-native-code-push/android/codepush.gradle" + +/** + * Set this to true to create two separate APKs instead of one: + * - An APK that only works on ARM devices + * - An APK that only works on x86 devices + * The advantage is the size of the APK is reduced by about 4MB. + * Upload all the APKs to the Play Store and people will download + * the correct one based on the CPU architecture of their device. + */ +def enableSeparateBuildPerCPUArchitecture = false + +/** + * Run Proguard to shrink the Java bytecode in release builds. + */ +def enableProguardInReleaseBuilds = false + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.1" + + defaultConfig { + applicationId "com.lingyong.me.noder" + minSdkVersion 16 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + ndk { + abiFilters "armeabi-v7a", "x86" + } + } + splits { + abi { + reset() + enable enableSeparateBuildPerCPUArchitecture + universalApk false // If true, also generate a universal APK + include "armeabi-v7a", "x86" + } + } + + signingConfigs { + release { + storeFile file(MYAPP_RELEASE_STORE_FILE) + storePassword MYAPP_RELEASE_STORE_PASSWORD + keyAlias MYAPP_RELEASE_KEY_ALIAS + keyPassword MYAPP_RELEASE_KEY_PASSWORD + } + } + + buildTypes { + release { + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + signingConfig signingConfigs.release + } + } + // applicationVariants are e.g. debug, release + applicationVariants.all { variant -> + variant.outputs.each { output -> + // For each separate APK per architecture, set a unique version code as described here: + // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits + def versionCodes = ["armeabi-v7a":1, "x86":2] + def abi = output.getFilter(OutputFile.ABI) + if (abi != null) { // null for the universal-debug, universal-release variants + output.versionCodeOverride = + versionCodes.get(abi) * 1048576 + defaultConfig.versionCode + } + } + } +} + +repositories { + maven { url 'https://github.com/500px/500px-android-blur/raw/master/releases/' } +} + +dependencies { + compile project(':react-native-blur') + compile project(':react-native-code-push') + compile project(':react-native-vector-icons') + compile project(':react-native-camera') + compile project(':react-native-barcodescanner') + compile fileTree(dir: "libs", include: ["*.jar"]) + compile "com.android.support:appcompat-v7:23.0.1" + compile "com.facebook.react:react-native:+" // From node_modules +} + +buildscript { + repositories { + maven { url 'https://github.com/500px/500px-android-blur/raw/master/releases/' } + } + dependencies { + classpath 'com.fivehundredpx:blurringview:1.0.0' + } +} + +// Run this once to be able to run the application with BUCK +// puts all compile dependencies into folder libs for BUCK to use +task copyDownloadableDepsToLibs(type: Copy) { + from configurations.compile + into 'libs' +} diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 00000000..6e8516c8 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,70 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Disabling obfuscation is useful if you collect stack traces from production crashes +# (unless you are using a system that supports de-obfuscate the stack traces). +-dontobfuscate + +# React Native + +# Keep our interfaces so they can be used by other ProGuard rules. +# See http://sourceforge.net/p/proguard/bugs/466/ +-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip +-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters +-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip + +# Do not strip any method/class that is annotated with @DoNotStrip +-keep @com.facebook.proguard.annotations.DoNotStrip class * +-keep @com.facebook.common.internal.DoNotStrip class * +-keepclassmembers class * { + @com.facebook.proguard.annotations.DoNotStrip *; + @com.facebook.common.internal.DoNotStrip *; +} + +-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { + void set*(***); + *** get*(); +} + +-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } +-keep class * extends com.facebook.react.bridge.NativeModule { *; } +-keepclassmembers,includedescriptorclasses class * { native ; } +-keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } +-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } +-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } + +-dontwarn com.facebook.react.** + +# TextLayoutBuilder uses a non-public Android constructor within StaticLayout. +# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. +-dontwarn android.text.StaticLayout + +# okhttp + +-keepattributes Signature +-keepattributes *Annotation* +-keep class okhttp3.** { *; } +-keep interface okhttp3.** { *; } +-dontwarn okhttp3.** + +# okio + +-keep class sun.misc.Unsafe { *; } +-dontwarn java.nio.file.* +-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement +-dontwarn okio.** diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..404765d0 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/assets/fonts/Entypo.ttf b/android/app/src/main/assets/fonts/Entypo.ttf new file mode 100644 index 00000000..1c8f5e91 Binary files /dev/null and b/android/app/src/main/assets/fonts/Entypo.ttf differ diff --git a/android/app/src/main/assets/fonts/EvilIcons.ttf b/android/app/src/main/assets/fonts/EvilIcons.ttf new file mode 100644 index 00000000..b270f985 Binary files /dev/null and b/android/app/src/main/assets/fonts/EvilIcons.ttf differ diff --git a/android/app/src/main/assets/fonts/FontAwesome.ttf b/android/app/src/main/assets/fonts/FontAwesome.ttf new file mode 100644 index 00000000..f221e50a Binary files /dev/null and b/android/app/src/main/assets/fonts/FontAwesome.ttf differ diff --git a/android/app/src/main/assets/fonts/Foundation.ttf b/android/app/src/main/assets/fonts/Foundation.ttf new file mode 100644 index 00000000..6cce217d Binary files /dev/null and b/android/app/src/main/assets/fonts/Foundation.ttf differ diff --git a/android/app/src/main/assets/fonts/Ionicons.ttf b/android/app/src/main/assets/fonts/Ionicons.ttf new file mode 100644 index 00000000..307ad889 Binary files /dev/null and b/android/app/src/main/assets/fonts/Ionicons.ttf differ diff --git a/android/app/src/main/assets/fonts/MaterialIcons.ttf b/android/app/src/main/assets/fonts/MaterialIcons.ttf new file mode 100644 index 00000000..7015564a Binary files /dev/null and b/android/app/src/main/assets/fonts/MaterialIcons.ttf differ diff --git a/android/app/src/main/assets/fonts/Octicons.ttf b/android/app/src/main/assets/fonts/Octicons.ttf new file mode 100644 index 00000000..0a62bb9e Binary files /dev/null and b/android/app/src/main/assets/fonts/Octicons.ttf differ diff --git a/android/app/src/main/assets/fonts/Zocial.ttf b/android/app/src/main/assets/fonts/Zocial.ttf new file mode 100644 index 00000000..e4ae46c6 Binary files /dev/null and b/android/app/src/main/assets/fonts/Zocial.ttf differ diff --git a/android/app/src/main/java/com/noder/MainActivity.java b/android/app/src/main/java/com/noder/MainActivity.java new file mode 100644 index 00000000..2b3a3edf --- /dev/null +++ b/android/app/src/main/java/com/noder/MainActivity.java @@ -0,0 +1,15 @@ +package com.lingyong.me.noder; + +import com.facebook.react.ReactActivity; + +public class MainActivity extends ReactActivity { + + /** + * Returns the name of the main component registered from JavaScript. + * This is used to schedule rendering of the component. + */ + @Override + protected String getMainComponentName() { + return "noder"; + } +} diff --git a/android/app/src/main/java/com/noder/MainApplication.java b/android/app/src/main/java/com/noder/MainApplication.java new file mode 100644 index 00000000..1b87c7d9 --- /dev/null +++ b/android/app/src/main/java/com/noder/MainApplication.java @@ -0,0 +1,61 @@ +package com.lingyong.me.noder; + +import android.app.Application; + +import com.facebook.react.ReactApplication; +import com.microsoft.codepush.react.CodePush; +import com.oblador.vectoricons.VectorIconsPackage; +import com.lwansbrough.RCTCamera.RCTCameraPackage; +import com.eguma.barcodescanner.BarcodeScannerPackage; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.shell.MainReactPackage; +import com.facebook.soloader.SoLoader; + +import java.util.Arrays; +import java.util.List; + +public class MainApplication extends Application implements ReactApplication { + + private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + // 2. Override the getJSBundleFile method in order to let + // the CodePush runtime determine where to get the JS + // bundle location from on each app start + @Override + protected String getJSBundleFile() { + return CodePush.getBundleUrl(); + } + + @Override + protected List getPackages() { + return Arrays.asList( + new MainReactPackage(), + new CodePush("Q2A8khx6JV4mXXcS0usR0LipDz0Y410YoZxlZ", MainApplication.this, BuildConfig.DEBUG), + new VectorIconsPackage(), + new RCTCameraPackage(), + new BarcodeScannerPackage() + ); + } + + @Override + protected String getJSMainModuleName() { + return "index.android"; + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + @Override + public void onCreate() { + super.onCreate(); + SoLoader.init(this, /* native exopackage */ false); + } +} diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..f948e794 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-ldpi/ic_launcher.png b/android/app/src/main/res/mipmap-ldpi/ic_launcher.png new file mode 100644 index 00000000..a53c8266 Binary files /dev/null and b/android/app/src/main/res/mipmap-ldpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..8f1eaf4a Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..593d85f2 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..53852d46 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..eae25d24 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/playstore-icon.png b/android/app/src/main/res/playstore-icon.png new file mode 100644 index 00000000..ec0ea23f Binary files /dev/null and b/android/app/src/main/res/playstore-icon.png differ diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..3b45fa55 --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Noder + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..6975b5af --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 00000000..eed9972b --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,24 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.2.3' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + mavenLocal() + jcenter() + maven { + // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm + url "$rootDir/../node_modules/react-native/android" + } + } +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 00000000..1fd964e9 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,20 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +android.useDeprecatedNdk=true diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..b5166dad Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..dbdc05d2 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/android/gradlew b/android/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/keystores/BUCK b/android/keystores/BUCK new file mode 100644 index 00000000..88e4c31b --- /dev/null +++ b/android/keystores/BUCK @@ -0,0 +1,8 @@ +keystore( + name = "debug", + properties = "debug.keystore.properties", + store = "debug.keystore", + visibility = [ + "PUBLIC", + ], +) diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 00000000..f98de997 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,13 @@ +rootProject.name = 'noder' + +include ':app' +include ':react-native-blur' +project(':react-native-blur').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-blur/android') +include ':react-native-barcodescanner' +project(':react-native-barcodescanner').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-barcodescanner/android') +include ':react-native-camera' +project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android') +include ':react-native-vector-icons' +project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') +include ':react-native-code-push' +project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app') diff --git a/app.json b/app.json new file mode 100644 index 00000000..4e3400c8 --- /dev/null +++ b/app.json @@ -0,0 +1,4 @@ +{ + "name": "noder", + "displayName": "noder" +} \ No newline at end of file diff --git a/app/actions/HomeActions.js b/app/actions/HomeActions.js deleted file mode 100644 index bda98dbb..00000000 --- a/app/actions/HomeActions.js +++ /dev/null @@ -1,21 +0,0 @@ -var types = require('../constants/ActionTypes') -var UserService = require('../services/UserService') -var window = require('../util/window') - - -exports.openLoginModal = function openLoginModal() { - return { - type: types.OPEN_LOGIN_MODAL, - isModalOpen: true - } -} - -exports.closeLoginModal = function closeLoginModal() { - return { - type: types.CLOSE_LOGIN_MODAL, - isModalOpen: false - } -} - - - diff --git a/app/actions/MessageActions.js b/app/actions/MessageActions.js deleted file mode 100644 index f3bb76b9..00000000 --- a/app/actions/MessageActions.js +++ /dev/null @@ -1,127 +0,0 @@ -var types = require('../constants/ActionTypes') -var MessageService = require('../services/MessageService') - - -var window = require('../util/window') - - -function getMessages(messages) { - return { - type: types.GET_MESSAGES, - hasRead: messages.has_read_messages, - hasNotRead: messages.hasnot_read_messages, - isLoading: true - } -} - -function fetchMessagesRequest() { - return { - type: types.FETCH_MESSAGES_REQUEST, - isLoading: true - } -} - -function fetchMessagesSuccess(messages) { - return { - type: types.FETCH_MESSAGES_SUCCESS, - isLoading: false, - hasRead: messages.has_read_messages, - hasNotRead: messages.hasnot_read_messages, - } -} - -function fetchMessagesFailed(err) { - return { - type: types.FETCH_MESSAGES_FAILED, - isLoading: false, - err: err - } -} - -exports.getUnreadMessageCount = function (token) { - return dispatch=> { - MessageService.req.getUnreadMessageCount(token) - .then(count=> { - dispatch({ - type: types.GET_UNREAD_MESSAGE_COUNT_SUCCESS, - count: count - }) - }) - .catch(err=> { - console.warn(err) - }) - .done() - } -} - - -exports.getMessages = function (token) { - return dispatch=> { - - dispatch(fetchMessagesRequest()) - - MessageService.storage.get() - .then(messages=> { - if (messages) { - dispatch(getMessages(messages)) - } - return MessageService.req.get(token) - }) - .then(messages=> { - if (messages) { - dispatch(fetchMessagesSuccess(messages)) - } - else { - throw 'FETCH_MESSAGES_FAILED' - } - }) - .catch(err=> { - dispatch(fetchMessagesFailed(err)) - }) - .done() - } -} - - -exports.fetchMessages = function (token) { - return dispatch=> { - dispatch(fetchMessagesRequest()) - - MessageService.req.get(token) - .then(messages=> { - if (messages) { - dispatch(fetchMessagesSuccess(messages)) - } - else { - throw 'FETCH_MESSAGES_FAILED' - } - }) - .catch(err=> { - dispatch(fetchMessagesFailed(err)) - }) - .done() - } -} - - -exports.markAsRead = function (token) { - return dispatch=> { - dispatch({ - type: types.MARK_AS_READ_REQUEST - }) - MessageService.req.markAsRead(token) - .then(()=> { - dispatch({ - type: types.MARK_AS_READ_SUCCESS - }) - window.alert('已全部标记为已读!') - }) - .catch(()=> { - dispatch({ - type: types.MARK_AS_READ_FAILED - }) - window.alert('标记失败!') - }) - .done() - } -} diff --git a/app/actions/TopicActions.js b/app/actions/TopicActions.js deleted file mode 100644 index 4afed3c9..00000000 --- a/app/actions/TopicActions.js +++ /dev/null @@ -1,37 +0,0 @@ -var types = require('../constants/ActionTypes') -var TopicService = require('../services/TopicService') - - -exports.getAllTopicsFromStorage = function () { - return dispatch=> { - TopicService.storage.getAll() - .then(results=> { - dispatch({ - type: types.GET_ALL_TOPICS_FROM_STORAGE, - results: results - }) - }) - .catch(err=> { - - }) - .done() - } -} - - -exports.getTopicsByTab = function (topics, tab) { - return { - type: types.GET_TOPICS, - topics: topics, - tab: tab - } -} - - -exports.updateTopicsByTab = function (topics, tab) { - return { - type: types.UPDATE_TOPICS, - topics: topics, - tab: tab - } -} diff --git a/app/actions/UserActions.js b/app/actions/UserActions.js deleted file mode 100644 index d6e9ffb5..00000000 --- a/app/actions/UserActions.js +++ /dev/null @@ -1,139 +0,0 @@ -var types = require('../constants/ActionTypes') -var UserService = require('../services/UserService') -var TopicService = require('../services/TopicService') -var MessageService = require('../services/MessageService') -var Storage = require('../services/Storage') - - -function getUser(user) { - return { - type: types.GET_USER, - user: user - } -} - - -exports.getLoginUserFromStorage = function () { - return dispatch=> { - var userTemp = {} - UserService.storage.getUser() - .then((user)=> { - // console.log('haveLoadedUser'); - if (user) { - dispatch(getUser(user)) - userTemp = user - return UserService.req.getLoginUserInfo(user) - } - else { - throw 'GET_LOGIN_USER_FROM_STORAGE_FAILED' - } - - }) - .then(userFetched=> { - // console.log('fetchUser'); - if (userFetched) { - var userUpdated = Object.assign(userTemp, userFetched) - UserService.storage.saveUser(userUpdated) - dispatch(getUser(userTemp)) - } - }) - .catch((err)=> { - console.warn(err) - }) - .done() - } -} - - -exports.fetchUser = function fetchUser(user) { - return dispatch => { - UserService.req.getLoginUserInfo(user) - .then(userInfo=> { - if (userInfo) { - Object.assign(user, userInfo) - UserService.storage.saveUser(user) - dispatch(getUser(user)) - } - }) - .catch(err=> { - console.warn(err) - }) - .done() - } -} - - -exports.checkToken = function (token) { - return dispatch=> { - var userTemp = {} - dispatch({ - type: types.CHECK_TOKEN_REQUREST - }) - UserService.req.checkToken(token) - .then(user=> { - userTemp = user - return UserService.req.getLoginUserInfo(user) - }) - .then((userInfo)=> { - if (userInfo) { - Object.assign(userTemp, userInfo) - UserService.storage.saveUser(userTemp) - dispatch(getUser(userTemp)) - dispatch({ - type: types.CHECK_TOKEN_SUCCESS, - isModalOpen: false - }) - } - else { - throw 'CHECK_TOKEN_FAILED' - } - }) - .catch(function (err) { - console.warn(err) - dispatch({ - type: types.CHECK_TOKEN_FAILED, - err: err - }) - window.alert('token验证失败') - }) - .done() - } -} - - -exports.likeTopic = function (topic) { - return { - type: types.LIKE_TOPIC, - topic: { - id: topic.id, - author: topic.author, - title: topic.title, - last_reply_at: topic.last_reply_at - } - } -} - - -exports.unLikeTopic = function (id) { - return { - type: types.UN_LIKE_TOPIC, - id: id - } -} - - -exports.logout = function () { - UserService.storage.clearUser() - return { - type: types.LOGOUT - } -} - - -exports.clear = function () { - TopicService.storage.remove() - MessageService.storage.remove() - return { - type: types.CLEAR - } -} diff --git a/app/actions/index.js b/app/actions/index.js deleted file mode 100644 index 7e78d955..00000000 --- a/app/actions/index.js +++ /dev/null @@ -1,10 +0,0 @@ -var user = require('./UserActions') -var home = require('./HomeActions') -var message = require('./MessageActions') -var topic = require('./TopicActions') - -var actions = {} - -Object.assign(actions, user, home, message, topic) - -module.exports = actions diff --git a/app/components/LikeIcon.js b/app/components/LikeIcon.js deleted file mode 100644 index 183877d6..00000000 --- a/app/components/LikeIcon.js +++ /dev/null @@ -1,117 +0,0 @@ -var React = require('react-native') -var { Icon, } = require('react-native-icons') - -var topicService = require('../services/TopicService') - - -var { - View, - Component, - TouchableOpacity, - StyleSheet, - ActivityIndicatorIOS - } = React - - -class LikeIcon extends Component { - constructor(props) { - super(props) - var userInfo = this.props.user - var isLiked - if (userInfo && userInfo.collect_topics) { - isLiked = this._isLiked(userInfo.collect_topics) - } - this.state = { - isLoading: false, - isLiked: isLiked - } - } - - componentWillReceiveProps(nextProps) { - var userInfo = nextProps.user - var isLiked - if (userInfo && userInfo.collect_topics) { - isLiked = this._isLiked(userInfo.collect_topics) - } - this.setState({ - isLiked: isLiked - }) - } - - - _isLiked(collections) { - var id = this.props.topic.id - return collections.some(function (item) { - return item.id == id - }) - } - - - _onLikedPress() { - if (!this.props.user || this.state.isLoading) { - return - } - this.setState({ - isLoading: true - }) - - let topic = this.props.topic - - - topicService.req.markTopicAsLike(topic.id, this.props.user.token, this.state.isLiked) - .then(() => { - let actions = this.props.actions - let likeTopic = actions.likeTopic - let unLikeTopic = actions.unLikeTopic - - !this.state.isLiked ? likeTopic(topic) : unLikeTopic(topic.id) - - this.setState({ - isLoading: false - }) - - }) - .catch(err => { - console.warn(err) - this.setState({ - isLoading: false - }) - }) - .done() - } - - - _renderIcon() { - if (this.state.isLoading) { - return ( - - - - ) - } - return ( - - ) - } - - - render() { - return ( - - {this._renderIcon()} - - ) - } -} - - -module.exports = LikeIcon diff --git a/app/components/Login.js b/app/components/Login.js deleted file mode 100644 index ff0e36b4..00000000 --- a/app/components/Login.js +++ /dev/null @@ -1,197 +0,0 @@ -var React = require('react-native') -var Modal = require('react-native-modal') -var Button = require('react-native-button') -var { Icon, } = require('react-native-icons') - - -var window = require('../util/window') -var { width, height } = window.get() - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - Image, - ListView, - TouchableHighlight, - Navigator, - AsyncStorage, - ActivityIndicatorIOS - } = React; - - -var styles = StyleSheet.create({ - wrapper: { - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'space-between', - height: 40, - backgroundColor: 'transparent' - }, - row: { - height: 40, - backgroundColor: '#3498DB', - paddingTop: 10, - paddingBottom: 10, - paddingLeft: 20, - paddingRight: 20, - flexDirection: 'row', - alignItems: 'center', - borderRadius: 2 - }, - button: { - flexDirection: 'row', - alignItems: 'center' - }, - icon: { - height: 40, - width: 30, - marginRight: 10 - }, - closeIcon: { - height: 20, - width: 20 - }, - closeButton: { - position: 'absolute', - //borderColor: 'rgba(255,255,255,0.6)', - borderRadius: 2, - //borderWidth: 1, - right: 20, - top: 20, - paddingLeft: 10, - paddingRight: 10, - paddingTop: 10, - paddingBottom: 5, - }, - buttonText: { - color: 'rgba(255,255,255,0.8)' - }, - loading: { - paddingRight: 40, - paddingLeft: 40, - paddingTop: 10, - paddingBottom: 10 - } -}) - -var modalStyles = StyleSheet.create({ - container: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - backgroundColor: 'transparent', - justifyContent: 'center', - }, - backdrop: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - backgroundColor: '#000000', - opacity: 0.5, - }, - modal: { - backgroundColor: 'rgba(0,0,0,0.3)', - borderRadius: 3, - borderWidth: 2, - borderColor: 'rgba(255,255,255,0.3)', - paddingTop: 40, - paddingBottom: 40, - margin: 20 - } -}); - -class Login extends Component { - constructor(props) { - super(props) - } - - - closeModal() { - this.props.actions.closeLoginModal() - } - - - _onLoginPress() { - if (this.props.checkTokenLoading) return - this.props.router.toQRCode() - } - - - _getCustomCloseButton() { - return ( - - - - ) - } - - - _renderLoginButton() { - if (this.props.checkTokenLoading) { - return ( - - ) - } - return ( - - ) - } - - - render() { - - return ( - this.closeModal()}> - - - - - {this._renderLoginButton()} - - - - ) - } - - -} - - -module.exports = Login diff --git a/app/components/MessagePage.js b/app/components/MessagePage.js deleted file mode 100644 index a962fbb8..00000000 --- a/app/components/MessagePage.js +++ /dev/null @@ -1,263 +0,0 @@ -var React = require('react-native') -var moment = require('moment') - - -var window = require('../util/window') -var { width, height } = window.get() - - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - Image, - ListView, - ActivityIndicatorIOS, - TouchableHighlight, - Navigator - } = React - - -var styles = StyleSheet.create({ - "row": { - "height": 90, - "flexDirection": "row", - "borderBottomColor": "rgba(0, 0, 0, 0.02)", - "borderBottomWidth": 1, - "paddingTop": 25, - "paddingRight": 0, - "paddingBottom": 25, - "paddingLeft": 20 - }, - "imgWrapper": { - "width": 90, - "position": "absolute", - "left": 20, - "top": 25, - "height": 65 - }, - "img": { - "height": 40, - "width": 40, - "borderRadius": 20 - }, - "topic": { - "marginLeft": 60 - }, - "title": { - "fontSize": 15 - }, - "topicFooter": { - "marginTop": 10, - "flexDirection": "row", - width: width - (20 + 90) - }, - "topicFooter text": { - "fontSize": 11, - "color": "rgba(0, 0, 0, 0.4)" - }, - "topicFooter date": { - "position": "absolute", - "right": 0, - "top": 0 - }, - "topicFooter count": { - "marginRight": 15 - }, - "topicFooter top": { - "fontSize": 11, - "marginTop": 1, - "marginRight": 0, - "marginBottom": 0, - "marginLeft": 10, - "color": "#E74C3C" - }, - "topicFooter good": { - "fontSize": 11, - "marginTop": 1, - "marginRight": 0, - "marginBottom": 0, - "marginLeft": 10, - "color": "#2ECC71" - }, - "topicFooter tab": { - "fontSize": 11, - "marginTop": 1, - "marginRight": 0, - "marginBottom": 0, - "marginLeft": 10 - }, - "loading": { - "marginTop": 250 - }, - rowFooterText: { - fontSize: 13, - color: 'rgba(0,0,0,0.7)' - }, - atText: { - color: '#E74C3C' - }, - replyText: { - color: '#2980B9' - }, - emptyMessage: { - marginTop: 80, - flex: 1 - }, - emptyMessageText: { - textAlign: 'center', - color: '#3498DB', - fontSize: 24 - } - -}) - - -class MessagePage extends Component { - constructor(props) { - super(props) - this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) - this.state = { - ds: this.ds.cloneWithRows(this.props.data) - } - } - - - componentWillReceiveProps(nextProps) { - if (nextProps.data != this.props.data) { - this.setState({ - ds: this.ds.cloneWithRows(nextProps.data) - }) - } - } - - - _onRowPress(message) { - this.props.router.toComments({ - topic: message.topic, - from: 'message', - reply: message.reply - }) - } - - - _renderRowFooter(message) { - var date = moment(message.reply.create_at).startOf('minute').fromNow() - - return ( - - - - {message.author.loginname} - - - {message.type == 'reply' ? ' 回复' : ' @'} - - - - - {date} - - - ) - } - - - _renderLoading() { - if (this.props.isLoading) { - return ( - - ) - } - return null; - } - - - _renderRow(message) { - var topic = message.topic - var title = topic.title - var titleLength = Math.floor((width - 100) / 15) + 2 - if (title.length > titleLength) { - title = title.substring(0, titleLength - 3) + '...' - } - - - return ( - {this._onRowPress(message)}} - underlayColor='#3498DB' - key={message.id}> - - - - - - - - - {title} - - - - {this._renderRowFooter(message)} - - - - - ) - } - - - _renderEmptyMessage() { - if (this.props.data.length == 0 && this.props.isLoading == false) { - return ( - - - 空空哒 - - - ) - } - } - - - _renderListView() { - if (this.props.didFocus) { - return ( - - ) - } - return null - } - - - render() { - return ( - - {this._renderLoading()} - {this._renderEmptyMessage()} - {this._renderListView()} - - ) - } -} - - -module.exports = MessagePage diff --git a/app/components/Nav.js b/app/components/Nav.js deleted file mode 100644 index 7a89e538..00000000 --- a/app/components/Nav.js +++ /dev/null @@ -1,95 +0,0 @@ -var React = require('react-native') - -var window = require('../util/window') -var { width, height } = window.get() - - -var { - Component, - View, - Text, - StyleSheet, - TouchableOpacity - } = React - - -class Nav extends Component { - constructor(props) { - super(props) - } - - - _renderNavContent() { - var navs = this.props.navs || {} - - return ['Left', 'Center', 'Right'].map((position)=> { - var nav = navs[position] - if (nav) { - return ( - - - {nav.text} - - - ) - } - return ( - - - ) - }) - } - - - render() { - return ( - this.nav=view} - style={styles.nav}> - - {this._renderNavContent()} - - - ) - } -} - - -var navHeight = 55 - - -var styles = StyleSheet.create({ - nav: { - height: navHeight, - width: width, - borderBottomColor: 'rgba(0,0,0,0.03)', - borderBottomWidth: 1, - flexDirection: 'row', - justifyContent: 'center', - alignItems: 'center' - }, - navItem: { - color: 'rgba(0,0,0,0.7)', - fontSize: 16 - }, - navLeft: { - textAlign: 'left', - paddingLeft: 15, - flex: 1 - }, - navRight: { - textAlign: 'right', - paddingRight: 15, - flex: 1 - }, - navCenter: { - textAlign: 'center', - flex: 2, - color: '#3498DB' - } -}) - -Nav.navHeight = navHeight -module.exports = Nav diff --git a/app/components/PageListView.js b/app/components/PageListView.js deleted file mode 100644 index ff553f0f..00000000 --- a/app/components/PageListView.js +++ /dev/null @@ -1,403 +0,0 @@ -var React = require('react-native') -var moment = require('moment') - -var TopicService = require('../services/TopicService') -var TopicRow = require('./TopicRow') - -var window = require('../util/window') - - -var { width, height } = window.get() - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - Image, - ListView, - ActivityIndicatorIOS, - TouchableHighlight, - LayoutAnimation, - TouchableOpacity - } = React - - -var extendsStyles = StyleSheet.create({ - topic: { - width: width - 100 - }, - loadingupdate: { - width: width, - marginTop: 20 - }, - loadingget: { - width: width, - marginBottom: 20, - marginTop: 20 - } -}); - -class PageListView extends Component { - constructor(porps) { - super(porps) - var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) - this.page = 1 - this.listRows = {} - this.state = { - ds: ds.cloneWithRows(this.props.data), - isLoading: false, - loadingPosition: 'top', - getTopicError: null - } - } - - - componentDidMount() { - this._fetchTopic('update') - } - - - shouldComponentUpdate(nextProps, nextState) { - if (nextProps.data != this.props.data || nextState.isLoading != this.state.isLoading) { - return true - } - return false - } - - - componentWillReceiveProps(nextProps) { - if (nextProps.data !== this.props.data) { - //console.log(this.props.data.length); - //LayoutAnimation.configureNext(LayoutAnimation.Presets.spring); - this.setState({ - ds: this.state.ds.cloneWithRows(nextProps.data) - }) - } - } - - - onEndReached() { - this._fetchTopic('get') - } - - onScroll(e) { - if (e.nativeEvent.contentOffset.y < -90) { - this._fetchTopic('update') - } - } - - scrollToTop() { - this._listView.setNativeProps({ - contentOffset: { - x: 0, - y: 0 - } - }) - } - - - _onRowPress(topic) { - this.props.router.toTopic({ - topic: topic, - from: 'home' - }) - } - - - _onChangeVisibleRows(visibleRows, changedRows) { - //let vRows = visibleRows.s1 - //let cRows = changedRows.s1 - // - //let listRows = this.listRows - - - //if (this.visibleRows) { - // for (key in cRows) { - // if (cRows[key]) { - // listRows[key].show() - // } - // else { - // listRows[key].hide() - // } - // } - //} - //else { - // this.visibleRows = vRows - //} - //listRows[3].hide() - //console.log('visibleRows:'); - //console.log(vRows); - //console.log('changedRows:'); - //console.log(cRows); - } - - - _onGetAgainPress() { - this._fetchTopic('get') - } - - - _fetchTopic(type) { - if (this.isFreshing) { - if (type == 'get') { - this.setState({ - getTopicError: 'fetchFailed' - }) - } - return - } - - - this.isFreshing = true - this.setState({ - isLoading: true, - loadingType: type - }) - - var page = (type == 'update') ? 1 : this.page + 1 - var tab = this.props.tab.name - var actions = this.props.actions - var getTopics = actions.getTopicsByTab - var updateTopics = actions.updateTopicsByTab - - TopicService.req.getTopicsByTab({ - page: page, - tab: tab, - limit: 10 - }) - .then(topics=> { - LayoutAnimation.configureNext(LayoutAnimation.Presets.spring) - type == 'update' ? updateTopics(topics, tab) : getTopics(topics, tab) - return null - }) - .catch(err=> { - console.warn(err) - if (type == 'get') { - return err - } - }) - .done((err)=> { - this.isFreshing = false - this.setState({ - isLoading: false, - err: err - }) - this.page = page - }) - } - - - _renderLoading(loadingType) { - return ( - - ) - } - - - _renderTopicFooter(topic) { - var renderArr = []; - var navs = { - ask: '问答', - share: '分享', - job: '招聘' - } - var tab = navs[topic.tab] || '分享'; - var date = moment(topic.last_reply_at).startOf('minute').fromNow(); - - - renderArr.push( - - {topic.reply_count + ' / ' + topic.visit_count} - - ); - renderArr.push( - - {tab} - - ); - - renderArr.push( - - {date} - - ); - - if (topic.top) { - renderArr.push( - - {'顶'} - - ); - } - if (topic.good) { - renderArr.push( - - {'精'} - - ); - } - return renderArr; - - } - - - _renderHeader() { - if (this.state.isLoading && this.state.loadingType == 'update') { - return this._renderLoading('update') - } - - return null - } - - - _renderFooter() { - if (this.state.isLoading && this.state.loadingType == 'get') { - return this._renderLoading('get') - } - return null - } - - - renderRow(topic, sectionId, rowId, highlightRow) { - var isVisible = false - if (rowId < 10) isVisible = true - return ( - this.listRows[rowId.toString()]=view} - key={topic.id} - onPress={this._onRowPress.bind(this)} - topic={topic} - footer={this._renderTopicFooter(topic)} - > - ) - } - - - render() { - return ( - - {this._listView = view}} - style={{backgroundColor:'rgba(255,255,255,1)'}} - onScroll={this.onScroll.bind(this)} - showsVerticalScrollIndicator={true} - initialListSize={10} - pagingEnabled={false} - removeClippedSubviews={true} - dataSource={this.state.ds} - renderRow={this.renderRow.bind(this)} - onEndReached={this.onEndReached.bind(this)} - scrollRenderAheadDistance={90} - renderHeader={this._renderHeader.bind(this)} - renderFooter={this._renderFooter.bind(this)} - //onChangeVisibleRows={this._onChangeVisibleRows.bind(this)} - /> - - ) - } -} - - -var styles = StyleSheet.create({ - "row": { - "height": 90, - "flexDirection": "row", - "borderBottomColor": "rgba(0, 0, 0, 0.02)", - "borderBottomWidth": 1, - "paddingTop": 25, - "paddingRight": 0, - "paddingBottom": 25, - "paddingLeft": 20 - }, - "imgWrapper": { - "width": 90, - "position": "absolute", - "left": 20, - "top": 25, - "height": 65 - }, - "img": { - "height": 40, - "width": 40, - "borderRadius": 20 - }, - "topic": { - "marginLeft": 60 - }, - "title": { - "fontSize": 15 - }, - "topicFooter": { - "marginTop": 12, - "flexDirection": "row" - }, - "topicFooter text": { - "fontSize": 11, - "color": "rgba(0, 0, 0, 0.5)" - }, - "topicFooter date": { - "position": "absolute", - "right": 0, - "top": 0 - }, - "topicFooter count": { - "marginRight": 15 - }, - "topicFooter top": { - "fontSize": 11, - "marginTop": 1, - "marginRight": 0, - "marginBottom": 0, - "marginLeft": 10, - "color": "#E74C3C" - }, - "topicFooter good": { - "fontSize": 11, - "marginTop": 1, - "marginRight": 0, - "marginBottom": 0, - "marginLeft": 10, - "color": "#2ECC71" - }, - "topicFooter tab": { - "fontSize": 11, - "marginTop": 1, - "marginRight": 0, - "marginBottom": 0, - "marginLeft": 10 - }, - "loading": { - "marginTop": 250 - }, - footerErrorText: { - fontSize: 20, - textAlign: 'center', - flex: 1 - }, - footerError: { - height: 76, - width: width, - flexDirection: 'column' - } -}) - -module.exports = PageListView; diff --git a/app/components/PageNavBar.js b/app/components/PageNavBar.js deleted file mode 100644 index 40b5a807..00000000 --- a/app/components/PageNavBar.js +++ /dev/null @@ -1,211 +0,0 @@ -var React = require('react-native') -var precomputeStyle = require('precomputeStyle') - - -var PageScrollView = require('./PageScrollView') - - -var window = require('../util/window') -var { width, height } = window.get() - - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - TouchableOpacity - } = React; - - -var stylesExtends = StyleSheet.create({ - navBar: { - width: width, - height: 40 - } -}); - - -class PageNavBar extends Component { - constructor(props) { - super(props) - this.state = { - offset: 0 - } - this._navBars = [] - } - - - - _getActiveItemStyle(opacity) { - return { - borderTopColor: 'rgba(241,196,15,' + opacity + ')' - } - } - - - _getNavs() { - var pageIndex = this.props.pageIndex - return this.props.navs.map((item, index, arr) => { - var activeStyle = this._getActiveItemStyle(0) - if (index == pageIndex) { - activeStyle = this._getActiveItemStyle(1) - } - - return ( - {this._navBars.push(view)}} - key={'navBar'+index} - style={[styles['navBar li'],activeStyle]}> - this.props.onItemPress(index)}> - - - {item} - - - - - ) - } - ) - } - - - _updateNavsStyle(offset) { - var space = this.props.space - this.props.navs.forEach((item, index, arr)=> { - var min = (index - 1) * space; - var max = (index + 1) * space; - var center = index * space; - - var opacity = 0; - if (offset > min && offset < center) { - opacity = (offset - min) / space; - } - if (offset > center && offset < max) { - opacity = (max - offset) / space; - } - - if (offset == center) { - opacity = 1; - } - - var activeStyle = this._getActiveItemStyle(opacity) - - this._navBars[index].setNativeProps(precomputeStyle(activeStyle)) - } - ); - } - - - // exports to another component, I don't want to use props to let many component to rerender, it's too slow - updateNav(offset) { - this.refs.navPageScrollInner.setNativeProps({ - contentOffset: { - x: offset, - y: 0 - } - }) - this._updateNavsStyle(offset) - } - - - render() { - var totalPages = this.props.totalPages; - var space = this.props.space; - - var widthStyle = { - width: { - width: (totalPages + 2) * 60 + (totalPages + 1) * (space - 60) - } - }; - - return ( - - - - - - - - - - - - - - {this._getNavs()} - - - - - - - - - - - - ) - } -} - - -var styles = StyleSheet.create({ - "navBar": { - "height": 40, - "backgroundColor": "rgba(0, 0, 0, 0.75)", - "flexDirection": "row", - "position": "absolute", - "top": 0, - "left": 0, - "alignItems": "center", - "justifyContent": "space-between" - }, - "navBar li": { - "height": 40, - "width": 60, - "flexDirection": "column", - "alignItems": "center", - "justifyContent": "space-around", - "borderTopWidth": 4, - "borderTopColor": "transparent" - }, - "navBar liActive": { - "borderTopColor": "#F1C40F" - }, - "navBar item": { - "paddingLeft": 2, - "paddingRight": 2, - "paddingTop": 12, - "paddingBottom": 0, - "height": 40 - }, - "navBar text": { - "color": "white", - "fontSize": 14 - }, - "navScroll": { - "height": 40 - } - } -) - - -module.exports = PageNavBar; diff --git a/app/components/PageScrollView.js b/app/components/PageScrollView.js deleted file mode 100644 index eee0ff39..00000000 --- a/app/components/PageScrollView.js +++ /dev/null @@ -1,92 +0,0 @@ -var React = require('react-native') -var window = require('../util/window') -var { width, height } = window.get() - - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS - } = React; - - -var stylesExtends = StyleSheet.create({ - page: { - width: width - } -}) - - -class PageScrollView extends Component { - constructor(props) { - super(props) - this.state = { - index: 0 - } - } - - _getInitContentOffset() { - return { - x: this.props.pageIndex * width, - y: 0 - }; - } - - - scrollTo(x,type) { - if(type>1){ - this.scrollView.setNativeProps({ - contentOffset: { - x: x, - y: 0 - } - } - ) - } - else{ - this.scrollView.scrollTo(0, x) - } - } - - - render() { - var self = this - return ( - this.scrollView=view} - contentOffset={this._getInitContentOffset()} - bounces={true} - horizontal={true} - directionalLockEnabled={true} - scrollEventThrottle={16} - onScroll={this.props.onScroll} - pagingEnabled={true} - onScrollBeginDrag={this.props.onScrollBeginDrag} - onScrollEndDrag={this.props.onScrollEndDrag} - scrollEnabled={true} - automaticallyAdjustContentInsets={false} - removeClippedSubviews={true} - showsHorizontalScrollIndicator={false} - showsVerticalScrollIndicator={false}> - - {this.props.children.map(function (pageContent, index) { - return ( - - {pageContent} - - ) - })} - - - ) - } - -} - - -module.exports = PageScrollView diff --git a/app/components/Setting.js b/app/components/Setting.js deleted file mode 100644 index 928dcab4..00000000 --- a/app/components/Setting.js +++ /dev/null @@ -1,195 +0,0 @@ -var React = require('react-native') -var Modal = require('react-native-modal') -var Button = require('react-native-button') -var { Icon, } = require('react-native-icons') - - -var window = require('../util/window') -var { width, height } = window.get() - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - ActivityIndicatorIOS, - TouchableOpacity - } = React - - -class Setting extends Component { - constructor(props) { - super(props) - } - - - onAboutPress() { - this.props.router.toAbout() - } - - - onLogoutPress() { - this.props.actions.logout() - this.props.router.replaceWithHome() - } - - - onClearPress() { - this.props.actions.clear() - window.alert('缓存清除成功!') - } - - - render() { - return ( - this.props.closeModal()} - hideCloseButton={true} - backdropType='blur' - backdropBlur='dark' - isVisible={this.props.isModalOpen} - onClose={() => this.props.closeModal()}> - - - - - - 设置 - - - - - - - - - 关于 - - - - - - - - - 清除缓存 - - - - - - - - - - 退出 - - - - - - - - this.props.closeModal()}> - - - - ) - } -} - - -var styles = StyleSheet.create({ - wrapper: { - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - backgroundColor: 'rgba(0,0,0,0.3)', - borderRadius: 3, - margin: 30, - width: width - 30 * 2 - }, - row: { - height: 40, - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center', - borderRadius: 2, - paddingLeft: 20, - width: width - 30 * 2, - backgroundColor: 'rgba(0,0,0,0.1)' - }, - rowText: { - paddingLeft: 20, - color: 'rgba(255,255,255,0.7)' - }, - logoutText: { - color: '#E74C3C' - }, - header: { - backgroundColor: 'rgba(0,0,0,0.5)' - }, - Icon: { - height: 20, - width: 20 - }, - closeIcon: { - height: 30, - width: 30, - borderRadius: 30 / 2, - borderColor: 'rgba(255,255,255,0.2)', - borderWidth: 2 - } -}) - -var modalStyles = StyleSheet.create({ - container: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - backgroundColor: 'transparent', - justifyContent: 'center', - }, - backdrop: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - backgroundColor: '#000000', - opacity: 0.5, - }, - modal: { - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center' - } -}) - - -module.exports = Setting diff --git a/app/components/TabBar.js b/app/components/TabBar.js deleted file mode 100644 index f5e5dc3a..00000000 --- a/app/components/TabBar.js +++ /dev/null @@ -1,91 +0,0 @@ -'use strict'; - -var React = require('react-native'); -var { - StyleSheet, - Text, - View, - TouchableOpacity, - } = React; - -var deviceWidth = require('Dimensions').get('window').width; -var precomputeStyle = require('precomputeStyle'); -var TAB_UNDERLINE_REF = 'TAB_UNDERLINE'; -var underLineColor = '#3498DB' -var activeTabTextColor = 'rgba(0,0,0,9)' -var normalTabTextColor = 'rgba(0,0,0,0.4)' - -var styles = StyleSheet.create({ - tab: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - paddingBottom: 10, - paddingTop: 10 - }, - - tabs: { - height: 50 + 4, - flexDirection: 'row', - marginTop: 0, - borderWidth: 1, - borderTopWidth: 0, - borderLeftWidth: 0, - borderRightWidth: 0, - borderBottomColor: 'rgba(0,0,0,0.06)', - //shadowColor: 'rgba(0,0,0,1)', - //shadowOffset: { - // width: -1, - // height: -2 - //}, - //shadowOpacity: 0.1, - //alignItems: 'center' - }, -}); - -var DefaultTabBar = React.createClass({ - propTypes: { - goToPage: React.PropTypes.func, - activeTab: React.PropTypes.number, - tabs: React.PropTypes.array - }, - - renderTabOption(name, page) { - var isTabActive = this.props.activeTab === page; - - return ( - this.props.goToPage(page)}> - - {name} - - - ); - }, - - setAnimationValue(value) { - this.refs[TAB_UNDERLINE_REF].setNativeProps(precomputeStyle({ - left: (deviceWidth * value) / this.props.tabs.length - })); - }, - - render() { - var numberOfTabs = this.props.tabs.length; - var tabUnderlineStyle = { - position: 'absolute', - width: deviceWidth / numberOfTabs, - height: 4, - backgroundColor: underLineColor, - bottom: 0, - }; - - return ( - - {this.props.tabs.map((tab, i) => this.renderTabOption(tab, i))} - - - ); - }, -}); - -module.exports = DefaultTabBar; diff --git a/app/components/TopicRow.js b/app/components/TopicRow.js deleted file mode 100644 index dd622d21..00000000 --- a/app/components/TopicRow.js +++ /dev/null @@ -1,144 +0,0 @@ -var React = require('react-native') -var moment = require('moment') - - -var window = require('../util/window') -var { width, height } = window.get() - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - Image, - ListView, - TouchableHighlight, - Navigator, - } = React - - -class TopicRow extends Component { - constructor(props) { - super(props) - let isVisible = this.props.isVisible - isVisible = typeof isVisible === 'undefined' || true - this.state = { - isVisible: isVisible - } - } - - - show() { - console.log('show'); - this.imgView.setNativeProps({ - source: { - uri: this.authorImg - } - }) - this.titleText.setNativeProps({ - text: this.title - }) - } - - - hide() { - this.imgView.setNativeProps({ - source: null - }) - this.titleText.setNativeProps({ - text: null - }) - } - - - render() { - let topic = this.props.topic - let authorImgUri = window.parseImgUrl(topic.author.avatar_url) - var title = topic.title - var titleLength = Math.floor((width - 100) / 15) + 2 - if (title.length > titleLength) { - title = title.substring(0, titleLength - 3) + '...' - } - - this.authorImg = authorImgUri - this.title = title - if (this.state.isVisible) { - return ( - {this.props.onPress(topic)}} - underlayColor='#3498DB' - key={topic.id}> - - - - this.imgView=view} - style={styles.img} - source={{uri:authorImgUri}} - > - - - - - this.titleText=view} - style={[styles.title]}> - {title} - - - - {this.props.footer} - - - - - - ) - } - else { - return null - } - } -} - - -var styles = StyleSheet.create({ - "row": { - "height": 90, - "flexDirection": "row", - "borderBottomColor": "rgba(0, 0, 0, 0.02)", - "borderBottomWidth": 1, - "paddingTop": 25, - "paddingRight": 0, - "paddingBottom": 25, - "paddingLeft": 20 - }, - "imgWrapper": { - "width": 90, - "position": "absolute", - "left": 20, - "top": 25, - "height": 65 - }, - "img": { - "height": 40, - "width": 40, - "borderRadius": 20 - }, - "topic": { - "marginLeft": 60, - width: width - 100 - }, - "title": { - "fontSize": 15 - }, - "topicFooter": { - "marginTop": 12, - "flexDirection": "row" - } -}) - - -module.exports = TopicRow diff --git a/app/components/TopicsInTab.js b/app/components/TopicsInTab.js deleted file mode 100644 index 330a269f..00000000 --- a/app/components/TopicsInTab.js +++ /dev/null @@ -1,165 +0,0 @@ -var React = require('react-native') -var rebound = require('rebound') - -// custom component -var PageScrollView = require('./PageScrollView') -var PageNavBar = require('./PageNavBar') -var PageListView = require('./PageListView') - - -var window = require('../util/window') -var { width, height } = window.get() - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - Image, - ListView, - TouchableHighlight, - Navigator, - AsyncStorage - } = React - - -class TopicsInTab extends Component { - constructor(props) { - super(props); - this.navs = ['精华', '问答', '主页', '分享', '招聘']; - this.totalPages = this.navs.length; - this.tabs = ['good', 'ask', 'all', 'share', 'job']; - this.space = (width - (60 * 3)) / 2 + 60; - var pageIndex = 2; - var pageScrollContentWidth = width * pageIndex; - var pageNavBarWith = (this.space / width) * pageScrollContentWidth; - var pageNavBarOffset = (pageIndex * width / pageScrollContentWidth) * pageNavBarWith; - - this.state = { - pageIndex: pageIndex, - navBarOffset: pageNavBarOffset - } - } - - componentWillMount() { - this.springSystem = new rebound.SpringSystem() - this._scrollSpring = this.springSystem.createSpring() - this._updateSpringConfig(this.props) - - this._scrollSpring.addListener({ - onSpringUpdate: () => { - var currentValue = this._scrollSpring.getCurrentValue() - var space = this.space - var offset = currentValue.offset - var pageScrollContentWidth = currentValue.contentWidth - if (offset < 0 || offset > pageScrollContentWidth - width) { - return - } - - var pageNavBarWith = (space / width) * pageScrollContentWidth - var pageNavBarOffset = (offset / pageScrollContentWidth) * pageNavBarWith - - this._pageNavBar.updateNav(pageNavBarOffset) - } - }); - } - - componentDidMount() { - this._scrollSpring.setCurrentValue({ - offset: this.state.pageIndex * width, - contentWidth: 0 - }); - } - - _updateSpringConfig(props) { - var springConfig = this._scrollSpring.getSpringConfig(); - springConfig.tension = rebound.OrigamiValueConverter.tensionFromOrigamiValue(props.springTension || 25) - springConfig.friction = rebound.OrigamiValueConverter.frictionFromOrigamiValue(props.springFriction || 8) - - this._scrollSpring.setOvershootClampingEnabled((typeof props.clampSpring === 'undefined') ? true : props.clampSpring) - } - - - shouldComponentUpdate(nextProps, nextState) { - if (nextProps.topic !== this.props.topic) { - return true - } - return false - } - - - _pageScrollViewOnScroll(e) { - var offset = e.nativeEvent.contentOffset.x - this._scrollSpring.setCurrentValue({ - offset: offset, - contentWidth: e.nativeEvent.contentSize.width - }) - } - - - _onNavItemPress(index) { - var {offset} = this._scrollSpring.getCurrentValue() - if (offset % width == 0) { - var currentIndex = offset / width - if (currentIndex == index) { - this['_pageListView_' + index] && this['_pageListView_' + index].scrollToTop() - } - this._pageScrollView.scrollTo(index * width, Math.abs(currentIndex - index)) - } - } - - - _renderPageListView() { - var navs = this.navs - var tabs = this.tabs - var space = this.space - return navs.map((nav, index) => { - var tab = tabs[index] - return ( - {this['_pageListView_'+index]=view}} - key={'listView'+index} - navs={navs} - space={space} - data={this.props.topic[tab].topics} - actions={this.props.actions} - tab={this.props.topic[tab]} - router={this.props.router} - /> - ) - }) - } - - - render() { - return ( - - {this._pageNavBar=view}}> - - - - {this._pageScrollView=view}} - pageIndex={this.state.pageIndex} - totalPages={this.totalPages} - onScroll={this._pageScrollViewOnScroll.bind(this)} - onScrollBeginDrag={this._pageScrollViewOnScroll.bind(this)} - > - {this._renderPageListView()} - - - ) - } -} - - -module.exports = TopicsInTab diff --git a/app/components/UserTopicPage.js b/app/components/UserTopicPage.js deleted file mode 100644 index d7c1dbc6..00000000 --- a/app/components/UserTopicPage.js +++ /dev/null @@ -1,127 +0,0 @@ -var React = require('react-native') -var moment = require('moment') - -var TopicRow = require('./TopicRow') -var Topic = require('../containers/Topic') - -var sceneConfig = require('../configs/sceneConfig') -var config = require('../configs/config') - -var window = require('../util/window') -var { width, height } = window.get() - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - Image, - ListView, - TouchableHighlight, - Navigator, - } = React - - -class UserTopicPage extends Component { - constructor(props) { - super(props) - this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) - this.data = this.props.data || [] - this.state = { - ds: this.ds.cloneWithRows(this.data) - } - } - - - componentWillReceiveProps(nextProps) { - if (nextProps.data != this.props.data) { - this.setState({ - ds: this.ds.cloneWithRows(nextProps.data) - }) - } - } - - - _onRowPress(topic) { - this.props.router.toTopic({ - topic: topic, - from: 'user' - }) - } - - - _renderRowFooter(topic) { - var date = moment(topic.last_reply_at).startOf('minute').fromNow(); - let dateItem = ( - - {date} - - ) - - let authorItem = ( - - {topic.author.loginname} - - ) - - - return [dateItem, authorItem] - } - - - _renderRow(topic) { - return ( - - ) - } - - - render() { - return ( - - - - ) - } -} - - -var styles = StyleSheet.create({ - container: { - width: width - }, - "topicFooter text": { - "fontSize": 11, - "color": "rgba(0, 0, 0, 0.3)" - }, - "topicFooter date": { - "position": "absolute", - "right": 0, - "top": 0 - }, - "topicFooter author": { - position: 'absolute', - left: 0, - top: 0 - } -}) - - -module.exports = UserTopicPage diff --git a/app/components/comment/CommentUp.js b/app/components/comment/CommentUp.js deleted file mode 100644 index 66cd1bb1..00000000 --- a/app/components/comment/CommentUp.js +++ /dev/null @@ -1,119 +0,0 @@ -var React = require('react-native') -var { Icon } = require('react-native-icons') - -var TopicService = require('../../services/TopicService') - -var { - Component, - View, - TouchableOpacity, - StyleSheet, - Text, - ActivityIndicatorIOS - } = React - - -class CommentUp extends Component { - constructor(props) { - super(props) - this.state = { - isUped: this._isUped(this.props.user.id, this.props.ups), - isLoading: false, - count: this.props.ups.length - } - } - - - _onUpPress() { - if (this.props.user.loginname == this.props.authorName) { - return window.alert('不能给自己点赞哦!') - } - if (this.state.isLoading) return - - this.setState({ - isLoading: true - }) - - TopicService.req.upComment(this.props.replyId, this.props.user.token) - .then(isUped=> { - let count = this.state.count - isUped ? count++ : count-- - this.setState({ - isUped: isUped, - isLoading: false, - count: count < 0 ? 0 : count - }) - }) - .catch(err=> { - console.warn(err) - this.setState({ - isLoading: false - }) - }) - .done() - } - - - _isUped(id, ups) { - return ups.some(item=> { - return item == id - }) - } - - - _renderUpIcon() { - if (this.state.isLoading) { - return ( - - ) - } - return ( - - ) - } - - - render() { - let count = this.state.count || 0 - return ( - - - - {this._renderUpIcon()} - - {count == 0 ? null : ({count})} - - - ) - } -} - - -var styles = StyleSheet.create({ - upIcon: { - height: 12, - width: 16 - }, - text: { - paddingLeft: 7, - fontSize: 12, - color: 'rgba(0,0,0,0.2)', - height: 12 - }, - loading: { - height: 12, - width: 16 - } -}) - - -module.exports = CommentUp diff --git a/app/components/htmlRender/CommentHtml.js b/app/components/htmlRender/CommentHtml.js deleted file mode 100644 index e18bb3d7..00000000 --- a/app/components/htmlRender/CommentHtml.js +++ /dev/null @@ -1,185 +0,0 @@ -var React = require('react-native') -var HtmlContent = require('./HtmlContent') - -var window = require('../../util/window') -var { width, height } = window.get() - -var { - Component, - View, - Text, - StyleSheet, - Image - }=React - - -class CommentHtml extends Component { - constructor(props) { - super(props) - if (this.props.style) { - this.styles = Object.assign({}, styles, this.props.style) - } - } - - render() { - return ( - - ) - } -} - - -var fontSize = 14 -var titleMargin = 5 -var liFontSize = fontSize - 2 - -var styles = StyleSheet.create({ - p: { - lineHeight: fontSize * 1.4, - fontSize: fontSize, - color: 'rgba(0,0,0,0.8)' - }, - pwrapper: { - marginTop: 5, - marginBottom: 5 - }, - - a: { - color: '#3498DB', - fontSize: fontSize, - paddingLeft: 4, - paddingRight: 4, - marginRight: 10, - marginLeft: 10 - }, - h1: { - fontSize: fontSize * 1.6, - fontWeight: "bold", - color: 'rgba(0,0,0,0.8)' - }, - h1wrapper: { - marginTop: titleMargin, - marginBottom: titleMargin - }, - h2: { - fontSize: fontSize * 1.5, - fontWeight: 'bold', - color: 'rgba(0,0,0,0.85)' - }, - h2wrapper: { - marginBottom: titleMargin, - marginTop: titleMargin - }, - h3: { - fontWeight: 'bold', - fontSize: fontSize * 1.4, - color: 'rgba(0,0,0,0.8)' - }, - h3wrapper: { - marginBottom: titleMargin - 2, - marginTop: titleMargin - 2 - }, - h4: { - fontSize: fontSize * 1.3, - color: 'rgba(0,0,0,0.7)', - fontWeight: 'bold' - }, - h4wrapper: { - marginBottom: titleMargin - 2, - marginTop: titleMargin - 2, - }, - h5: { - fontSize: fontSize * 1.2, - color: 'rgba(0,0,0,0.7)', - fontWeight: 'bold' - }, - h5wrapper: { - marginBottom: titleMargin - 3, - marginTop: titleMargin - 3, - }, - h6: { - fontSize: fontSize * 1.1, - color: 'rgba(0,0,0,0.7)', - fontWeight: 'bold' - }, - h6wrapper: { - marginBottom: titleMargin - 3, - marginTop: titleMargin - 3, - }, - li: { - fontSize: fontSize * 0.9, - color: 'rgba(0,0,0,0.7)' - }, - liwrapper: { - paddingLeft: 20, - marginBottom: 10 - }, - strong: { - fontWeight: 'bold' - }, - em: { - fontStyle: 'italic' - }, - codeScrollView: { - backgroundColor: '#333', - flexDirection: 'column', - marginBottom: 15 - }, - codeRow: { - flex: 1, - flexDirection: 'row', - height: 25, - alignItems: 'center' - }, - codeFirstRow: { - paddingTop: 20, - height: 25 + 20 - }, - codeLastRow: { - paddingBottom: 20, - height: 25 + 20 - }, - codeFirstAndLastRow: { - paddingBottom: 20, - height: 25 + 40, - paddingTop: 20 - }, - lineNum: { - width: 55, - color: 'rgba(255,255,255,0.5)', - }, - lineNumWrapper: { - width: 55, - height: 25, - backgroundColor: 'rgba(0,0,0,0.1)', - flexDirection: 'row', - alignItems: 'center', - paddingLeft: 20 - }, - codeWrapper: { - flexDirection: 'column' - }, - codeLineWrapper: { - height: 25, - flexDirection: 'row', - alignItems: 'center', - paddingLeft: 20, - paddingRight: 20 - }, - blockquotewrapper: { - paddingLeft: 20, - borderLeftColor: '#3498DB', - borderLeftWidth: 3 - }, - img:{ - width: width - 80, - height: width - 80, - resizeMode: Image.resizeMode.contain - } -}) - -module.exports = CommentHtml diff --git a/app/components/htmlRender/HtmlContent.js b/app/components/htmlRender/HtmlContent.js deleted file mode 100644 index e2caf07e..00000000 --- a/app/components/htmlRender/HtmlContent.js +++ /dev/null @@ -1,118 +0,0 @@ -var React = require('react-native') - -var HtmlRender = require('react-native-html-render') - -var window = require('../../util/window') - - -var { width, height } = window.get() - -var { - Component, - View, - Text, - StyleSheet, - Image, - LinkingIOS, - Navigator - }=React - -var contentFontSize = 16 - - -var styles = StyleSheet.create({ - img: { - width: width - 30, - height: width - 30, - resizeMode: Image.resizeMode.contain - } -}) - - -var regs = { - http: { - topic: /^https?:\/\/cnodejs\.org\/topic\/\w*/, - user: /^https?:\/\/cnodejs\.org\/user\/\w*/ - } -} - - -class HtmlContent extends Component { - constructor(props) { - super(props) - } - - - _onLinkPress(url) { - let router = this.props.router - - if (/^\/user\/\w*/.test(url)) { - let authorName = url.replace(/^\/user\//, '') - - router.toUser({ - userName: authorName - }) - } - - if (/^https?:\/\/.*/.test(url)) { - if (regs.http.topic.test(url)) { - let topicId = url.replace(/^https?:\/\/cnodejs\.org\/topic\//, '') - - return router.toTopic({ - topicId: topicId, - from: 'html' - }) - } - - if (regs.http.user.test(url)) { - let userName = url.replace(/^https?:\/\/cnodejs\.org\/user\//, '') - - return router.toUser({ - userName: userName - }) - } - - window.link(url) - } - - if (/^mailto:\w*/.test(url)) { - window.link(url) - } - } - - - _renderNode(node, index, parent, type) { - var name = node.name - - var imgStyle = (this.props.style && this.props.style.img) || styles.img - - if (node.type == 'block' && type == 'block') { - if (name == 'img') { - var uri = window.parseImgUrl(node.attribs.src) - if (/.*\.gif$/.test(uri)) return null - return ( - - - ) - } - } - } - - - render() { - return ( - - ) - } - -} - -module.exports = HtmlContent diff --git a/app/components/overlay/CommentOverlay.js b/app/components/overlay/CommentOverlay.js deleted file mode 100644 index 4bfe6740..00000000 --- a/app/components/overlay/CommentOverlay.js +++ /dev/null @@ -1,95 +0,0 @@ -var React = require('react-native'); -var Dimensions = require('Dimensions'); -var { Icon, } = require('react-native-icons') -var Button = require('react-native-button'); - - -var OverlayButton = require('./OverlayButton'); - - -var config = require('../../configs/config'); - -var { width, height } = Dimensions.get('window'); - - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - Image, - ListView, - TouchableHighlight, - Navigator, - AsyncStorage, - ActivityIndicatorIOS - } = React; - -var overlaySize = 45 - -var iconSize = 12 - -var styles = StyleSheet.create({ - position: { - right: 20, - bottom: 20 - }, - commentText: { - textAlign: 'center', - color: 'white', - fontSize: 12, - paddingLeft: 4 - }, - content: { - height: overlaySize, - width: overlaySize, - borderRadius: overlaySize / 2, - flexDirection: 'row', - justifyContent: 'center', - alignItems: 'center' - }, - commentIcon: { - height: iconSize, - width: iconSize, - } -}) - - -class CommentOverlay extends Component { - constructor(props) { - super(props) - } - - - _renderCommentReplyCount(count) { - if (count > 999) { - return '1k+' - } - return count - } - - render() { - return ( - - - - - {this._renderCommentReplyCount(this.props.topic.reply_count)} - - - - ) - } -} - - -module.exports = CommentOverlay diff --git a/app/components/overlay/Loading.js b/app/components/overlay/Loading.js deleted file mode 100644 index 230cc928..00000000 --- a/app/components/overlay/Loading.js +++ /dev/null @@ -1,76 +0,0 @@ -var React = require('react-native') -var { Icon } = require('react-native-icons') -var Modal = require('react-native-modal') - -var window = require('../../util/window') -var { width, height } = window.get() - - -var { - View, - StyleSheet, - Component, - Text, - Image, - ActivityIndicatorIOS - } = React - - -class Loading extends Component { - constructor(props) { - super(props) - } - - - render() { - return ( - - - - - ) - } -} - - -var modalStyles = StyleSheet.create({ - container: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - backgroundColor: 'transparent', - justifyContent: 'center', - alignItems: 'center' - }, - backdrop: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - backgroundColor: '#000000', - opacity: 0.3, - }, - modal: { - backgroundColor: 'white', - flex: 1, - height: 120, - width: 120, - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - borderRadius: 5 - } -}) - - -module.exports = Loading diff --git a/app/components/overlay/MarkAsReadOverlay.js b/app/components/overlay/MarkAsReadOverlay.js deleted file mode 100644 index 3e637a0b..00000000 --- a/app/components/overlay/MarkAsReadOverlay.js +++ /dev/null @@ -1,86 +0,0 @@ -var React = require('react-native') - -var Button = require('react-native-button') -var OverlayButton = require('./OverlayButton') - -var window = require('../../util/window') -var { width, height } = window.get() - - -var { - View, - StyleSheet, - Component, - Text, - ActivityIndicatorIOS - } = React - -var overlaySize = 45 - - -var styles = StyleSheet.create({ - position: { - right: 20, - bottom: 20 - }, - text: { - textAlign: 'center', - color: 'white', - fontSize: 12 - }, - content: { - height: overlaySize, - width: overlaySize, - borderRadius: overlaySize / 2, - flexDirection: 'column', - justifyContent: 'center' - } -}) - - -class MarkAsRead extends Component { - constructor(props) { - super(props) - } - - - _onPress() { - if (this.props.message.hasNotRead.length == 0) { - window.alert('暂无未读消息!') - } - else { - this.props.markAsRead(this.props.token) - } - } - - - _renderContent() { - if (this.props.isLoading) { - return ( - - ) - } - return ( - - 已读 - - ) - } - - - render() { - return ( - - - {this._renderContent()} - - - ) - } -} - - -module.exports = MarkAsRead diff --git a/app/components/overlay/MessageOverlay.js b/app/components/overlay/MessageOverlay.js deleted file mode 100644 index 67ab37d5..00000000 --- a/app/components/overlay/MessageOverlay.js +++ /dev/null @@ -1,113 +0,0 @@ -var React = require('react-native') -var { Icon, } = require('react-native-icons') - -var OverlayButton = require('./OverlayButton') - - -var window = require('../../util/window') -var { width, height } = window.get() - -var { - View, - Text, - Component, - StyleSheet, - Image - } = React; - - -class MessageOverlay extends Component { - constructor(props) { - super(props) - } - - componentDidMount() { - this.props.getUnreadCount(this.props.user.token) - } - - - _renderMessageCount() { - var count = this.props.count - - if (count > 0) { - return ( - - - {count > 999 ? '1k+' : count} - - - ) - } - - return null - } - - - _onPress() { - this.props.router.toMessage() - } - - - render() { - if (this.props.user) { - return ( - - - - {this._renderMessageCount()} - - ) - } - return null - } -} - - -var overlaySize = 45 -var countBoxSize = 20 -var countTextSize = 10 - - -var styles = StyleSheet.create({ - icon: { - height: overlaySize, - width: overlaySize, - borderRadius: overlaySize / 2 - }, - countWrapper: { - height: countBoxSize, - width: countBoxSize, - borderRadius: countBoxSize / 2, - backgroundColor: 'red', - position: 'absolute', - right: -5, - top: -5 - }, - countText: { - color: 'rgba(255,255,255,0.8)', - fontSize: countTextSize, - lineHeight: countBoxSize - countTextSize / 2, - textAlign: 'center', - height: countBoxSize, - width: countBoxSize, - borderRadius: countBoxSize / 2, - backgroundColor: 'transparent' - }, - position: { - right: 20, - bottom: 20 - }, - container: { - backgroundColor: 'blue', - borderRadius: overlaySize / 2 - } -}) - - -module.exports = MessageOverlay diff --git a/app/components/overlay/OverlayButton.js b/app/components/overlay/OverlayButton.js deleted file mode 100644 index 0c00c229..00000000 --- a/app/components/overlay/OverlayButton.js +++ /dev/null @@ -1,57 +0,0 @@ -var React = require('react-native') -var Button = require('react-native-button') - -var { - View, - Text, - Component, - TouchableHighlight, - StyleSheet - } = React - -var overlayButtonSize = 45 - -var styles = StyleSheet.create({ - container: { - height: overlayButtonSize, - width: overlayButtonSize, - position: 'absolute', - //left: 20, - //bottom: 20, - borderRadius: overlayButtonSize / 2, - backgroundColor: 'rgba(0,0,0,0.7)' - }, - returnIcon: { - height: overlayButtonSize, - width: overlayButtonSize, - borderRadius: overlayButtonSize / 2 - }, - defaultPosition: { - left: 20, - bottom: 20 - } -}) - - -class OverlayButton extends Component { - constructor(props) { - super(props) - } - - - render() { - return ( - - - - ) - } -} - - -module.exports = OverlayButton diff --git a/app/components/overlay/Return.js b/app/components/overlay/Return.js deleted file mode 100644 index f6b3b177..00000000 --- a/app/components/overlay/Return.js +++ /dev/null @@ -1,59 +0,0 @@ -var React = require('react-native') - -var Button = require('react-native-button') -var { Icon } = require('react-native-icons') - -var OverlayButton = require('./OverlayButton') - - -var window = require('../../util/window') -var { width, height } = window.get() - -var { - View, - Text, - Component, - TouchableHighlight, - StyleSheet, - Navigator - } = React; - - -var returnSize = 45 - - -var styles = StyleSheet.create({ - returnIcon: { - height: returnSize, - width: returnSize, - borderRadius: returnSize / 2 - } -}) - - -class Return extends Component { - constructor(props) { - super(props) - } - - - _onPress() { - this.props.router && this.props.router.pop && this.props.router.pop() - } - - - render() { - return ( - - - - ) - } -} - -module.exports = Return diff --git a/app/components/overlay/Return2.js b/app/components/overlay/Return2.js deleted file mode 100644 index 5ca7a965..00000000 --- a/app/components/overlay/Return2.js +++ /dev/null @@ -1,50 +0,0 @@ -var React = require('react-native') -var OverlayButton = require('./OverlayButton') -var { Icon, } = require('react-native-icons') - -var { - Component, - View, - StyleSheet - } = React - - -class Return2 extends Component { - constructor(props) { - super(props) - } - - - render() { - return ( - - - - ) - } -} - -var styles = StyleSheet.create({ - position: { - position: 'absolute', - left: 15, - top: 15 - }, - container: { - backgroundColor: 'transparent' - }, - icon: { - width: 20, - height: 20 - } -}) - - -module.exports = Return2 diff --git a/app/components/overlay/UserOverlay.js b/app/components/overlay/UserOverlay.js deleted file mode 100644 index 8f743df6..00000000 --- a/app/components/overlay/UserOverlay.js +++ /dev/null @@ -1,70 +0,0 @@ -var React = require('react-native') -var { Icon, } = require('react-native-icons') - -var OverlayButton = require('./OverlayButton') - - -var window = require('../../util/window') -var { width, height } = window.get() - -var { - View, - Text, - Component, - StyleSheet, - Image - } = React; - - -var overlaySize = 45 - -var styles = StyleSheet.create({ - userImg: { - borderWidth: 2, - borderColor: '#2C3E50' - }, - icon: { - height: overlaySize, - width: overlaySize, - borderRadius: overlaySize / 2 - } -}) - - -class UserOverlay extends Component { - constructor(props) { - super(props) - } - - - _renderOverlayContent() { - if (this.props.user) { - return ( - - - ) - } - - return ( - - ) - } - - - render() { - return ( - - {this._renderOverlayContent()} - - ) - } -} - -module.exports = UserOverlay diff --git a/app/configs/Router.js b/app/configs/Router.js deleted file mode 100644 index 575235a4..00000000 --- a/app/configs/Router.js +++ /dev/null @@ -1,119 +0,0 @@ -var React = require('react-native') - -// Components -var User = require('../containers/User') -var Topic = require('../containers/Topic') -var Comments = require('../containers/Comments') -var Message = require('../containers/Message') -var QRCode = require('../containers/QRCode') -var About = require('../containers/About') -var Publish = require('../containers/Publish') - -// Config -var sceneConfig = require('./sceneConfig') - - -var { - Navigator - } = React - -var customFloatFromRight = sceneConfig.customFloatFromRight - - -class Router { - constructor(navigator) { - this.navigator = navigator - } - - push(props, route) { - let routesList = this.navigator.getCurrentRoutes() - let nextIndex = routesList[routesList.length - 1].index + 1 - route.props = props - route.index = nextIndex - this.navigator.push(route) - } - - - pop() { - this.navigator.pop() - } - - - toUser(props) { - this.push(props, { - component: User, - name: 'user', - sceneConfig: customFloatFromRight - }) - } - - toTopic(props) { - this.push(props, { - component: Topic, - name: 'topic', - sceneConfig: customFloatFromRight - }) - } - - toComments(props) { - this.push(props, { - component: Comments, - name: 'comments', - sceneConfig: customFloatFromRight - }) - } - - toMessage(props) { - this.push(props, { - component: Message, - name: 'message', - sceneConfig: customFloatFromRight - }) - } - - toQRCode(props) { - this.push(props, { - component: QRCode, - name: 'qrCode', - sceneConfig: Navigator.SceneConfigs.FloatFromBottom - }) - } - - - toAbout() { - this.push({}, { - component: About, - name: 'about', - sceneConfig: sceneConfig.customFloatFromBottom - }) - } - - - toPublish() { - this.push({}, { - component: Publish, - name: 'publish', - sceneConfig: customFloatFromRight - }) - } - - - replaceWithHome() { - this.navigator.popToTop() - } - - replaceWithTopic(props) { - let routesList = this.navigator.getCurrentRoutes() - let index = routesList[routesList.length - 1].index - var route = { - props: props, - index: index, - component: Topic, - sceneConfig: customFloatFromRight - } - this.navigator.replace(route) - } -} - -module.exports = Router - diff --git a/app/configs/animation.js b/app/configs/animation.js deleted file mode 100644 index 26472cc5..00000000 --- a/app/configs/animation.js +++ /dev/null @@ -1,36 +0,0 @@ -var React = require('react-native') - -var { - LayoutAnimation - } = React - -var animations = {} - -animations.keyboard = { - layout: { - spring: { - duration: 400, - create: { - duration: 300, - type: LayoutAnimation.Types.easeInEaseOut, - property: LayoutAnimation.Properties.opacity, - }, - update: { - type: LayoutAnimation.Types.spring, - springDamping: 400 - } - }, - easeInEaseOut: { - duration: 400, - create: { - type: LayoutAnimation.Types.easeInEaseOut, - property: LayoutAnimation.Properties.scaleXY, - }, - update: { - type: LayoutAnimation.Types.easeInEaseOut, - } - } - } -} - -module.exports = animations \ No newline at end of file diff --git a/app/configs/config.js b/app/configs/config.js deleted file mode 100644 index 089b1592..00000000 --- a/app/configs/config.js +++ /dev/null @@ -1,17 +0,0 @@ -var packageObj = require('../../package.json') - -module.exports = { - domain: 'https://cnodejs.org/', - apiPath: '/api/v1', - bgImgUri: 'http://7lrzfj.com1.z0.glb.clouddn.com/soliury213H.png', - replySuffix: '\n\nFrom\040[Noder](https://github.com/soliury/noder-react-native)', - sourceInGithub: 'https://github.com/soliury/noder-react-native', - sourceNameInGithub: 'noder-react-native', - package: packageObj, - author: { - blog: 'http://lingyong.me/about', - cnodeName: 'soliury' - }, - cnodeAbout: 'https://cnodejs.org/about', - RNWebPage: 'http://facebook.github.io/react-native/' -} diff --git a/app/configs/onRun.js b/app/configs/onRun.js deleted file mode 100644 index 8af6a0ef..00000000 --- a/app/configs/onRun.js +++ /dev/null @@ -1,15 +0,0 @@ -var React = require('react-native') -// var storage = require('../services/Storage') - -var packageObj = require('../../package.json') - -var { - StatusBarIOS - } = React - -// storage.clear() - -StatusBarIOS.setHidden(true, false) - - -global.__packageObj__ = packageObj diff --git a/app/configs/sceneConfig.js b/app/configs/sceneConfig.js deleted file mode 100644 index ba18e98d..00000000 --- a/app/configs/sceneConfig.js +++ /dev/null @@ -1,33 +0,0 @@ -var React = require('react-native') -var Dimensions = require('Dimensions'); - -var { - Navigator - } = React - -var { width, height } = Dimensions.get('window'); - - -var baseConfig = Navigator.SceneConfigs.FloatFromRight; -var popGestureConfig = Object.assign({}, baseConfig.gestures.pop, { - edgeHitWidth: width / 3 -}); - - -var fullPopGestureConfig = Object.assign({}, Navigator.SceneConfigs.FloatFromBottom.gestures.pop, { - edgeHitWidth: width -}) - - -exports.customFloatFromRight = Object.assign({}, baseConfig, { - gestures: { - pop: popGestureConfig - } -}) - - -exports.customFloatFromBottom = Object.assign({}, Navigator.SceneConfigs.FloatFromBottom, { - gestures: { - pop: fullPopGestureConfig - } -}) diff --git a/app/constants/ActionTypes.js b/app/constants/ActionTypes.js deleted file mode 100644 index caee4146..00000000 --- a/app/constants/ActionTypes.js +++ /dev/null @@ -1,38 +0,0 @@ -exports.GET_USER = 'GET_USER' -exports.GET_LOGIN_USER_FROM_STORAGE = 'GET_LOGIN_USER_FROM_STORAGE' -exports.GET_USER_FROM_STORAGE_FAILED = 'GET_USER_FROM_STORAGE_FAILED' -exports.FETCH_USER = 'FETCH_USER' - - -exports.OPEN_LOGIN_MODAL = 'OPEN_LOGIN_MODAL' -exports.CLOSE_LOGIN_MODAL = 'CLOSE_LOGIN_MODAL' -exports.LOGIN_SUCCESS = 'LOGIN_SUCCESS' -exports.QR_SUCCESS = 'QR_SUCCESS' -exports.CHECK_TOKEN_SUCCESS = 'CHECK_TOKEN_SUCCESS' -exports.CHECK_TOKEN_REQUREST = 'CHECK_TOKEN_REQUREST' -exports.CHECK_TOKEN_FAILED = 'CHECK_TOKEN_FAILED' -exports.LIKE_TOPIC = 'LIKE_TOPIC' -exports.UN_LIKE_TOPIC = 'UN_LIKE_TOPIC' -exports.LOGOUT='LOGOUT' -exports.CLEAR='CLEAR' - - -exports.GET_UNREAD_MESSAGE_COUNT_SUCCESS = 'GET_UNREAD_MESSAGE_COUNT_SUCCESS' -exports.GET_MESSAGES = 'GET_MESSAGES' -exports.FETCH_MESSAGES_FAILED = 'FETCH_MESSAGES_FAILED' -exports.FETCH_MESSAGES_REQUEST = 'FETCH_MESSAGES_REQUEST' -exports.FETCH_MESSAGES_SUCCESS = 'FETCH_MESSAGES_SUCCESS' -exports.MARK_AS_READ_SUCCESS = 'MARK_AS_READ_SUCCESS' -exports.MARK_AS_READ_FAILED = 'MARK_AS_READ_FAILED' -exports.MARK_AS_READ_REQUEST = 'MARK_AS_READ_REQUEST' - - -exports.GET_ALL_TOPICS_FROM_STORAGE = 'GET_ALL_TOPICS_FROM_STORAGE' -exports.FETCH_TOPICS_BY_TAB_REQUEST = 'FETCH_TOPICS_BY_TAB_REQUEST' -exports.FETCH_TOPICS_BY_TAB_SUCCESS = 'FETCH_TOPICS_BY_TAB_SUCCESS' -exports.FETCH_TOPICS_BY_TAB_FAILED = 'FETCH_TOPICS_BY_TAB_FAILED' - - -exports.GET_TOPICS = 'GET_TOPICS' -exports.UPDATE_TOPICS = 'UPDATE_TOPICS' - diff --git a/app/containers/About.js b/app/containers/About.js deleted file mode 100644 index a995c394..00000000 --- a/app/containers/About.js +++ /dev/null @@ -1,173 +0,0 @@ -var React = require('react-native') -var BlurView = require('react-native-blur').BlurView -var { Icon } = require('react-native-icons') - - -var config = require('../configs/config') -var window = require('../util/window') -var { width, height } = window.get() - - -var { - View, - Component, - PropTypes, - Text, - StyleSheet, - Image, - ActivityIndicatorIOS, - TouchableOpacity - } = React - -class Home extends Component { - constructor(props) { - super(props) - } - - - _onSourceInGithubPress() { - window.link(config.sourceInGithub) - } - - - render() { - return ( - - - - - - - - Noder - - {' v' + config.package.version} - - - - window.link(config.cnodeAbout)}> - For CNodejs.org - - - - - - - - - - - - - this.props.router.toUser({ - userName:config.author.cnodeName - })}> - @soliury - - - - window.link(config.author.blog)}> - - - - - window.link(config.RNWebPage)}> - Power By - React-Native {'v' + config.package.dependencies['react-native']} - - - - - ) - } -} - -Home.propTypes = { - actions: PropTypes.object, - state: PropTypes.object -} - -var styles = StyleSheet.create({ - bgWall: { - height: height, - width: width - }, - noderLogo: { - height: 150, - width: 150 - }, - container: { - width: width, - height: height, - flexDirection: 'column', - alignItems: 'center', - paddingTop: 30 - }, - title: { - marginTop: 20, - fontSize: 30, - color: 'rgba(255,255,255,0.7)', - borderBottomWidth: 1, - borderBottomColor: 'rgba(255,255,255,0.1)', - - }, - subTitle: { - marginTop: 10, - fontSize: 16, - color: 'rgba(255,255,255,0.5)' - }, - row: { - flexDirection: 'row', - justifyContent: 'center', - height: 40, - alignItems: 'center' - }, - rowIcon: { - height: 40, - width: 40 - }, - footer: { - position: 'absolute', - bottom: 0, - width: width, - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center' - }, - arrow: { - marginTop: 40, - height: 50, - width: 50 - }, - blog: { - height: 20, - width: 100, - opacity: 0.5 - }, - reactNative: { - fontSize: 16, - color: 'rgba(255,255,255,0.3)', - marginBottom: 10 - } -}) - -module.exports = Home diff --git a/app/containers/App.js b/app/containers/App.js deleted file mode 100644 index 4aea04ba..00000000 --- a/app/containers/App.js +++ /dev/null @@ -1,40 +0,0 @@ -var React = require('react-native') -var Redux = require('redux') -var NoderApp = require('./NoderApp') - -var reducer = require('../reducers') - - -var { - Provider - } = require('redux/react-native') - - -var { - createStore - } = Redux - - -var { - Component, - View - } = React - - -var store = createStore(reducer) - - -class App extends Component { - render() { - return ( - - {function () { - return - }} - - ) - } -} - - -module.exports = App diff --git a/app/containers/Comments.js b/app/containers/Comments.js deleted file mode 100644 index 2a6f8ec9..00000000 --- a/app/containers/Comments.js +++ /dev/null @@ -1,631 +0,0 @@ -var React = require('react-native') -var window = require('../util/window') -var { width, height } = window.get() -var precomputeStyle = require('precomputeStyle') - - -var moment = require('moment') -var { Icon } = require('react-native-icons') -var KeyboardEvents = require('react-native-keyboardevents') -var KeyboardEventEmitter = KeyboardEvents.Emitter -var markdown = require("markdown").markdown - -var Return = require('../components/overlay/Return') -var CommentHtml = require('../components/htmlRender/CommentHtml') -var CommentUp = require('../components/comment/CommentUp') -var Nav = require('../components/Nav') - -var TopicService = require('../services/TopicService') -var genColor = require('../util/genColor') -var config = require('../configs/config') -var animations = require('../configs/animation') - - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - Image, - ListView, - ActivityIndicatorIOS, - TouchableOpacity, - TouchableHighlight, - Navigator, - PushNotificationIOS, - TextInput, - LayoutAnimation - } = React - - -class Comments extends Component { - constructor(props) { - super(props) - var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); - var data = []; - this.state = { - ds: ds.cloneWithRows(data), - commentLoading: false, - replyUploading: false, - isLoaded: false, - didFocus: false - } - this.updateKeyboardSpace = this.updateKeyboardSpace.bind(this) - this.resetKeyboardSpace = this.resetKeyboardSpace.bind(this) - } - - updateKeyboardSpace(frames) { - LayoutAnimation.configureNext(animations.keyboard.layout.spring); - this.commentsView.setNativeProps({ - height: commentsHeight - frames.end.height - }) - } - - resetKeyboardSpace() { - LayoutAnimation.configureNext(animations.keyboard.layout.spring); - this.commentsView.setNativeProps({ - height: commentsHeight - }) - } - - - componentDidMount() { - this._fetchComment() - KeyboardEventEmitter.on(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace) - KeyboardEventEmitter.on(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace) - } - - - componentDidFocus() { - this.setState({ - didFocus: true - }) - } - - - componentWillUnmount() { - KeyboardEventEmitter.off(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace) - KeyboardEventEmitter.off(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace) - } - - - componentDidUpdate() { - setTimeout(() => this._scrollToReply()) - } - - - _scrollToReply() { - let reply = this.props.reply - if (reply) { - let row = this[reply.id] - if (row && row.measure) { - row.measure((x, y, width, height, pageX, pageY) => { - this._listView.setNativeProps({ - contentOffset: { - x: 0, - y: y - } - }) - }) - - row.setNativeProps(precomputeStyle({ - styles: { - backgroundColor: 'red' - } - })) - } - } - } - - - _fetchComment() { - if (this.state.commentLoading) { - return - } - - this.setState({ - commentLoading: true - }) - TopicService.req.getTopicById(this.props.topic.id) - .then(topic=> { - this.topic = topic - return topic.replies - }) - .then(replies=> { - return replies.reverse() - }) - .then(comments=> { - this.comments = comments - this.setState({ - ds: this.state.ds.cloneWithRows(this.comments), - commentLoading: false, - isLoaded: true - }) - }) - .catch((err)=> { - console.warn(err) - this.setState({ - commentLoading: false - }) - }) - .done() - } - - - _doReply() { - var content = this.textInputValue - if (this.state.replyUploading || content == '' || content == null) { - return - } - let user = this.props.state.user - let topic = this.props.topic - content = content + config.replySuffix - - this.setState({ - replyUploading: true - }) - - - TopicService.req.reply(topic.id, content, user.token, this.replyId) - .then(replyId=> { - var newReply = { - id: replyId, - author: { - loginname: user.loginname, - avatar_url: user.avatar_url - }, - content: markdown.toHTML(content), - ups: [], - create_at: new Date() - } - this.comments = [newReply].concat(this.comments) - this.replyId = null - this.setState({ - ds: this.state.ds.cloneWithRows(this.comments), - replyUploading: false - }) - this.textInput.setNativeProps({ - text: '' - }) - this.textInputValue = '' - this.textInput.blur() - }) - .catch(err=> { - console.warn(err) - this.setState({ - replyUploading: false - }) - }) - .done() - } - - - _onReplyPress(id, authorName) { - this.textInput.focus() - let text = `@${authorName} ` - this.textInput.setNativeProps({ - text: text - }) - this.replyId = id - this.textInputValue = text - } - - - _onAuthorTextPress(authorName) { - let text = (this.textInputValue || '') + ` @${authorName} ` - - this.textInput.setNativeProps({ - text: text - }) - this.textInputValue = text - } - - - _onAuthorImgPress(authorName) { - this.props.router.toUser({ - userName: authorName - }) - } - - - renderRow(comment, sectionID, rowID, highlightRow) { - var authorName = comment.author.loginname - var domain = config.domain - var date = moment(comment.create_at).startOf('minute').fromNow() - var commentNum = this.comments.length - parseInt(rowID) - var focusStyle = {} - if (this.props.reply) { - let replyId = this.props.reply.id - if (replyId == comment.id) { - focusStyle = { - backgroundColor: 'rgba(0,2,125,0.07)' - } - } - } - - var footer = ( - - - - - - - - - - ) - - - return ( - this[comment.id]=view} - key={comment.id} - style={[styles.commentWrapper,focusStyle]}> - - - - - - - - {commentNum} 楼 - - - - - - - - - {{authorName}} - - - - - - - {date} - - - - - - - {!this.props.state.user || footer} - - - ) - } - - - _renderComments() { - if (this.state.didFocus && this.state.isLoaded) { - return ( - this._listView=view} - style={{backgroundColor:'rgba(255,255,255,1)'}} - showsVerticalScrollIndicator={true} - initialListSize={10} - pagingEnabled={false} - removeClippedSubviews={true} - dataSource={this.state.ds} - renderRow={this.renderRow.bind(this)} - /> - ) - } - - return ( - - ) - } - - - _renderReplySubmiteIcon() { - if (this.state.replyUploading) { - return ( - - - - ) - } - return ( - - ) - } - - - _renderReplyForm() { - var user = this.props.state.user - - if (!user) return null - - var userImg = window.parseImgUrl(user.avatar_url) - - return ( - - - this.props.router.toUser({isLoginUser:true})}> - - - - - - this.textInput=view} - value={this.state.textInput} - multiline={true} - placeholder='嘿,说点啥吧' - style={styles.replyInput} - onChangeText={(text) => { - this.textInput.setNativeProps({ - text:text - }) - this.textInputValue = text - }} - /> - - - - this._doReply()}> - {this._renderReplySubmiteIcon()} - - - - ) - } - - - render() { - var count = this.state.ds.getRowCount() - - var router = this.props.router - - var navs = { - Left: { - text: '返回', - onPress: ()=> { - router.pop() - } - }, - Center: { - text: '评论 ' + count, - onPress: ()=> { - if (count > 0) { - this._listView.setNativeProps({ - contentOffset: { - x: 0, - y: 0 - } - }) - } - } - } - } - - if (this.state.didFocus && this.props.reply && this.state.isLoaded) { - navs = { - ...navs, - Right: { - text: '正文', - onPress: ()=> { - router.toTopic({ - topic: this.topic - }) - } - } - } - } - - return ( - - - - this.commentsView=view} - style={[styles.comments,{height:this.props.state.user?commentsHeight:commentsHeight+replyFormHeight}]}> - {this._renderComments()} - - - {this._renderReplyForm()} - - ) - } -} - - -var navHeight = 55 -var authorImgSize = 35 -var commentContentOffset = 15 * 2 + authorImgSize -var commentIconSize = 12 -var replyFormHeight = 55 -var commentsHeight = height - 40 - 20 - replyFormHeight -var submitButtonWidth = 55 - -var commentHtmlStyle = StyleSheet.create({ - img: { - width: width - commentContentOffset - 15, - height: width - commentContentOffset - 15, - resizeMode: Image.resizeMode.contain - } -}) - -var styles = StyleSheet.create({ - container: { - backgroundColor: 'white', - height: height - }, - - titleText: { - color: 'rgba(0,0,0,0.7)', - fontSize: 16 - }, - - comments: { - //marginTop: 20, - width: width, - height: commentsHeight - }, - - commentWrapper: { - borderBottomColor: 'rgba(0,0,0,0.02)', - borderBottomWidth: 1, - padding: 15, - flexDirection: 'row', - }, - - commentHeader: { - flexDirection: 'row', - alignItems: 'center' - }, - - date: { - flexDirection: 'row', - flex: 1 - }, - - author: { - flex: 1 - }, - authorText: { - color: 'rgba(0,0,0,0.3)', - fontSize: 12 - }, - - dateIcon: { - height: commentIconSize, - width: commentIconSize, - flexDirection: 'row' - }, - - dateText: { - color: 'rgba(0,0,0,0.3)', - fontSize: 12, - textAlign: 'right', - flex: 1 - }, - - commentIcon: { - height: commentIconSize, - width: commentIconSize - }, - - - imageWrapper: { - width: authorImgSize + 15 - }, - - commentNumText: { - marginTop: 15, - fontSize: 12, - color: 'rgba(0,0,0,0.3)', - textAlign: 'center', - width: authorImgSize - - }, - - commentContentWrapper: { - width: width - commentContentOffset - 15, - }, - - authorImg: { - height: authorImgSize, - width: authorImgSize, - borderRadius: authorImgSize / 2 - - }, - commentFooter: { - flexDirection: 'row', - flex: 1, - justifyContent: 'space-between', - alignItems: 'flex-start', - marginTop: 15 - }, - up: { - width: 80, - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center' - }, - replyIcon: { - height: 12, - width: 15 - }, - upIcon: { - height: 10, - width: 13 - }, - replyFormWrapper: { - height: replyFormHeight + 4, - width: width, - flexDirection: 'row', - shadowColor: 'rgba(0,0,0,1)', - shadowOffset: { - width: -2, - height: -2 - }, - shadowOpacity: 0.1, - alignItems: 'center' - }, - replyUserImgWrapper: { - width: authorImgSize + 15 * 2, - flexDirection: 'row', - justifyContent: 'center' - }, - userImg: { - height: authorImgSize, - width: authorImgSize, - resizeMode: Image.resizeMode.contain, - }, - replyInputWrapper: { - width: width - replyFormHeight - submitButtonWidth, - flexDirection: 'row', - alignItems: 'center' - }, - replyInput: { - flex: 1, - fontSize: 14, - height: 14 * 2, - lineHeight: 14 * 1.4 - }, - submitIcon: { - width: authorImgSize, - height: authorImgSize - } -}) - -module.exports = Comments diff --git a/app/containers/Home.js b/app/containers/Home.js deleted file mode 100644 index 772c350d..00000000 --- a/app/containers/Home.js +++ /dev/null @@ -1,128 +0,0 @@ -var React = require('react-native') - - -var UserOverlay = require('../components/overlay/UserOverlay') -var Login = require('../components/Login') -var TopicsInTab = require('../components/TopicsInTab') -var MessageOverlay = require('../components/overlay/MessageOverlay') - - -var config = require('../configs/config') -var window = require('../util/window') -var { width, height } = window.get() - - -var { - View, - Component, - PropTypes, - Text, - StyleSheet, - Image, - ActivityIndicatorIOS - } = React - -class Home extends Component { - constructor(props) { - super(props) - } - - - _userOverlayOnPress() { - let actions = this.props.actions - let state = this.props.state - if (!state.user) { - actions.openLoginModal() - } - else { - this.props.router.toUser({ - isLoginUser: true - }) - } - } - - - render() { - let loginUser = this.props.state.user - let home = this.props.state.home - - let messageOverlay = ( - - ) - - - return ( - - - - - - - - - - {loginUser ? messageOverlay : null} - - - - - - - ) - } -} - -Home.propTypes = { - actions: PropTypes.object, - state: PropTypes.object -} - -var styles = StyleSheet.create({ - container: { - width: width, - "flex": 1, - "backgroundColor": "transparent" - }, - page: { - width: width - }, - scrollContainer: { - height: height - 40, - "flex": 1 - }, - listView: { - backgroundColor: 'blue' - }, - navScroll: { - "height": 40, - "backgroundColor": "rgba(0, 0, 0, 0.75)", - "position": "absolute", - "left": 0, - "right": 0, - "overflow": "hidden" - } -}); - -module.exports = Home diff --git a/app/containers/Message.js b/app/containers/Message.js deleted file mode 100644 index 5be37c9f..00000000 --- a/app/containers/Message.js +++ /dev/null @@ -1,92 +0,0 @@ -// Require module -var React = require('react-native') -var ScrollableTabView = require('react-native-scrollable-tab-view') - - -var MessagePage = require('../components/MessagePage') -var TabBar = require('../components/TabBar') -var Return = require('../components/overlay/Return') -var MarkAsReadOverlay = require('../components/overlay/MarkAsReadOverlay') - - -var window = require('../util/window') -var { width, height } = window.get() - -var { - View, - Text, - Component, - StyleSheet - } = React - - -class Message extends Component { - constructor(props) { - super(props) - this.state = { - didFocus: false - } - } - - - componentDidMount() { - this.props.actions.getMessages(this.props.state.user.token) - } - - - componentDidFocus() { - this.setState({ - didFocus: true - }) - } - - - render() { - let message = this.props.state.message - let didFocus = this.state.didFocus - let hasNotReadCount = message.hasNotRead.length - let hasReadCount = message.hasRead.length - - return ( - - TabBar}> - - - - - - - - ) - } -} - - -var styles = StyleSheet.create({ - container: { - backgroundColor: 'white', - height: height - } -}) - - -module.exports = Message diff --git a/app/containers/Navitation.js b/app/containers/Navitation.js deleted file mode 100644 index 46f05aec..00000000 --- a/app/containers/Navitation.js +++ /dev/null @@ -1,74 +0,0 @@ -var React = require('react-native') -var Home = require('./Home') -var Router = require('../configs/Router') - -var { - PropTypes, - Component, - Navigator - } = React - - -class Navitation extends Component { - constructor(props) { - super(props) - this.initialRoute = { - name: 'home', - index: 0, - component: Home - } - } - - - componentDidMount() { - this.props.actions.getLoginUserFromStorage() - this.props.actions.getAllTopicsFromStorage() - - this.navigator.navigationContext.addListener('didfocus', e => { - let route = e.data.route - this[route.name] && this[route.name].componentDidFocus && this[route.name].componentDidFocus() - }) - } - - - renderScene(route, navigator) { - this.router = this.router || new Router(navigator) - if (route.component) { - return React.createElement(route.component, Object.assign({}, route.props, - { - ref: view=>this[route.name] = view, - actions: this.props.actions, - state: this.props.state, - router: this.router - } - )) - } - } - - - configureScene(route) { - if (route.sceneConfig) { - return route.sceneConfig - } - return Navigator.SceneConfigs.FloatFromRight - } - - - render() { - return ( - this.navigator=view} - initialRoute={this.initialRoute} - configureScene={this.configureScene.bind(this)} - renderScene={this.renderScene.bind(this)} - /> - ) - } -} - -Navitation.propTypes = { - actions: PropTypes.object -} - - -module.exports = Navitation diff --git a/app/containers/NoderApp.js b/app/containers/NoderApp.js deleted file mode 100644 index 48b899c9..00000000 --- a/app/containers/NoderApp.js +++ /dev/null @@ -1,42 +0,0 @@ -var React = require('react-native') -var Redux = require('redux') -var Navigation = require('./Navitation') -var NoderActions = require('../actions') - -var {bindActionCreators} = Redux - -var { - Connector - } = require('redux/react-native') - -var { - Component, - Navigator - } = React - - -class NoderApp extends Component { - constructor(props) { - super(props) - } - - - render() { - return ( - state}> - {this.renderChild} - - ) - } - - - renderChild(state) { - var actions = bindActionCreators(NoderActions, state.dispatch) - return ( - - ) - } -} - - -module.exports = NoderApp diff --git a/app/containers/Publish.js b/app/containers/Publish.js deleted file mode 100644 index b4296d31..00000000 --- a/app/containers/Publish.js +++ /dev/null @@ -1,357 +0,0 @@ -var React = require('react-native') -var { Icon } = require('react-native-icons') -var Modal = require('react-native-modal') -var precomputeStyle = require('precomputeStyle') -var KeyboardEvents = require('react-native-keyboardevents') -var KeyboardEventEmitter = KeyboardEvents.Emitter - -var Nav = require('../components/Nav') -var Loading = require('../components/overlay/Loading') - -var TopicService = require('../services/TopicService') - -var window = require('../util/window') -var { width, height } = window.get() -var config = require('../configs/config') - - -var { - Component, - View, - Text, - StyleSheet, - PickerIOS, - TouchableOpacity, - TextInput, - ScrollView - } = React - - -var PickerItemIOS = PickerIOS.Item - - -class Publish extends Component { - constructor(props) { - super(props) - this.tabs = { - ask: '问答', - share: '分享', - job: '招聘' - } - this.state = { - selectTab: 'share', - isPickerShow: false, - dirty: false, - isPublishing: false - } - this.updateKeyboardSpace = this.updateKeyboardSpace.bind(this) - this.resetKeyboardSpace = this.resetKeyboardSpace.bind(this) - } - - - updateKeyboardSpace(frames) { - this.contentInput.setNativeProps({ - height: contentHeight - frames.end.height - }) - } - - resetKeyboardSpace() { - this.contentInput.setNativeProps({ - height: contentHeight - }) - } - - - componentDidMount() { - KeyboardEventEmitter.on(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace) - KeyboardEventEmitter.on(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace) - } - - componentWillUnmount() { - KeyboardEventEmitter.off(KeyboardEvents.KeyboardDidShowEvent, this.updateKeyboardSpace) - KeyboardEventEmitter.off(KeyboardEvents.KeyboardWillHideEvent, this.resetKeyboardSpace) - } - - - _blur() { - this.titleInput.blur() - this.contentInput.blur() - } - - - _validateForm() { - if (!this.state.dirty) { - return window.alert('请选择要发布的板块!') - } - - - if (!this.titleInputValue || this.titleInput == '') { - return window.alert('标题不能为空!') - } - - if (!this.contentInputValue || this.contentInput == '') { - return window.alert('你还没写东西呢!') - } - - if (this.titleInputValue.length <= 10) { - return window.alert('标题字数必须在10字以上!') - } - - return true - } - - - _submit() { - if (this.state.isPublishing || !this._validateForm()) return - - this.setState({ - isPublishing: true - }) - TopicService.req.publish(this.titleInputValue, this.state.selectTab, this.contentInputValue, this.props.state.user.token) - .then(topicId=> { - this.props.router.replaceWithTopic({ - topicId: topicId, - from: 'html' - }) - }) - .catch(err=> { - console.log(err) - window.alert('发布帖子失败!') - }) - .done(()=> { - this.setState({ - isPublishing: false - }) - }) - } - - - _onPickerPress() { - this.setState({ - isPickerShow: true, - dirty: true - }) - this._blur() - } - - - _onPickerValueChange(tab) { - this.setState({ - selectTab: tab - }) - } - - - _closeModal() { - this.setState({ - isPickerShow: false - }) - } - - - _renderPickerContent() { - return Object.keys(this.tabs).map(tab=> { - return ( - - ) - }) - } - - - render() { - var router = this.props.router - - var navs = { - Left: { - text: '返回', - onPress: ()=> { - router.pop() - this._blur() - } - }, - Center: { - text: '发表帖子' - }, - Right: { - text: '发布', - onPress: ()=> this._submit() - } - } - - - return ( - - - - this.contentView=view} - style={styles.content}> - - - - - - {this.state.dirty ? this.tabs[this.state.selectTab] : '请选择板块'} - - - - - - - - - - this.titleInput=view} - placeholder='请输入标题' - style={styles.titleInput} - onChangeText={(text) => { - this.titleInputValue = text - }} - /> - - - - this.contentInput=view} - value={'\n'+config.replySuffix} - style={styles.topicContent} - multiline={true} - onChangeText={(text) => { - this.contentInputValue = text - }} - /> - - - - - this._closeModal()}> - - - - - {this._renderPickerContent()} - - - - - - - - - - ) - } -} - - -var textColor = 'rgba(0,0,0,0.7)' -var contentHeight = height - 51 * 2 - Nav.navHeight - -var styles = StyleSheet.create({ - container: { - height: height, - width: width, - backgroundColor: 'white' - }, - row: { - height: 51, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - borderBottomColor: 'rgba(0,0,0,0.03)', - borderBottomWidth: 1 - }, - selectorIcon: { - height: 20, - width: 20 - }, - labelIcon: { - marginRight: 15 - }, - tabSelectorText: { - flex: 1, - color: textColor - }, - titleInput: { - height: 50, - flex: 1, - color: textColor, - fontSize: 14 - }, - content: { - paddingRight: 15, - paddingLeft: 15 - }, - topicContent: { - flexDirection: 'row', - alignItems: 'flex-start', - justifyContent: 'space-between', - paddingTop: 20, - height: contentHeight - } -}) - - -var modalStyles = StyleSheet.create({ - container: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - backgroundColor: 'transparent', - justifyContent: 'flex-end', - }, - backdrop: { - position: 'absolute', - top: 0, - bottom: 0, - left: 0, - right: 0, - backgroundColor: '#000000', - opacity: 0.07, - }, - modal: { - backgroundColor: 'white', - - } -}) - - -module.exports = Publish - - diff --git a/app/containers/QRCode.js b/app/containers/QRCode.js deleted file mode 100644 index 3f4f51ca..00000000 --- a/app/containers/QRCode.js +++ /dev/null @@ -1,172 +0,0 @@ -var React = require('react-native') -var Camera = require('react-native-camera') -var { Icon, } = require('react-native-icons') -var Button = require('react-native-button') - - -var window = require('../util/window') -var { width, height } = window.get() - - -var { - StyleSheet, - View, - Text, - TouchableOpacity, - Component, - Navigator, - VibrationIOS - } = React; - -var cameraSize = 250 -var borderColor = 'rgba(255,255,255,0.6)' -var borderBoxSize = 35 - -var styles = StyleSheet.create({ - camera: { - width: width, - height: height, - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center' - }, - header: { - height: 80, - width: 350, - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center' - }, - cameraView: { - height: cameraSize, - width: cameraSize, - }, - container: { - height: 350 - }, - borderBox: { - position: 'absolute', - borderWidth: 2, - height: borderBoxSize, - width: borderBoxSize - }, - borderLeftTop: { - borderColor: 'transparent', - borderLeftColor: borderColor, - borderTopColor: borderColor, - left: 0, - top: 0 - }, - borderRightTop: { - borderColor: 'transparent', - borderRightColor: borderColor, - borderTopColor: borderColor, - right: 0, - top: 0 - }, - borderLeftBottom: { - borderColor: 'transparent', - borderLeftColor: borderColor, - borderBottomColor: borderColor, - left: 0, - bottom: 0 - }, - borderRightBottom: { - borderColor: 'transparent', - borderRightColor: borderColor, - borderBottomColor: borderColor, - right: 0, - bottom: 0 - }, - infoText: { - color: 'rgba(255,255,255,0.7)', - textAlign: 'center', - marginTop: 40, - fontSize: 24 - }, - closeButton: { - width: 35, - height: 35 - }, - closeIcon: { - width: 35, - height: 35, - borderRadius: 35 / 2, - backgroundColor: 'rgba(0,0,0,0.4)' - }, - buttonWrapper: { - width: 35, - height: 35, - position: 'absolute', - right: 30, - top: 0 - } - -}) - - -class QRCode extends Component { - constructor(props) { - super(props) - this.succesed = false - } - - _onBarCodeRead(result) { - if (this.succesed) return - - var self = this - self.succesed = true - VibrationIOS.vibrate() - this.props.actions.checkToken(result.data) - this.props.router.pop() - } - - _onClosePress() { - this.props.router.pop() - } - - render() { - return ( - - - - - - - - - - - - - - - - - - - - 请将二维码放到框内 - - - - - - ) - } -} - - -module.exports = QRCode; diff --git a/app/containers/Topic.js b/app/containers/Topic.js deleted file mode 100644 index b5842f33..00000000 --- a/app/containers/Topic.js +++ /dev/null @@ -1,299 +0,0 @@ -// Require module -var React = require('react-native') - -var moment = require('moment') -var { Icon } = require('react-native-icons') - - -// Component module -var HtmlContent = require('../components/htmlRender/HtmlContent') -var Return = require('../components/overlay/Return') -var CommentOverlay = require('../components/overlay/CommentOverlay') - - -// Config module -var config = require('../configs/config') - - -// Util module -var genColor = require('../util/genColor') -var TopicService = require('../services/TopicService') -var window = require('../util/window') -var { width, height } = window.get() - - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - Image, - ListView, - ActivityIndicatorIOS, - TouchableOpacity, - TouchableHighlight, - Navigator - } = React; - - -var topicHeaderHeight = 100; -var topicAuthorWidth = 100; -var headerPaddingTop = 20; -var authorImgHeight = 40; -var contentPadding = 15; - - -var styles = StyleSheet.create({ - container: { - flex: 1, - width: width, - backgroundColor: 'white', - height: height - }, - header: { - //height: topicHeaderHeight, - flex: 1, - alignItems: 'center', - justifyContent: 'space-between', - //backgroundColor: 'red', - flexDirection: 'row', - //paddingTop: 20, - paddingRight: 20, - paddingLeft: 20 - }, - authorTouchable: { - //width: topicAuthorWidth, - //backgroundColor: 'rgba(0,0,0,0.6)' - }, - authorWrapper: { - //height: topicHeaderHeight - headerPaddingTop, - width: topicAuthorWidth - 40, - //backgroundColor: 'blue', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'space-between' - }, - authorImg: { - width: authorImgHeight, - height: authorImgHeight, - borderRadius: authorImgHeight / 2 - }, - author: { - paddingBottom: 12, - color: 'rgba(255,255,255,0.7)', - fontSize: 12 - }, - titleWrapper: { - width: width - topicAuthorWidth - 20, - flexDirection: 'column', - paddingTop: 20, - paddingBottom: 20 - }, - title: { - color: 'rgba(255,255,255,0.9)', - width: width - topicAuthorWidth - 20, - justifyContent: 'flex-end', - flex: 1, - lineHeight: 1.2 * 16 - }, - titleFooter: { - flex: 1, - flexDirection: 'row', - alignItems: 'flex-end', - justifyContent: 'space-between', - marginTop: 20 - }, - date: { - width: 100, - flexDirection: 'row', - }, - dateText: { - color: 'rgba(255,255,255,0.5)', - fontSize: 12 - }, - dateIcon: { - width: 12, - height: 16, - marginRight: 8 - }, - like: { - width: 20, - flexDirection: 'row', - }, - likeIcon: { - width: 20, - height: 16, - marginRight: 8 - }, - content: { - paddingRight: contentPadding, - paddingLeft: contentPadding, - paddingTop: contentPadding, - paddingBottom: contentPadding, - backgroundColor: 'white' - }, - -}) - - -class Topic extends Component { - constructor(props) { - super(props) - this.headerColor = genColor() - this.state = { - likedLoading: false, - topic: this.props.topic, - isLoading: false, - didFocus: false - } - } - - - componentDidMount() { - if (this.props.from == 'user') { - return this._fetchTopic(this.state.topic.id) - } - - if (this.props.from == 'html') { - return this._fetchTopic(this.props.topicId) - } - } - - - componentDidFocus() { - this.setState({ - didFocus: true - }) - } - - - _fetchTopic(id) { - this.setState({ - isLoading: true - }) - TopicService.req.getTopicById(id) - .then(topic=> { - this.setState({ - isLoading: false, - topic: topic - }) - }) - .catch(err => { - console.warn(err) - this.setState({ - isLoading: false - }) - }) - .done() - } - - - _onCommentOverlayPress() { - this.props.router.toComments({ - topic: this.state.topic, - from: 'topic' - }) - } - - - _onAuthorImgPress(authorName) { - this.props.router.toUser({ - userName: authorName - }) - } - - - _renderContent(content) { - if (this.state.didFocus && content) { - return ( - - ) - } - - - return ( - - ) - } - - - render() { - var topic = this.state.topic - - - if (topic) { - var imgUri = window.parseImgUrl(topic.author.avatar_url) - var authorName = topic.author.loginname - var date = moment(topic.create_at).startOf('minute').fromNow() - return ( - - - - - - - - - - - - - - - - {topic.title} - - - - - - - {date} - - - - - - - - - {this._renderContent(topic.content)} - - - - - - ) - } - - return ( - - - - ) - - } -} - - -module.exports = Topic; diff --git a/app/containers/User.js b/app/containers/User.js deleted file mode 100644 index 9bab8dac..00000000 --- a/app/containers/User.js +++ /dev/null @@ -1,318 +0,0 @@ -// React-Native Module -var React = require('react-native') -var moment = require('moment') -var ScrollableTabView = require('react-native-scrollable-tab-view') -var { Icon, } = require('react-native-icons') - - -// Custom Component -var UserTopicPage = require('../components/UserTopicPage') -var Return = require('../components/overlay/Return') -var TabBar = require('../components/TabBar') -var Setting = require('../components/Setting') - - -var genColor = require('../util/genColor') -var UserService = require('../services/UserService') -var window = require('../util/window') -var { width, height } = window.get() - -var { - View, - StyleSheet, - ScrollView, - Component, - Text, - StatusBarIOS, - Image, - ListView, - TouchableHighlight, - TouchableOpacity, - Navigator, - ActivityIndicatorIOS, - LayoutAnimation - } = React - - -class User extends Component { - constructor(props) { - super(props) - this.state = { - userInfo: null, - wallColor: genColor(), - didFocus: false, - isSettingModalOpen: false - } - } - - - componentDidMount() { - if (this.props.isLoginUser) { - this.props.actions.fetchUser(this.props.state.user) - } - else { - this._getUserInfo() - } - } - - - componentDidFocus() { - LayoutAnimation.configureNext(LayoutAnimation.Presets.spring); - this.setState({ - didFocus: true - }) - } - - - _onGithubPress(name) { - if (name == '' || !name) return - window.link('https://github.com/' + name) - } - - - onSettingModalClosePress() { - this.setState({ - isSettingModalOpen: false - }) - } - - - onSettingIconPress() { - this.setState({ - isSettingModalOpen: true - }) - } - - - _getUserInfo() { - let userName = this.props.userName - - UserService.req.getUserInfo(userName) - .then(userInfo=> { - console.log('get userINfo'); - this.setState({ - userInfo: userInfo - }) - }) - .catch(err=> { - console.warn(err) - if (err == 'UserNotExist') { - window.alert('用户不存在') - this.props.router.pop() - } - }) - .done() - } - - - _renderUserTopics(userInfo) { - let recentReplies = userInfo.recent_replies - let recentTopics = userInfo.recent_topics - if (this.state.didFocus) { - return ( - - TabBar}> - - - - - ) - } - - if (this.props.isLoginUser) { - return ( - - ) - } - - } - - - render() { - var userInfo = this.state.userInfo - - let isLoginUser = this.props.isLoginUser - - if (isLoginUser) { - userInfo = this.props.state.user - } - - if (!userInfo) { - return ( - - - - - ) - } - let imgUri = window.parseImgUrl(userInfo.avatar_url) - let createTime = moment(userInfo.create_at).format('l') - let authorName = userInfo.loginname - let githubName = userInfo.githubUsername - let pubTopicIcon = ( - { - this.props.router.toPublish() - }} - > - - - ) - - let settingIcon = ( - - - - ) - - return ( - - - - - {isLoginUser ? pubTopicIcon : null} - - - - - - - {isLoginUser ? settingIcon : null} - - - - - - - {authorName} - - - - - - - {'注册时间: ' + createTime} - - - - {'积分:' + userInfo.score} - - - - {this._renderUserTopics(userInfo)} - - - - - - - ) - } -} - -var bgWallHeight = 160 -var authorWrapperHeight = 100 -var authorImgSize = 60 -var fontColor = 'rgba(255,255,255,0.7)' - -var styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: 'white' - }, - loading: { - flex: 1, - width: width - }, - bgWall: { - height: bgWallHeight, - flexDirection: 'column', - justifyContent: 'space-between', - alignItems: 'center', - paddingTop: 30, - paddingBottom: 10 - }, - imgRow: { - width: width, - flexDirection: 'row', - justifyContent: 'space-around' - }, - icon: { - width: 30, - height: authorImgSize - }, - authorWrapper: { - height: authorWrapperHeight, - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'space-between' - }, - authorImg: { - height: authorImgSize, - width: authorImgSize, - borderRadius: authorImgSize / 2 - }, - bgWallFooter: { - flexDirection: 'row', - justifyContent: 'space-between', - width: width - }, - bgWallFooterText: { - paddingLeft: 10, - paddingRight: 10, - fontSize: 12, - color: 'rgba(255,255,255,0.6)' - }, - github: { - color: fontColor - }, - userTopicPage: { - height: height - bgWallHeight - 70 - }, - list: { - width: width - } - -}) - - -module.exports = User - - diff --git a/app/mocks/topic.js b/app/mocks/topic.js deleted file mode 100644 index 9c9039c0..00000000 --- a/app/mocks/topic.js +++ /dev/null @@ -1,128 +0,0 @@ -module.exports = { - "data": { - "id": "55604d9c4eb040084cfe5d4a", - "author_id": "51ed5627f4963ade0ea60395", - "tab": "share", - "content": "

Markdown 语法简明手册

\n
\n

$ 表示行内公式:\n质能守恒方程可以用一个很简洁的方程式 $E=mc^2$ 来表达

\n
\n

1. 使用 * 和 ** 表示斜体和粗体

\n

示例:

\n

这是 斜体,这是 粗体

\n

2. 使用 === 表示一级标题,使用 — 表示二级标题

\n

示例:

\n

这是一个一级标题

\n

这是一个二级标题

\n

这是一个三级标题

\n

这是个四级标题

\n
这是个五级标题
\n
这是个六级标题
\n

你也可以选择在行首加井号表示不同级别的标题,例如:# H1, ## H2, ### H3。

\n

3. 使用 [描述](链接地址) 为文字增加外链接

\n

示例:

\n

这是去往 本人博客 的链接。

\n

4. 在行末加两个空格表示换行

\n

示例:

\n

第一行(此行最右有两个看不见的空格)
\n第二行

\n

5. 使用 *,+,- 表示无序列表

\n

示例:

\n
    \n
  • 无序列表项 一
  • \n
  • 无序列表项 二
  • \n
  • 无序列表项 三
  • \n
\n

6. 使用数字和点表示有序列表

\n

示例:

\n
    \n
  1. 有序列表项 一
  2. \n
  3. 有序列表项 二
  4. \n
  5. 有序列表项 三
  6. \n
\n

7. 使用 > 表示文字引用

\n

示例:

\n
\n

野火烧不尽,春风吹又生

\n
\n

8. 使用 `代码` 表示行内代码块

\n

示例:

\n

让我们聊聊 html

\n

9. 使用 四个缩进空格 表示代码块

\n

示例:

\n
这是一个代码块,此行左侧有四个不可见的空格\n

10. 使用 ![描述](图片链接地址) 插入图像

\n

示例:

\n

\"IMG_0417.PNG\"

\n

\"我的头像\"

\n

Cmd 高阶语法手册

\n

1. LaTeX 公式,表达式支持

\n

$ 表示行内公式:

\n

质能守恒方程可以用一个很简洁的方程式 $E=mc^2$ 来表达

\n

$$ 表示整行公式:

\n

$$\\sum_{i=1}^n a_i=0$$

\n

$$f(x_1,x_x,\\ldots,x_n) = x_1^2 + x_2^2 + \\cdots + x_n^2 $$

\n

$$\\sum^{j-1}{k=0}{\\widehat{\\gamma}{kj} z_k}$$

\n

2. 加强的代码块,支持四十一种编程语言的语法高亮的显示,行号显示

\n

非代码示例:

\n
$ sudo apt-get install vim-gnome\n

Python 示例:

\n
@requires_authorization\ndef somefunc(param1='', param2=0):\n    '''A docstring'''\n    if param1 > param2: # interesting\n        print 'Greater'\n    return (param2 - param1 + 1) or None\n\nclass SomeClass:\n    pass\n\n>>> message = '''interpreter\n... prompt'''\n

JavaScript 示例:

\n
/**\n* nth element in the fibonacci series.\n* @param n >= 0\n* @return the nth element, >= 0.\n*/\nfunction fib(n) {\n  var a = 1, b = 1;\n  var tmp;\n  while (--n >= 0) {\n    tmp = a;\n    a += b;\n    b = tmp;\n  }\n  return a;\n}\n\ndocument.write(fib(10));\n

3. 表格支持

\n

示例:

\n\n\n\n\n\n\n\n\n\n
项目价格数量
计算机$16005
手机$1212
管线$1234
\n

4. 定义型列表

\n

名词 1\n: 定义 1(左侧有一个可见的冒号和四个不可见的空格)

\n

代码块 2\n: 这是代码块的定义(左侧有一个可见的冒号和四个不可见的空格)

\n
    代码块(左侧有八个不可见的空格)\n

\n
", - "title": "请勿删除此贴,正在调试react-native cnode客户端html渲染", - "last_reply_at": "2015-06-23T09:00:32.914Z", - "good": false, - "top": false, - "reply_count": 12, - "visit_count": 636, - "create_at": "2015-05-23T09:51:24.233Z", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "replies": [{ - "id": "55618d248f294e213d10b82c", - "author": { - "loginname": "alsotang", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F1147375%3Fv%3D3%26s%3D120" - }, - "content": "

好用心地在调整格式啊

\n
", - "ups": [], - "create_at": "2015-05-24T08:34:44.076Z" - }, { - "id": "556190258f294e213d10b831", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "content": "

先来点谍照。。。。

\n

\"IMG_0417.PNG\"

\n

\"IMG_0418.PNG\"

\n

\"IMG_0420.PNG\"

\n
![IMG_0421.PNG](//dn-cnode.qbox.me/Fi93MaU3HXiaBu8mt8LBWr4FODXY)
", - "ups": ["551a5c05687c387d2f5b2bff"], - "create_at": "2015-05-24T08:47:33.126Z" - }, { - "id": "556190828f294e213d10b832", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "content": "

渲染html时没用webview哦,用得本地视图来显示的哦

\n
", - "ups": [], - "create_at": "2015-05-24T08:49:06.798Z" - }, { - "id": "5561e0dd8f294e213d10b864", - "author": { - "loginname": "WangZishi", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F8288105%3Fv%3D3%26s%3D120" - }, - "content": "

期待啊\n自豪地采用 CNodeJS ionic

\n
", - "ups": [], - "create_at": "2015-05-24T14:31:57.215Z" - }, { - "id": "5562a8288f294e213d10b8f9", - "author": { - "loginname": "booxood", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2F124ea13daf1648975e002b3c5e89d7e2%3Fsize%3D48" - }, - "content": "

\n
", - "ups": [], - "create_at": "2015-05-25T04:42:16.211Z" - }, { - "id": "5562b7f28f294e213d10b913", - "author": { - "loginname": "thondery", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F7646730%3Fv%3D3%26s%3D120" - }, - "content": "

好漂亮,期待试用

\n
", - "ups": [], - "create_at": "2015-05-25T05:49:38.556Z" - }, { - "id": "5562c3ce8f294e213d10b920", - "author": { - "loginname": "ilanceli", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F874744%3Fv%3D3%26s%3D120" - }, - "content": "

赞\n不过lz最好自己搭个测试环境

\n
", - "ups": [], - "create_at": "2015-05-25T06:40:14.832Z" - }, { - "id": "556547867d4c64752effb524", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "content": "

@ilanceli 没搭,干脆就这么滴了

\n
", - "ups": [], - "create_at": "2015-05-27T04:26:46.910Z" - }, { - "id": "556566207d4c64752effb545", - "author": { - "loginname": "jysperm", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F1191561%3Fv%3D3%26s%3D120" - }, - "content": "

感觉网页版的样式也要调一调 …

\n
", - "ups": [], - "create_at": "2015-05-27T06:37:20.821Z" - }, { - "id": "5565db1ebf0bd1f1570a0036", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "content": "

@jysperm 要不你来调一调嘛,网页版的确实也需要改进啊\n自豪地采用 CNodeJS ionic

\n
", - "ups": [], - "create_at": "2015-05-27T14:56:30.466Z" - }, { - "id": "5589202301d3ce0d73d69106", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "content": "

9. 使用 四个缩进空格 表示代码块

\n

示例:

\n
这是一个代码块,此行左侧有四个不可见的空格\n

10. 使用 ![描述](图片链接地址) 插入图像

\n

示例:

\n

\"我的头像\"

\n
", - "ups": [], - "create_at": "2015-06-23T09:00:19.652Z" - }, { - "id": "5589203001d3ce0d73d69108", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "content": "

@soliury ### 9. 使用 四个缩进空格 表示代码块

\n

示例:

\n
这是一个代码块,此行左侧有四个不可见的空格\n

10. 使用 ![描述](图片链接地址) 插入图像

\n

示例:

\n

\"我的头像\"

\n
", - "ups": [], - "create_at": "2015-06-23T09:00:32.897Z" - }] - } -} \ No newline at end of file diff --git a/app/mocks/userInfo.js b/app/mocks/userInfo.js deleted file mode 100644 index edee20fb..00000000 --- a/app/mocks/userInfo.js +++ /dev/null @@ -1,372 +0,0 @@ -module.exports = { - "data": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120", - "githubUsername": "soliury", - "create_at": "2013-07-22T15:56:23.097Z", - "score": 1275, - "recent_topics": [{ - "id": "55604d9c4eb040084cfe5d4a", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "title": "请勿删除此贴,正在调试react-native cnode客户端html渲染", - "last_reply_at": "2015-07-02T10:08:24.522Z" - }, { - "id": "55561c2e7cabb7b45ee6bc69", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "title": "【Gulp Tips】错误处理", - "last_reply_at": "2015-05-15T16:17:50.185Z" - }, { - "id": "5552fc48c62bb7483db55101", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "title": "【Gulp Tips】如何正确地删除文件", - "last_reply_at": "2015-05-13T07:24:56.959Z" - }, { - "id": "5551b1cf7664e06d7cd471a6", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "title": "【Gulp Tips】gulp流为何流", - "last_reply_at": "2015-05-12T14:21:21.231Z" - }, { - "id": "5551a6067664e06d7cd4718f", - "author": { - "loginname": "soliury", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5032079%3Fv%3D3%26s%3D120" - }, - "title": "关于gulp", - "last_reply_at": "2015-05-13T10:46:18.039Z" - }], - "recent_replies": [{ - "id": "5595f55547e6bdc30297ed8b", - "author": { - "loginname": "meiguixu", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F13146138%3Fv%3D3%26s%3D120" - }, - "title": "【巨头联手:阿里巴巴+SMG】平台广阔,坐标上海,第一财经高薪招募RUBY及WEB开发工程师", - "last_reply_at": "2015-07-03T02:50:38.925Z" - }, { - "id": "55955f2147e6bdc30297ecd7", - "author": { - "loginname": "zenghongyujia123", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F7914166%3Fv%3D3%26s%3D120" - }, - "title": "[上海]已拿A轮融资的互联网+物流创业新军 - 底薪180K+ 和 15K+期权 颜值(高)味道(爆)与环境 (爽),诚聘 js 程序员 !", - "last_reply_at": "2015-07-03T04:25:46.068Z" - }, { - "id": "5595402b47e6bdc30297ecb7", - "author": { - "loginname": "mmXiaoYao", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F13150693%3Fv%3D3%26s%3D120" - }, - "title": "velocity.Parser and velocity.Compile", - "last_reply_at": "2015-07-02T13:59:55.532Z" - }, { - "id": "5594f0a047e6bdc30297ebf4", - "author": { - "loginname": "youlong723687543", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F13144449%3Fv%3D3%26s%3D120" - }, - "title": "技术世界一片茫然", - "last_reply_at": "2015-07-03T00:25:20.826Z" - }, { - "id": "5594ed6947e6bdc30297ebeb", - "author": { - "loginname": "somonus", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5165612%3Fv%3D3%26s%3D120" - }, - "title": "[杭州-滨江] 阿里巴巴数据产品部招聘前端/全端工程师", - "last_reply_at": "2015-07-03T01:39:29.849Z" - }], - "collect_topics": [{ - "id": "55928df39418ff516f650e6b", - "author": { - "loginname": "DavidCai1993", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5886475%3Fv%3D3%26s%3D120" - }, - "title": "分享一个自己翻译的io.js API 中文文档(完成度100%)", - "last_reply_at": "2015-07-03T04:38:05.380Z" - }, { - "id": "5590adbbebf9c92d17e734de", - "author": { - "loginname": "i5ting", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F3118295%3Fv%3D3%26s%3D120" - }, - "title": "mongodb运维之副本集实践", - "last_reply_at": "2015-07-01T08:00:54.885Z" - }, { - "id": "558d1453ebf9c92d17e732fa", - "author": { - "loginname": "PaulGuo", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F758740%3Fv%3D3%26s%3D120" - }, - "title": "美团酒店Node全栈开发实践", - "last_reply_at": "2015-07-01T04:00:23.493Z" - }, { - "id": "558b6b92c31358754d3aa3cd", - "author": { - "loginname": "i5ting", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F3118295%3Fv%3D3%26s%3D120" - }, - "title": "sails vs meteor之sails篇", - "last_reply_at": "2015-06-30T01:17:55.285Z" - }, { - "id": "558a80b0c31358754d3aa343", - "author": { - "loginname": "turing", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2Ffd05a307dcd03fdef795a3c9810ae667%3Fsize%3D48" - }, - "title": "聊聊实时 Node 应用性能监测的实现", - "last_reply_at": "2015-07-03T04:04:14.020Z" - }, { - "id": "55815f28395a0c1812f18257", - "author": { - "loginname": "i5ting", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F3118295%3Fv%3D3%26s%3D120" - }, - "title": "Koa 还是 Express?", - "last_reply_at": "2015-06-24T13:22:20.747Z" - }, { - "id": "557c354d16839d2d539362b6", - "author": { - "loginname": "luoyjx", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4217102%3Fv%3D3%26s%3D120" - }, - "title": "分享下重放攻击的概念", - "last_reply_at": "2015-06-16T05:46:03.935Z" - }, { - "id": "55778225c4e7fbea6e9a3357", - "author": { - "loginname": "i5ting", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F3118295%3Fv%3D3%26s%3D120" - }, - "title": "Nodejs RESTFul架构实践", - "last_reply_at": "2015-06-14T12:47:37.356Z" - }, { - "id": "5536708e48636414313a72ff", - "author": { - "loginname": "i5ting", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F3118295%3Fv%3D3%26s%3D120" - }, - "title": "使用config来管理配置文件", - "last_reply_at": "2015-04-23T15:17:00.088Z" - }, { - "id": "552b3b9382388cec50cf6d95", - "author": { - "loginname": "i5ting", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F3118295%3Fv%3D3%26s%3D120" - }, - "title": "客户端 API 开发总结", - "last_reply_at": "2015-06-24T01:59:19.938Z" - }, { - "id": "5524989ab50122cc0bf6d60e", - "author": { - "loginname": "2596887568", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F9349200%3Fv%3D3%26s%3D120" - }, - "title": "AngularJS的启动引导过程", - "last_reply_at": "2015-04-08T10:51:50.328Z" - }, { - "id": "551802d3687c387d2f5b2906", - "author": { - "loginname": "JerryC8080", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F6801672%3Fv%3D3%26s%3D120" - }, - "title": "基于RESTful API 怎么设计用户权限控制?", - "last_reply_at": "2015-05-27T01:19:10.861Z" - }, { - "id": "551200e6d792542a29789a43", - "author": { - "loginname": "tw93", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F8736212%3Fv%3D3%26s%3D120" - }, - "title": "深入浅出Nodejs读书笔记", - "last_reply_at": "2015-06-11T04:53:25.330Z" - }, { - "id": "54b3fc05edf686411e1b9ce1", - "author": { - "loginname": "wewoor", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F2766811%3Fv%3D3%26s%3D120" - }, - "title": "谁也阻挡不了我穿墙!!搭建自己的VPN", - "last_reply_at": "2015-01-29T12:15:12.992Z" - }, { - "id": "549ec1388ade094b67f3fdb4", - "author": { - "loginname": "i5ting", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F3118295%3Fv%3D3%26s%3D120" - }, - "title": "关于sloc", - "last_reply_at": "2014-12-28T14:59:02.225Z" - }, { - "id": "5475befe65e5a201268b9193", - "author": { - "loginname": "wizardforcel", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5080126%3Fv%3D3%26s%3D120" - }, - "title": "W3School 教程整理", - "last_reply_at": "2014-12-07T01:10:08.412Z" - }, { - "id": "546c0b721c825b0c4d79e84a", - "author": { - "loginname": "zengliqi", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F9347370%3Fv%3D3%26s%3D120" - }, - "title": "也谈如何构建高性能服务端程序", - "last_reply_at": "2014-11-19T03:56:27.098Z" - }, { - "id": "546a08fa7981ed441bdda690", - "author": { - "loginname": "pockry", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2F530c7eeafcacfbe52827a98c6a4a1358%3Fsize%3D48" - }, - "title": "passport.js学习笔记", - "last_reply_at": "2014-11-24T03:11:08.567Z" - }, { - "id": "545628badcf5d4372651d18c", - "author": { - "loginname": "justjavac", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F359395%3Fv%3D3%26s%3D120" - }, - "title": "开发者必备的 Chrome 扩展", - "last_reply_at": "2014-11-02T15:19:26.933Z" - }, { - "id": "5450e433d0c2f0fe2f5339dc", - "author": { - "loginname": "laomayi", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2F2da2a62c55430459e62a6cdb41a41a06%3Fsize%3D48" - }, - "title": "我用NodeJS写了个DHT爬虫, 发现比Python写出的还牛逼!", - "last_reply_at": "2014-10-31T07:08:19.658Z" - }, { - "id": "54474a6b649ac9220757b8c7", - "author": { - "loginname": "justjavac", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F359395%3Fv%3D3%26s%3D120" - }, - "title": "Firebase 相关文章的索引", - "last_reply_at": "2014-10-23T07:01:14.870Z" - }, { - "id": "541414d88518442c6218e15d", - "author": { - "loginname": "lgqlee", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F6489372%3Fv%3D3%26s%3D120" - }, - "title": "大家都是怎么学node的呢?", - "last_reply_at": "2014-09-21T03:46:49.567Z" - }, { - "id": "540880ebf4d8f79a5a0706df", - "author": { - "loginname": "okoala", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F2127199%3Fv%3D3%26s%3D120" - }, - "title": "教你如何快速掌握Chrome DevTools中的各种NB技能~~", - "last_reply_at": "2014-09-06T02:51:21.993Z" - }, { - "id": "53ca1b2d2df7453a44f8ebf4", - "author": { - "loginname": "FuGardenia", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F3283580%3Fv%3D3%26s%3D120" - }, - "title": "全国省市乡镇村地区五级联动", - "last_reply_at": "2014-07-20T05:18:53.891Z" - }, { - "id": "53c652bfc9507b404446ee40", - "author": { - "loginname": "lcjnil", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F5821684%3Fv%3D3%26s%3D120" - }, - "title": "【翻译】在Nodejs中使用JSON WEB Tokens", - "last_reply_at": "2014-07-17T07:02:00.576Z" - }, { - "id": "5354cfdb1969a7b22afbbf82", - "author": { - "loginname": "youqingkui", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F7046903%3Fv%3D3%26s%3D120" - }, - "title": "请问在 Express 4.0 里如何实现上传?", - "last_reply_at": "2015-04-02T00:21:22.285Z" - }, { - "id": "535376501969a7b22aca6d24", - "author": { - "loginname": "nswbmw", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2F11c35a5b58d99d2c8a950165b795917d%3Fsize%3D48" - }, - "title": "学习 Node.js 的 6 个步骤", - "last_reply_at": "2014-08-11T13:41:50.494Z" - }, { - "id": "5203a71844e76d216a727d2e", - "author": { - "loginname": "ggaaooppeenngg", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F4769989%3Fv%3D3%26s%3D120" - }, - "title": "通读cheerio API", - "last_reply_at": "2015-05-11T07:16:24.961Z" - }, { - "id": "51fc8bd944e76d216ab64939", - "author": { - "loginname": "kimady", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2F2c63b57d3c76ccaed06fcc34ba0e8d33%3Fsize%3D48" - }, - "title": "Node.js 对图片进行裁切、缩放 (gm)", - "last_reply_at": "2014-12-04T08:59:47.007Z" - }, { - "id": "5190d61263e9f8a542acd83b", - "author": { - "loginname": "shiedman", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2F849581002e39edc8ffe0cb8b97ee6f12%3Fsize%3D48" - }, - "title": "[技术讨论]mongodb驱动的正确使用方法", - "last_reply_at": "2014-08-20T05:02:55.341Z" - }, { - "id": "516526766d38277306c7d277", - "author": { - "loginname": "lhfcws", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2F19775e24394f727eb342154459370d20%3Fsize%3D48" - }, - "title": "初识 mocha in NodeJS", - "last_reply_at": "2015-06-05T04:19:13.338Z" - }, { - "id": "50aeec5e637ffa41559d2fbe", - "author": { - "loginname": "luofei614", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2Fe45ec2d493a3ffdd0b8a80bb3f8ed5b2%3Fsize%3D48" - }, - "title": "nodejs+cloudfoundry 实现代理服务器。", - "last_reply_at": "2012-11-23T16:08:23.196Z" - }, { - "id": "5076313f25bf229e20212ba8", - "author": { - "loginname": "342479384", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2Fab32ab04dd8ab0a45a6760ae8a466e2a%3Fsize%3D48" - }, - "title": "如何用node.js 获取访问者的公网IP?", - "last_reply_at": "2015-06-15T09:03:11.382Z" - }, { - "id": "504b4924e2b84515770103dd", - "author": { - "loginname": "a272121742", - "avatar_url": "/agent?url=http%3A%2F%2Fwww.gravatar.com%2Favatar%2Fb087595f7b1a3801718f7a04d24add89%3Fsize%3D48" - }, - "title": "Mongoose学习参考文档——基础篇", - "last_reply_at": "2015-05-18T11:01:56.015Z" - }, { - "id": "4fa94df3b92b05485007fd87", - "author": { - "loginname": "JacksonTian", - "avatar_url": "/agent?url=https%3A%2F%2Favatars.githubusercontent.com%2Fu%2F327019%3Fv%3D3%26s%3D120" - }, - "title": "Node内存泄漏专题", - "last_reply_at": "2014-12-05T03:08:30.190Z" - }] - } -} \ No newline at end of file diff --git a/app/reducers/home.js b/app/reducers/home.js deleted file mode 100644 index e9e95adc..00000000 --- a/app/reducers/home.js +++ /dev/null @@ -1,33 +0,0 @@ -var types = require('../constants/ActionTypes') - -var initialState = { - isModalOpen: false, - checkTokenLoading: false -} - - -module.exports = function (state, action) { - state = state || initialState - switch (action.type) { - case types.OPEN_LOGIN_MODAL: - return { - isModalOpen: true - } - case types.CLOSE_LOGIN_MODAL: - return { - isModalOpen: false - } - case types.CHECK_TOKEN_REQUREST: - return { - ...state, - checkTokenLoading: true - } - case types.CHECK_TOKEN_SUCCESS: - return { - isModalOpen: false, - checkTokenLoading: false - } - default : - return state - } -} diff --git a/app/reducers/index.js b/app/reducers/index.js deleted file mode 100644 index 5bc3ec7b..00000000 --- a/app/reducers/index.js +++ /dev/null @@ -1,4 +0,0 @@ -exports.user = require('./user') -exports.home = require('./home') -exports.message = require('./message') -exports.topic = require('./topic') diff --git a/app/reducers/message.js b/app/reducers/message.js deleted file mode 100644 index 7c910345..00000000 --- a/app/reducers/message.js +++ /dev/null @@ -1,76 +0,0 @@ -var types = require('../constants/ActionTypes') - -var initialState = { - isLoading: false, - hasNotRead: [], - hasRead: [], - unreadMessageCount: 0, - isMarkAsReadLoading: false -} - - -module.exports = function (state, action) { - state = state || initialState - - switch (action.type) { - case types.GET_UNREAD_MESSAGE_COUNT_SUCCESS: - return { - ...state, - unreadMessageCount: action.count - } - - case types.GET_MESSAGES: - return { - ...state, - isLoading: true, - unreadMessageCount: action.hasNotRead.length, - hasRead: action.hasRead, - hasNotRead: action.hasNotRead - } - - case types.FETCH_MESSAGES_REQUEST: - return { - ...state, - isLoading: true - } - - case types.FETCH_MESSAGES_SUCCESS: - return { - ...state, - unreadMessageCount: action.hasNotRead.length, - hasRead: action.hasRead, - hasNotRead: action.hasNotRead, - isLoading: false - } - - case types.FETCH_MESSAGES_FAILED: - return { - ...state, - isLoading: false, - } - - case types.MARK_AS_READ_REQUEST: - return { - ...state, - isMarkAsReadLoading: true - } - - case types.MARK_AS_READ_SUCCESS: - return { - ...state, - hasNotRead: [], - hasRead: state.hasNotRead.concat(state.hasRead), - unreadMessageCount: 0, - isMarkAsReadLoading: false - } - - case types.MARK_AS_READ_FAILED: - return { - ...state, - isMarkAsReadLoading: false - } - - default : - return state - } -} diff --git a/app/reducers/topic.js b/app/reducers/topic.js deleted file mode 100644 index 7086fc5a..00000000 --- a/app/reducers/topic.js +++ /dev/null @@ -1,113 +0,0 @@ -//var React = require('react-native') -//var {ListView} = React - - -var types = require('../constants/ActionTypes') - -var tabs = ['good', 'ask', 'all', 'share', 'job'] - -var initialTabState = { - isLoading: true, - topics: [] -} - - -var initialState = {} - - -tabs.forEach(function (tab) { - initialTabState.name = tab - initialState[tab] = Object.assign({}, initialTabState) -}) - - -function getTopicsFromStorage(state, action) { - var {results} = action - - results.forEach((item, index)=> { - state[tabs[index]].topics = item[1] || [] - }) - - return Object.assign({}, state) -} - -function fetchTopicsByTabRequest(state, action) { - var {tab} = action - var tabState = state[tab] - state[tab] = { - ...tabState, - isLoading: true - } - return Object.assign({}, state) - -} - -function fetchTopicsByTabSuccess(state, action) { - var {tab} = action - var tabState = state[tab] - var topics = tabState.topics - var page = state[tab].page - if (action.loadingType == 'get') { - topics = topics.concat(action.topics) - page++ - } - else { - topics = action.topics - page = 1 - } - state[tab] = { - ...tabState, - topics: topics, - isLoading: false, - page: page - } - return Object.assign({}, state) -} - - -function getTopics(state, action) { - var {tab,topics} = action - var tabState = state[tab] - state[tab] = { - ...tabState, - topics: tabState.topics.concat(topics) - } - return Object.assign({}, state) -} - - -function updateTopics(state, action) { - var {tab,topics} = action - var tabState = state[tab] - - state[tab] = { - ...tabState, - topics: topics - } - return Object.assign({}, state) -} - - -module.exports = function (state, action) { - state = state || initialState - - switch (action.type) { - case types.GET_ALL_TOPICS_FROM_STORAGE: - return getTopicsFromStorage(state, action) - - //case types.FETCH_TOPICS_BY_TAB_REQUEST: - // return fetchTopicsByTabRequest(state, action) - // - //case types.FETCH_TOPICS_BY_TAB_SUCCESS: - // return fetchTopicsByTabSuccess(state, action) - - case types.GET_TOPICS: - return getTopics(state, action) - - case types.UPDATE_TOPICS: - return updateTopics(state, action) - - default : - return state - } -} diff --git a/app/reducers/user.js b/app/reducers/user.js deleted file mode 100644 index 720acbee..00000000 --- a/app/reducers/user.js +++ /dev/null @@ -1,51 +0,0 @@ -var types = require('../constants/ActionTypes') - - -var initialState = null - -function unLikeTopic(state, id) { - var collections = state.collect_topics - var index = -1 - for (var i = 0; i < collections.length; i++) { - if (collections[i].id == id) { - index = i - } - } - if (index > -1) { - collections.splice(index, 1) - } - return { - ...state, - collect_topics: collections - } -} - -module.exports = function (state, action) { - state = state || initialState - switch (action.type) { - case types.GET_USER: - return action.user - - - case types.FETCH_USER: - return action.user - - - case types.LIKE_TOPIC: - return { - ...state, - collect_topics: [action.topic].concat(state.collect_topics) - } - - - case types.UN_LIKE_TOPIC: - return unLikeTopic(state, action.id) - - - case types.LOGOUT: - return null - - default: - return state - } -} diff --git a/app/services/MessageService.js b/app/services/MessageService.js deleted file mode 100644 index b1c44269..00000000 --- a/app/services/MessageService.js +++ /dev/null @@ -1,66 +0,0 @@ -var Storage = require('./Storage') -var request = require('./Request') -var config = require('../configs/config') - -var storage = {} - -storage.get = function () { - return Storage.getItem('messages') -} - -storage.save = function (value) { - return Storage.setItem('messages', value) -} - -storage.remove = function () { - return Storage.removeItem('messages') -} - - -var req = {} - -req.get = function (token) { - let apiUrl = config.domain + config.apiPath + '/messages' + '?accesstoken=' + token - - return request.get(apiUrl) - .then((data)=>data.data) - .then((messages)=> { - if (messages) { - storage.save(messages) - return messages - } - else { - throw 'getMessagesFailed' - } - }) -} - -req.markAsRead = function (token) { - let apiUrl = config.domain + config.apiPath + '/message/mark_all' - - return request.post(apiUrl, { - accesstoken: token - }) - .then(data=> { - console.log(data); - if (data.success) { - return data - } - else { - throw 'markAsReadFailed' - } - }) -} - - -req.getUnreadMessageCount = function (token) { - let url = config.domain + config.apiPath + '/message/count' - return request.get(url, { - accesstoken: token - }) - .then(data=>data.data) -} - - -exports.storage = storage -exports.req = req diff --git a/app/services/Request.js b/app/services/Request.js deleted file mode 100644 index 3e036cb6..00000000 --- a/app/services/Request.js +++ /dev/null @@ -1,29 +0,0 @@ -var queryString = require('query-string') - -var request = {} - -request.get = function (url, params) { - if (params) { - url += '?' + queryString.stringify(params) - } - return fetch(url) - .then(res=>res.json()) -} - - -request.post = function (url, body) { - let fetchOptions = { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(body) - } - - return fetch(url, fetchOptions) - .then(res=>res.json()) -} - - -module.exports = request \ No newline at end of file diff --git a/app/services/Storage.js b/app/services/Storage.js deleted file mode 100644 index 6965075b..00000000 --- a/app/services/Storage.js +++ /dev/null @@ -1,39 +0,0 @@ -var React = require('react-native') - -var AsyncStorage = React.AsyncStorage - -var Storage = {} - - -Storage.setItem = function (key, value) { - if (value == null) return Promise.reject('value is null') - return AsyncStorage.setItem(key, JSON.stringify(value)) -} - -Storage.getItem = function (key) { - var result = AsyncStorage.getItem(key) - .then(function (value) { - return JSON.parse(value) - }) - - return result -} - -Storage.clear = AsyncStorage.clear - -Storage.removeItem = AsyncStorage.removeItem - -Storage.multiGet = function (keys) { - return AsyncStorage.multiGet(keys) - .then(results=> { - return results.map(item=> { - return [item[0], JSON.parse(item[1])] - }) - }) -} - -Storage.multiRemove = function (keys) { - return AsyncStorage.multiRemove(keys) -} - -module.exports = Storage diff --git a/app/services/TopicService.js b/app/services/TopicService.js deleted file mode 100644 index a7aa051c..00000000 --- a/app/services/TopicService.js +++ /dev/null @@ -1,150 +0,0 @@ -var request = require('./Request') -var Storage = require('./Storage') - -var config = require('../configs/config') -var tabs = ['good', 'ask', 'all', 'share', 'job'] - - -var storage = {} - -storage.get = function (tab) { - return Storage.getItem('tab_' + tab) - .then(topics=> { - if (topics) { - return topics - } - throw 'topicsInStorageIsEmpty' - }) -} - -storage.getAll = function () { - return Storage.multiGet(tabs.map(tab=> { - return 'tab_' + tab - })) -} - - -storage.remove = function () { - return Storage.multiRemove(tabs.map(tab=> { - return 'tab_' + tab - })) -} - - -var req = {} - - -req.getTopicsByTab = function (params) { - var url = config.domain + '/api/v1/topics' - - return request.get(url, params) - .then(data=>data.data) - .then(topics => { - if (params.page == 1 && topics) { - Storage.setItem('tab_' + params.tab, topics) - } - return topics - }) -} - - -req.getTopicById = function (id) { - let url = config.domain + '/api/v1/topic/' + id - return request.get(url) - .then(data=>data.data) - .then(topic=> { - if (topic && topic.id) { - return topic - } - throw 'GetTopicError' - }) -} - - -req.markTopicAsLike = function (id, token, isLiked) { - var apiUrl = config.domain + config.apiPath - - if (!isLiked) { - apiUrl += '/topic/collect' - } - else { - apiUrl += '/topic/de_collect' - } - - - return request.post(apiUrl, { - accesstoken: token, - topic_id: id - }) - .then(data => { - if (!data.success) { - throw 'error' - } - return data - }) -} - - -req.reply = function (topicId, content, token, replyId) { - let apiUrl = config.domain + config.apiPath - var body = { - accesstoken: token, - content: content - } - if (replyId) { - body.reply_id = replyId - } - let url = `${apiUrl}/topic/${topicId}/replies` - - return request.post(url, body) - .then(data=> { - if (data.success) { - return data.reply_id - } - else { - throw 'do reply failed' - } - }) -} - - -req.upComment = function (replyId, token) { - let apiUrl = config.domain + config.apiPath - var body = { - accesstoken: token - } - - let url = `${apiUrl}/reply/${replyId}/ups` - - return request.post(url, body) - .then(data=> { - if (data.success) { - return data.action == 'up' - } - else { - throw 'do reply failed' - } - }) -} - - -req.publish = function (title, tab, content, token) { - let url = `${config.domain + config.apiPath}/topics` - const body = { - title: title, - tab: tab, - content: content, - accesstoken: token - } - return request.post(url, body) - .then(data=> { - if (data.success) { - return data.topic_id - } - throw 'publish failed' - }) -} - - -exports.storage = storage -exports.req = req diff --git a/app/services/UserService.js b/app/services/UserService.js deleted file mode 100644 index 82863114..00000000 --- a/app/services/UserService.js +++ /dev/null @@ -1,93 +0,0 @@ -var Storage = require('./Storage') -var config = require('../configs/config') -var request = require('./Request') - -var storage = {} - - -storage.saveUser = function (user) { - return Storage.setItem('user', user) -} - - -storage.clearUser = function () { - return Storage.removeItem('user') -} - - -storage.saveUserInfo = function (userInfo) { - return Storage.setItem('userInfo', userInfo) -} - - -storage.getUser = function () { - return Storage.getItem('user') -} - -storage.getUserInfo = function () { - return Storage.getItem('userInfo') -} - -storage.getUserAndUserInfo = function () { - return Promise.all([ - storage.getUser(), - storage.getUserInfo() - ]) - .then(results=> { - return { - user: results[0], - userInfo: results[1] - } - }) -} - - -var req = {} - - -req.getLoginUserInfo = function (user) { - var apiUrl = config.domain + config.apiPath - - return request.get(apiUrl + '/user/' + user.loginname) - .then((data)=>data.data) - .then(userInfo=> { - if (userInfo) { - Storage.setItem('userInfo', userInfo) - return userInfo - } - return Storage.getItem('userInfo') - }) -} - - -req.getUserInfo = function (userName) { - var apiUrl = config.domain + config.apiPath - - return request.get(apiUrl + '/user/' + userName) - .then(data=> { - if (data.error_msg) { - throw 'UserNotExist' - } - return data - }) - .then((data)=>data.data) -} - - -req.checkToken = function (token) { - var apiUrl = config.domain + config.apiPath + '/accesstoken' - return request.post(apiUrl, { - accesstoken: token - }) - .then(data => { - if (data.success) { - data.token = token - Storage.setItem('user', data) - return data - } - throw 'wrong token' - }) -} - -exports.storage = storage -exports.req = req diff --git a/app/util/genColor.js b/app/util/genColor.js deleted file mode 100644 index dee5388f..00000000 --- a/app/util/genColor.js +++ /dev/null @@ -1,16 +0,0 @@ -var colors = ['#E74C3C', '#C0392B', '#1ABC9C', - '#16A085', '#2ECC71', '#27AE60', '#3498DB', - '#2980B9', '#9B59B6', '#8E44AD', '#34495E', - '#2C3E50', '#E67E22', - '#D35400', '#7F8C8D']; - - -function getRandomNum(Min, Max) { - var Range = Max - Min; - var Rand = Math.random(); - return (Min + Math.round(Rand * Range)); -} - -module.exports = function () { - return colors[getRandomNum(0, colors.length - 1)]; -}; diff --git a/app/util/window.js b/app/util/window.js deleted file mode 100644 index ba5f451e..00000000 --- a/app/util/window.js +++ /dev/null @@ -1,38 +0,0 @@ -var React = require('react-native') -var Dimensions = require('Dimensions') - - -var { - AlertIOS, - LinkingIOS - } = React - - -// The Dimensions API may change, so I move to a single module -exports.get = function () { - return Dimensions.get('window') -} - - -exports.alert = function (content) { - AlertIOS.alert(content) -} - - -exports.link = function (url) { - LinkingIOS.canOpenURL(url, (supported) => { - if (!supported) { - console.warn("Can't support the url") - } else { - LinkingIOS.openURL(url) - } - }) -} - - -exports.parseImgUrl= function (url) { - if (/^\/\/.*/.test(url)) { - url = 'http:' + url - } - return url -} diff --git a/codecept.conf.js b/codecept.conf.js new file mode 100644 index 00000000..7508639d --- /dev/null +++ b/codecept.conf.js @@ -0,0 +1,55 @@ +let CODECEPT_WORK_PATH = './e2e'; + +exports.config = { + output: CODECEPT_WORK_PATH + '/output', + helpers: process.profile === 'android' || process.profile === 'ios' ? { + Appium: { + smartWait: 35000, + app: process.profile === 'android' ? './android/app/build/outputs/apk/app-debug.apk' : './ios/build/Build/Products/Release-iphonesimulator/e2etest.app', + platform: process.profile === 'android' ? 'Android' : 'iOS', + desiredCapabilities: { + platformVersion: process.profile === 'ios' ? '10.3' : undefined, + deviceName: process.profile === 'ios' ? 'iPhone Simulator' : 'Android Emulator' + } + } + } : { + WebDriverIO: { + url: 'http://localhost:3000/', + browser: 'chrome' + } + }, + multiple: { + android: { + browsers: ['firefox'] + }, + basic: { + browsers: ['chrome', 'firefox'] + }, + smoke: { + grep: '@smoke', + browsers: [ + 'firefox', { + browser: 'chrome', + windowSize: 'maximize' + }, { + browser: 'chrome', + windowSize: '1200x840' + } + ] + } + }, + include: { + I: CODECEPT_WORK_PATH + '/custom_steps.js', + initStep: CODECEPT_WORK_PATH + '/steps/init.js', + AlertFragment: CODECEPT_WORK_PATH + '/fragments/Alert.js', + generalPage: CODECEPT_WORK_PATH + '/pages/general.js', + HomePage: CODECEPT_WORK_PATH + '/pages/Home.js' + }, + mocha: {}, + bootstrap: false, + teardown: null, + hooks: [], + tests: CODECEPT_WORK_PATH + '/tests/*.js', + timeout: 10000, + name: 'Noder' +}; diff --git a/e2e/custom_steps.js b/e2e/custom_steps.js new file mode 100644 index 00000000..279ec96e --- /dev/null +++ b/e2e/custom_steps.js @@ -0,0 +1,8 @@ +// in this file you can append custom step methods to 'I' object +'use strict'; + +module.exports = function() { + return actor({ + // Define custom steps here, use 'this' to access default methods of I. + }); +}; diff --git a/e2e/fragments/Alert.js b/e2e/fragments/Alert.js new file mode 100644 index 00000000..8fa3237c --- /dev/null +++ b/e2e/fragments/Alert.js @@ -0,0 +1,20 @@ +/// +'use strict'; + +let I; + +module.exports = { + _init() { + I = require('../custom_steps.js')(); + }, + + button1: { + android: { + id: 'android:id/button1' + } + }, + + clickButton1() { + this.button1[process.profile] && I.click(this.button1[process.profile]); + } +}; diff --git a/e2e/pages/Home.js b/e2e/pages/Home.js new file mode 100644 index 00000000..5852272e --- /dev/null +++ b/e2e/pages/Home.js @@ -0,0 +1,14 @@ +/// +'use strict'; + +let I; + +module.exports = { + _init() { + I = require('../custom_steps.js')(); + }, + + ensureOpen() { + I.seeElement('~主页'); + } +}; diff --git a/e2e/pages/general.js b/e2e/pages/general.js new file mode 100644 index 00000000..a1064f7a --- /dev/null +++ b/e2e/pages/general.js @@ -0,0 +1,46 @@ +/// + +// Page object for General page (shared element/operations across all pages) +'use strict'; + +let I; + +module.exports = { + _init() { + I = actor(); + }, + + swipeLeft() { + I.touchPerform([{ + action: 'press', + options: { + x: 400, + y: 200 + } + }, { + action: 'moveTo', + options: { + x: -300 + } + }, { + action: 'release' + }, { + action: 'wait', + options: { + ms: 100 + } + }]); + }, + + click(x, y) { + I.touchPerform([{ + action: 'press', + options: { + x, + y, + } + }, { + action: 'release' + }]); + } +}; diff --git a/e2e/steps.d.ts b/e2e/steps.d.ts new file mode 100644 index 00000000..87e0025f --- /dev/null +++ b/e2e/steps.d.ts @@ -0,0 +1,108 @@ + +type ICodeceptCallback = (i: CodeceptJS.I) => void; + +declare const actor: () => CodeceptJS.I; +declare const Feature: (string: string) => void; +declare const Scenario: (string: string, callback: ICodeceptCallback) => void; +declare const Before: (callback: ICodeceptCallback) => void; +declare const After: (callback: ICodeceptCallback) => void; +declare const within: (selector: string, callback: Function) => void; + +declare namespace CodeceptJS { + export interface I { + defineTimeout: (timeouts) => any; + amOnPage: (amOnPage) => any; + click: (click) => any; + doubleClick: (doubleClick) => any; + rightClick: (rightClick) => any; + fillField: (fillField) => any; + appendField: (appendField) => any; + selectOption: (selectOption) => any; + attachFile: (attachFile) => any; + checkOption: (checkOption) => any; + grabTextFrom: (grabTextFrom) => any; + grabHTMLFrom: (locator) => any; + grabValueFrom: (grabValueFrom) => any; + grabCssPropertyFrom: (grabCssPropertyFrom) => any; + grabAttributeFrom: (grabAttributeFrom) => any; + seeInTitle: (seeInTitle) => any; + seeTitleEquals: (seeTitleEquals) => any; + dontSeeInTitle: (dontSeeInTitle) => any; + grabTitle: (grabTitle) => any; + see: (text, context=null) => any; + seeTextEquals: (text, context=null) => any; + dontSee: (text, context=null) => any; + seeInField: (field, value) => any; + dontSeeInField: (field, value) => any; + seeCheckboxIsChecked: (field) => any; + dontSeeCheckboxIsChecked: (field) => any; + seeElement: (seeElement) => any; + dontSeeElement: (dontSeeElement) => any; + seeElementInDOM: (locator) => any; + dontSeeElementInDOM: (locator) => any; + seeInSource: (seeInSource) => any; + grabSource: () => any; + grabBrowserLogs: (grabBrowserLogs) => any; + dontSeeInSource: (dontSeeInSource) => any; + seeNumberOfElements: (selector, num) => any; + seeNumberOfVisibleElements: (locator, num) => any; + seeCssPropertiesOnElements: (seeCssPropertiesOnElements) => any; + seeAttributesOnElements: (seeAttributesOnElements) => any; + grabNumberOfVisibleElements: (grabNumberOfVisibleElements) => any; + seeInCurrentUrl: (url) => any; + dontSeeInCurrentUrl: (url) => any; + seeCurrentUrlEquals: (seeCurrentUrlEquals) => any; + dontSeeCurrentUrlEquals: (dontSeeCurrentUrlEquals) => any; + executeScript: (executeScript) => any; + executeAsyncScript: (executeAsyncScript) => any; + scrollTo: (locator, offsetX=0, offsetY=0) => any; + moveCursorTo: (moveCursorTo) => any; + saveScreenshot: (saveScreenshot) => any; + setCookie: (cookie) => any; + clearCookie: (cookie) => any; + clearField: (clearField) => any; + seeCookie: (name) => any; + dontSeeCookie: (name) => any; + grabCookie: (name) => any; + acceptPopup: () => any; + cancelPopup: () => any; + seeInPopup: (text) => any; + pressKey: (key) => any; + resizeWindow: (resizeWindow) => any; + dragAndDrop: (srcElement, destElement) => any; + closeOtherTabs: (closeOtherTabs) => any; + wait: (sec) => any; + waitForEnabled: (waitForEnabled) => any; + waitForElement: (locator, sec=null) => any; + waitUntilExists: (locator, sec=null) => any; + waitInUrl: (waitInUrl) => any; + waitUrlEquals: (waitUrlEquals) => any; + waitForText: (waitForText) => any; + waitForValue: (waitForValue) => any; + waitForVisible: (waitForVisible) => any; + waitNumberOfVisibleElements: (waitNumberOfVisibleElements) => any; + waitForInvisible: (waitForInvisible) => any; + waitToHide: (locator, sec=null) => any; + waitForStalenessOf: (locator, sec=null) => any; + waitUntil: (fn, sec=null, timeoutMsg=null) => any; + switchTo: (switchTo) => any; + switchToNextTab: (num=1, sec=null) => any; + switchToPreviousTab: (num=1, sec=null) => any; + closeCurrentTab: () => any; + openNewTab: () => any; + refreshPage: () => any; + scrollPageToTop: () => any; + scrollPageToBottom: () => any; + debug: (msg) => any; + debugSection: (section, msg) => any; + runOnIOS: (caps, fn) => any; + runOnAndroid: (caps, fn) => any; + runInWeb: (fn) => any; + say: (msg) => any; + + } +} + +declare module "codeceptjs" { + export = CodeceptJS; +} diff --git a/e2e/steps/init.js b/e2e/steps/init.js new file mode 100644 index 00000000..71be7ffc --- /dev/null +++ b/e2e/steps/init.js @@ -0,0 +1,28 @@ +/// +'use strict'; + +let I, AlertFragment; + +module.exports = { + _init() { + I = require('../custom_steps.js')(); + AlertFragment = require('../fragments/Alert'); + AlertFragment._init(); + }, + + workaroundOfStartNative() { + // When test on Android, I found that src/Home.js need Alert and click here, + // then following testing contain ~ locator comes from accessibiltyLabel in + // any react-native component can be capture successly. + // If you fix this workaround, please tell me + AlertFragment.clickButton1(); + }, + + toHome() { + I.runInWeb(() => { + I.amOnPage('/'); + }); + + this.workaroundOfStartNative(); + } +}; diff --git a/e2e/tests/clickSome.js b/e2e/tests/clickSome.js new file mode 100644 index 00000000..97b9c152 --- /dev/null +++ b/e2e/tests/clickSome.js @@ -0,0 +1,28 @@ +/// +Feature('Click works as expected'); + +Before((I, initStep) => { + initStep.toHome(); +}); + +After((I) => { + I.wait(2); +}); + +Scenario('Perform click some tab', (I, HomePage) => { + HomePage.ensureOpen(); + I.wait(2); + I.click('~问答'); + I.wait(2); + I.click('~主页'); +}); + +Scenario('Perform click some topic', (I, HomePage, generalPage) => { + HomePage.ensureOpen(); + I.runOnAndroid(() => { + I.wait(2); + generalPage.swipeLeft(); + I.wait(2); + generalPage.click(345, 345); + }); +}); diff --git a/gulpFile.coffee b/gulpFile.coffee deleted file mode 100755 index fe2c67aa..00000000 --- a/gulpFile.coffee +++ /dev/null @@ -1,37 +0,0 @@ -gulp = require 'gulp' -replace = require 'gulp-replace' -gutil = require 'gulp-util' -runSequence = require 'run-sequence' -devIp = require 'dev-ip' - - -child_process = require 'child_process' - -appDelegateSrc = './iOS/AppDelegate.m' -port = 8081 - - -gulp.task 'replace', -> - ip = devIp()[0] - reg = /// - jsCodeLocation\s=\s - \[NSURL\sURLWithString: - @"http:.*\n - ///g - # ip = 'localhost' - gulp.src appDelegateSrc - .pipe replace reg, "jsCodeLocation = [NSURL URLWithString:@\"http://#{ip}:#{port}/index.ios.bundle\"];\n" - .pipe gulp.dest './iOS' - - -gulp.task 'package', (cb)-> - cmd = "./node_modules/react-native/packager/packager.sh" - start = child_process.spawn cmd, ['--port', port] - start.stdout.on 'data', (data)-> - gutil.log data.toString() - start.stderr.on 'data', (data)-> - gutil.log data.toString() - - -gulp.task 'start', -> - runSequence 'replace', 'package' diff --git a/iOS/AppDelegate.m b/iOS/AppDelegate.m deleted file mode 100644 index cd18150d..00000000 --- a/iOS/AppDelegate.m +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "AppDelegate.h" - -#import "RCTRootView.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - NSURL *jsCodeLocation; - - /** - * Loading JavaScript code - uncomment the one you want. - * - * OPTION 1 - * Load from development server. Start the server from the repository root: - * - * $ npm start - * - * To run on device, change `localhost` to the IP address of your computer - * (you can get this by typing `ifconfig` into the terminal and selecting the - * `inet` value under `en0:`) and make sure your computer and iOS device are - * on the same Wi-Fi network. - */ - - jsCodeLocation = [NSURL URLWithString:@"http://169.254.79.139:8081/index.ios.bundle"]; - - /** - * OPTION 2 - * Load from pre-bundled file on disk. To re-generate the static bundle - * from the root of your project directory, run - * - * $ react-native bundle --minify - * - * see http://facebook.github.io/react-native/docs/runningondevice.html - */ - -// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; - - RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation - moduleName:@"noder" - launchOptions:launchOptions]; - - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [[UIViewController alloc] init]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; - return YES; -} - -@end diff --git a/iOS/Images.xcassets/AppIcon.appiconset/Contents.json b/iOS/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 34081ff0..00000000 --- a/iOS/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "noder-Icon.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "noder-Icon-1.png", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/iOS/Images.xcassets/AppIcon.appiconset/noder-Icon-1.png b/iOS/Images.xcassets/AppIcon.appiconset/noder-Icon-1.png deleted file mode 100644 index fb12b90d..00000000 Binary files a/iOS/Images.xcassets/AppIcon.appiconset/noder-Icon-1.png and /dev/null differ diff --git a/iOS/Images.xcassets/AppIcon.appiconset/noder-Icon.png b/iOS/Images.xcassets/AppIcon.appiconset/noder-Icon.png deleted file mode 100644 index fb12b90d..00000000 Binary files a/iOS/Images.xcassets/AppIcon.appiconset/noder-Icon.png and /dev/null differ diff --git a/iOS/Images.xcassets/bg2.imageset/Contents.json b/iOS/Images.xcassets/bg2.imageset/Contents.json deleted file mode 100644 index 5f2082c9..00000000 --- a/iOS/Images.xcassets/bg2.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "bg2@1x.jpg" - }, - { - "idiom" : "universal", - "scale" : "2x", - "filename" : "bg2@2x.jpg" - }, - { - "idiom" : "universal", - "scale" : "3x", - "filename" : "bg2@3x.jpg" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/iOS/Images.xcassets/bg2.imageset/bg2@1x.jpg b/iOS/Images.xcassets/bg2.imageset/bg2@1x.jpg deleted file mode 100644 index 469bb881..00000000 Binary files a/iOS/Images.xcassets/bg2.imageset/bg2@1x.jpg and /dev/null differ diff --git a/iOS/Images.xcassets/bg2.imageset/bg2@2x.jpg b/iOS/Images.xcassets/bg2.imageset/bg2@2x.jpg deleted file mode 100644 index 469bb881..00000000 Binary files a/iOS/Images.xcassets/bg2.imageset/bg2@2x.jpg and /dev/null differ diff --git a/iOS/Images.xcassets/bg2.imageset/bg2@3x.jpg b/iOS/Images.xcassets/bg2.imageset/bg2@3x.jpg deleted file mode 100644 index 469bb881..00000000 Binary files a/iOS/Images.xcassets/bg2.imageset/bg2@3x.jpg and /dev/null differ diff --git a/iOS/Images.xcassets/blog.imageset/blog@2x.png b/iOS/Images.xcassets/blog.imageset/blog@2x.png deleted file mode 100644 index 4e7701b4..00000000 Binary files a/iOS/Images.xcassets/blog.imageset/blog@2x.png and /dev/null differ diff --git a/iOS/Images.xcassets/blog.imageset/blog@3x.png b/iOS/Images.xcassets/blog.imageset/blog@3x.png deleted file mode 100644 index 4e7701b4..00000000 Binary files a/iOS/Images.xcassets/blog.imageset/blog@3x.png and /dev/null differ diff --git a/iOS/Images.xcassets/logo.imageset/Contents.json b/iOS/Images.xcassets/logo.imageset/Contents.json deleted file mode 100644 index a1c5f3e2..00000000 --- a/iOS/Images.xcassets/logo.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x", - "filename" : "logo@1x.png" - }, - { - "idiom" : "universal", - "scale" : "2x", - "filename" : "logo@2x.png" - }, - { - "idiom" : "universal", - "scale" : "3x", - "filename" : "logo@2x.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/iOS/zh-Hans.lproj/LaunchScreen.strings b/iOS/zh-Hans.lproj/LaunchScreen.strings deleted file mode 100644 index 52ebd053..00000000 --- a/iOS/zh-Hans.lproj/LaunchScreen.strings +++ /dev/null @@ -1,6 +0,0 @@ - -/* Class = "UILabel"; text = "Powered by React Native"; ObjectID = "8ie-xW-0ye"; */ -"8ie-xW-0ye.text" = "Powered by React Native"; - -/* Class = "UILabel"; text = "noder3"; ObjectID = "kId-c2-rCX"; */ -"kId-c2-rCX.text" = "noder3"; diff --git a/index.android.js b/index.android.js new file mode 100644 index 00000000..ab3b0b38 --- /dev/null +++ b/index.android.js @@ -0,0 +1,4 @@ +import { AppRegistry } from 'react-native' +import Noder from './src' + +AppRegistry.registerComponent('noder', () => Noder) diff --git a/index.ios.js b/index.ios.js index f5aca7fe..ab3b0b38 100644 --- a/index.ios.js +++ b/index.ios.js @@ -1,35 +1,4 @@ -var React = require('react-native') -var App = require('./app/containers/App') - -//var user = require('./app/mocks/user') -//var userInfo = require('./app/mocks/userInfo') -//var UserService = require('./app/services/UserService') -//Object.assign(user, userInfo) - - -// on run -require('./app/configs/onRun') - - - -var { - Component, - AppRegistry - } = React - - -class Noder extends Component { - - componentDidMount() { - //UserService.storage.saveUser(user) - //UserService.storage.clearUser() - } - - render() { - return ( - - ) - } -} +import { AppRegistry } from 'react-native' +import Noder from './src' AppRegistry.registerComponent('noder', () => Noder) diff --git a/index.web.js b/index.web.js new file mode 100644 index 00000000..face6828 --- /dev/null +++ b/index.web.js @@ -0,0 +1,14 @@ +import 'babel-polyfill' +import 'fetch-detector' +import 'fetch-ie8' +import {AppRegistry} from 'react-native' +import Noder from './src' + +AppRegistry.registerComponent('noder', () => Noder) + +var app = document.createElement('div') +document.body.appendChild(app) + +AppRegistry.runApplication('noder', { + rootTag: app +}) diff --git a/iOS/Info.plist b/ios/noder-tvOS/Info.plist similarity index 81% rename from iOS/Info.plist rename to ios/noder-tvOS/Info.plist index 4b37a5a3..2fb6a11c 100644 --- a/iOS/Info.plist +++ b/ios/noder-tvOS/Info.plist @@ -22,8 +22,6 @@ 1 LSRequiresIPhoneOS - NSLocationWhenInUseUsageDescription - UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities @@ -38,5 +36,19 @@ UIViewControllerBasedStatusBarAppearance + NSLocationWhenInUseUsageDescription + + NSAppTransportSecurity + + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + + + diff --git a/ios/noder-tvOSTests/Info.plist b/ios/noder-tvOSTests/Info.plist new file mode 100644 index 00000000..886825cc --- /dev/null +++ b/ios/noder-tvOSTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/ios/noder.xcodeproj/project.pbxproj b/ios/noder.xcodeproj/project.pbxproj new file mode 100644 index 00000000..b8f7931d --- /dev/null +++ b/ios/noder.xcodeproj/project.pbxproj @@ -0,0 +1,1510 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; + 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; + 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; + 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; + 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; + 00E356F31AD99517003FC87E /* noderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* noderTests.m */; }; + 0539EE701B94445A8DDF1F63 /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = AC8A1E4B2B2349F59F02BD96 /* FontAwesome.ttf */; }; + 09BB28342A2E4D7A9B8DAC2A /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2D54DF81EB27461291C38CFB /* Ionicons.ttf */; }; + 0DFA4E087D2C4407BE495FF5 /* Foundation.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F2C11DAE49124AC3B69A8AA6 /* Foundation.ttf */; }; + 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; + 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; + 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; + 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; + 2CDDEA4C2BC9435CA628C2D1 /* EvilIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C886CD7B69BF47E1A5022F45 /* EvilIcons.ttf */; }; + 596ABFFDF7214900BDB25237 /* libRNBlur.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 06C625281A094439A622DDC2 /* libRNBlur.a */; }; + 5C5FAA68CB9E4B249911CF46 /* libRNVectorIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 939C2E9550714D478EE17736 /* libRNVectorIcons.a */; }; + 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; + 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */; }; + 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */; }; + 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */; }; + 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */; }; + 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */; }; + 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */; }; + 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */; }; + 2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; }; + 2DCD954D1E0B4F2C00145EB5 /* noderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* noderTests.m */; }; + 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; + 8F0A23C3FA6848FFAC679696 /* Entypo.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2B3574A3CE4D4F569715439E /* Entypo.ttf */; }; + 95F7C17B9DE042F8ACF316EF /* MaterialIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 415C9DD3E4DA4D4F8EA6930A /* MaterialIcons.ttf */; }; + 9E459D6D1CC751AA00F6C61D /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E459D6C1CC751AA00F6C61D /* libz.tbd */; }; + 9E93228A6688474BA6948F29 /* libCodePush.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 51408331D0894403A3207186 /* libCodePush.a */; }; + ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; }; + BE7FCBED6AF945FA87EB4FA9 /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 53F483A02108469FB6D758C8 /* Octicons.ttf */; }; + D3B2D6F8393B4EA9AB57CAFF /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1DDEF6DB42F647D28EBF87BC /* Zocial.ttf */; }; + F5DDCEAF1E6B40C98D7EF640 /* libRCTCamera.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E381C2EF86A4AEFB656769E /* libRCTCamera.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTActionSheet; + }; + 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTGeolocation; + }; + 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5115D1A9E6B3D00147676; + remoteInfo = RCTImage; + }; + 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B511DB1A9E6C8500147676; + remoteInfo = RCTNetwork; + }; + 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 832C81801AAF6DEF007FA2F7; + remoteInfo = RCTVibration; + }; + 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = noder; + }; + 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTSettings; + }; + 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3C86DF461ADF2C930047B81A; + remoteInfo = RCTWebSocket; + }; + 146834031AC3E56700842450 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; + remoteInfo = React; + }; + 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2D02E47A1E0B4A5D006451C7; + remoteInfo = "noder-tvOS"; + }; + 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; + remoteInfo = "RCTImage-tvOS"; + }; + 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28471D9B043800D4039D; + remoteInfo = "RCTLinking-tvOS"; + }; + 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28541D9B044C00D4039D; + remoteInfo = "RCTNetwork-tvOS"; + }; + 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28611D9B046600D4039D; + remoteInfo = "RCTSettings-tvOS"; + }; + 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A287B1D9B048500D4039D; + remoteInfo = "RCTText-tvOS"; + }; + 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28881D9B049200D4039D; + remoteInfo = "RCTWebSocket-tvOS"; + }; + 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28131D9B038B00D4039D; + remoteInfo = "React-tvOS"; + }; + 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C059A1DE3340900C268FA; + remoteInfo = yoga; + }; + 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C06751DE3340C00C268FA; + remoteInfo = "yoga-tvOS"; + }; + 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; + remoteInfo = cxxreact; + }; + 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; + remoteInfo = "cxxreact-tvOS"; + }; + 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; + remoteInfo = jschelpers; + }; + 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; + remoteInfo = "jschelpers-tvOS"; + }; + 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTAnimation; + }; + 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28201D9B03D100D4039D; + remoteInfo = "RCTAnimation-tvOS"; + }; + 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTLinking; + }; + 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5119B1A9E6C1200147676; + remoteInfo = RCTText; + }; + 9E0421361CB5131100D2C9C1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9365FA91633D4242A938BBBD /* RNBlur.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = A68BD7BC1BC31318005F02DF; + remoteInfo = RNBlur; + }; + 9E04213B1CB5131100D2C9C1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6E7CF76670244BF8BD9F6FAD /* RCTCamera.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 4107012F1ACB723B00C6AA39; + remoteInfo = RCTCamera; + }; + 9E0421401CB5131100D2C9C1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 71C2834D6880428CA06F4852 /* RNVectorIcons.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 5DBEB1501B18CEA900B34395; + remoteInfo = RNVectorIcons; + }; + 9E459D5D1CC7519600F6C61D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E5438F2DD1224DC69F235A90 /* CodePush.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = CodePush; + }; + ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 358F4ED71D1E81A9004DF814; + remoteInfo = RCTBlob; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; + 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; }; + 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; + 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; + 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; + 00E356EE1AD99517003FC87E /* noderTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = noderTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* noderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = noderTests.m; sourceTree = ""; }; + 06C625281A094439A622DDC2 /* libRNBlur.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNBlur.a; sourceTree = ""; }; + 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; + 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* noder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = noder.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = noder/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = noder/AppDelegate.m; sourceTree = ""; }; + 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = noder/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = noder/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = noder/main.m; sourceTree = ""; }; + 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; + 1DDEF6DB42F647D28EBF87BC /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = ""; }; + 2B3574A3CE4D4F569715439E /* Entypo.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = ""; }; + 2D02E47B1E0B4A5D006451C7 /* noder-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "noder-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2D02E4901E0B4A5D006451C7 /* noder-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "noder-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2D54DF81EB27461291C38CFB /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = ""; }; + 415C9DD3E4DA4D4F8EA6930A /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = ""; }; + 4E381C2EF86A4AEFB656769E /* libRCTCamera.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTCamera.a; sourceTree = ""; }; + 51408331D0894403A3207186 /* libCodePush.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libCodePush.a; sourceTree = ""; }; + 53F483A02108469FB6D758C8 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = ""; }; + 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; + 6E7CF76670244BF8BD9F6FAD /* RCTCamera.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTCamera.xcodeproj; path = "../node_modules/react-native-camera/ios/RCTCamera.xcodeproj"; sourceTree = ""; }; + 71C2834D6880428CA06F4852 /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = ""; }; + 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; + 9365FA91633D4242A938BBBD /* RNBlur.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNBlur.xcodeproj; path = "../node_modules/react-native-blur/ios/RNBlur.xcodeproj"; sourceTree = ""; }; + 939C2E9550714D478EE17736 /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = ""; }; + 9E459D6C1CC751AA00F6C61D /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + AC8A1E4B2B2349F59F02BD96 /* FontAwesome.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf"; sourceTree = ""; }; + ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = ""; }; + C886CD7B69BF47E1A5022F45 /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = ""; }; + E5438F2DD1224DC69F235A90 /* CodePush.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = CodePush.xcodeproj; path = "../node_modules/react-native-code-push/ios/CodePush.xcodeproj"; sourceTree = ""; }; + F2C11DAE49124AC3B69A8AA6 /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00E356EB1AD99517003FC87E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9E459D6D1CC751AA00F6C61D /* libz.tbd in Frameworks */, + ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */, + 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */, + 146834051AC3E58100842450 /* libReact.a in Frameworks */, + 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */, + 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, + 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, + 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, + 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, + 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */, + 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, + 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, + 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, + 596ABFFDF7214900BDB25237 /* libRNBlur.a in Frameworks */, + F5DDCEAF1E6B40C98D7EF640 /* libRCTCamera.a in Frameworks */, + 5C5FAA68CB9E4B249911CF46 /* libRNVectorIcons.a in Frameworks */, + 9E93228A6688474BA6948F29 /* libCodePush.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D02E4781E0B4A5D006451C7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2D02E4C91E0B4AEC006451C7 /* libReact.a in Frameworks */, + 2D02E4C21E0B4AEC006451C7 /* libRCTAnimation-tvOS.a in Frameworks */, + 2D02E4C31E0B4AEC006451C7 /* libRCTImage-tvOS.a in Frameworks */, + 2D02E4C41E0B4AEC006451C7 /* libRCTLinking-tvOS.a in Frameworks */, + 2D02E4C51E0B4AEC006451C7 /* libRCTNetwork-tvOS.a in Frameworks */, + 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */, + 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */, + 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D02E48D1E0B4A5D006451C7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 00C302A81ABCB8CE00DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302B61ABCB90400DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302BC1ABCB91800DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */, + 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302D41ABCB9D200DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, + 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302E01ABCB9EE00DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, + ); + name = Products; + sourceTree = ""; + }; + 00E356EF1AD99517003FC87E /* noderTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* noderTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = noderTests; + sourceTree = ""; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 139105B71AF99BAD00B5F7CC /* Products */ = { + isa = PBXGroup; + children = ( + 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, + 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 139FDEE71B06529A00C62182 /* Products */ = { + isa = PBXGroup; + children = ( + 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, + 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* noder */ = { + isa = PBXGroup; + children = ( + 008F07F21AC5B25A0029DE68 /* main.jsbundle */, + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = noder; + sourceTree = ""; + }; + 146834001AC3E56700842450 /* Products */ = { + isa = PBXGroup; + children = ( + 146834041AC3E56700842450 /* libReact.a */, + 3DAD3EA31DF850E9000B6D8A /* libReact.a */, + 3DAD3EA51DF850E9000B6D8A /* libyoga.a */, + 3DAD3EA71DF850E9000B6D8A /* libyoga.a */, + 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */, + 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */, + 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */, + 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */, + 3DAD3EA31DF850E9000B6D8A /* libReact-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 5E91572E1DD0AC6500FF2AA8 /* Products */ = { + isa = PBXGroup; + children = ( + 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */, + 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 78C398B11ACF4ADC00677621 /* Products */ = { + isa = PBXGroup; + children = ( + 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, + 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */, + 146833FF1AC3E56700842450 /* React.xcodeproj */, + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, + ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */, + 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, + 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */, + 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */, + 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */, + 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */, + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, + 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, + 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, + 9365FA91633D4242A938BBBD /* RNBlur.xcodeproj */, + 6E7CF76670244BF8BD9F6FAD /* RCTCamera.xcodeproj */, + 71C2834D6880428CA06F4852 /* RNVectorIcons.xcodeproj */, + E5438F2DD1224DC69F235A90 /* CodePush.xcodeproj */, + ); + name = Libraries; + sourceTree = ""; + }; + 832341B11AAA6A8300B99B32 /* Products */ = { + isa = PBXGroup; + children = ( + 832341B51AAA6A8300B99B32 /* libRCTText.a */, + 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 9E459D6C1CC751AA00F6C61D /* libz.tbd */, + 13B07FAE1A68108700A75B9A /* noder */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* noderTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + 941F82EA40564FBA80400623 /* Resources */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* noder.app */, + 00E356EE1AD99517003FC87E /* noderTests.xctest */, + 2D02E47B1E0B4A5D006451C7 /* noder-tvOS.app */, + 2D02E4901E0B4A5D006451C7 /* noder-tvOSTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 941F82EA40564FBA80400623 /* Resources */ = { + isa = PBXGroup; + children = ( + 2B3574A3CE4D4F569715439E /* Entypo.ttf */, + C886CD7B69BF47E1A5022F45 /* EvilIcons.ttf */, + AC8A1E4B2B2349F59F02BD96 /* FontAwesome.ttf */, + F2C11DAE49124AC3B69A8AA6 /* Foundation.ttf */, + 2D54DF81EB27461291C38CFB /* Ionicons.ttf */, + 415C9DD3E4DA4D4F8EA6930A /* MaterialIcons.ttf */, + 53F483A02108469FB6D758C8 /* Octicons.ttf */, + 1DDEF6DB42F647D28EBF87BC /* Zocial.ttf */, + ); + name = Resources; + sourceTree = ""; + }; + 9E0421291CB5131100D2C9C1 /* Products */ = { + isa = PBXGroup; + children = ( + 9E0421371CB5131100D2C9C1 /* libRNBlur.a */, + ); + name = Products; + sourceTree = ""; + }; + 9E0421381CB5131100D2C9C1 /* Products */ = { + isa = PBXGroup; + children = ( + 9E04213C1CB5131100D2C9C1 /* libRCTCamera.a */, + ); + name = Products; + sourceTree = ""; + }; + 9E04213D1CB5131100D2C9C1 /* Products */ = { + isa = PBXGroup; + children = ( + 9E0421411CB5131100D2C9C1 /* libRNVectorIcons.a */, + ); + name = Products; + sourceTree = ""; + }; + 9E459D5A1CC7519500F6C61D /* Products */ = { + isa = PBXGroup; + children = ( + 9E459D5E1CC7519600F6C61D /* libCodePush.a */, + ); + name = Products; + sourceTree = ""; + }; + ADBDB9201DFEBF0600ED6528 /* Products */ = { + isa = PBXGroup; + children = ( + ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00E356ED1AD99517003FC87E /* noderTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "noderTests" */; + buildPhases = ( + 00E356EA1AD99517003FC87E /* Sources */, + 00E356EB1AD99517003FC87E /* Frameworks */, + 00E356EC1AD99517003FC87E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 00E356F51AD99517003FC87E /* PBXTargetDependency */, + ); + name = noderTests; + productName = noderTests; + productReference = 00E356EE1AD99517003FC87E /* noderTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 13B07F861A680F5B00A75B9A /* noder */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "noder" */; + buildPhases = ( + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = noder; + productName = "Hello World"; + productReference = 13B07F961A680F5B00A75B9A /* noder.app */; + productType = "com.apple.product-type.application"; + }; + 2D02E47A1E0B4A5D006451C7 /* noder-tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "noder-tvOS" */; + buildPhases = ( + 2D02E4771E0B4A5D006451C7 /* Sources */, + 2D02E4781E0B4A5D006451C7 /* Frameworks */, + 2D02E4791E0B4A5D006451C7 /* Resources */, + 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "noder-tvOS"; + productName = "noder-tvOS"; + productReference = 2D02E47B1E0B4A5D006451C7 /* noder-tvOS.app */; + productType = "com.apple.product-type.application"; + }; + 2D02E48F1E0B4A5D006451C7 /* noder-tvOSTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "noder-tvOSTests" */; + buildPhases = ( + 2D02E48C1E0B4A5D006451C7 /* Sources */, + 2D02E48D1E0B4A5D006451C7 /* Frameworks */, + 2D02E48E1E0B4A5D006451C7 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */, + ); + name = "noder-tvOSTests"; + productName = "noder-tvOSTests"; + productReference = 2D02E4901E0B4A5D006451C7 /* noder-tvOSTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 00E356ED1AD99517003FC87E = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + 13B07F861A680F5B00A75B9A = { + DevelopmentTeam = HT6H5U9WMQ; + }; + 2D02E47A1E0B4A5D006451C7 = { + CreatedOnToolsVersion = 8.2.1; + ProvisioningStyle = Automatic; + }; + 2D02E48F1E0B4A5D006451C7 = { + CreatedOnToolsVersion = 8.2.1; + ProvisioningStyle = Automatic; + TestTargetID = 2D02E47A1E0B4A5D006451C7; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "noder" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 9E459D5A1CC7519500F6C61D /* Products */; + ProjectRef = E5438F2DD1224DC69F235A90 /* CodePush.xcodeproj */; + }, + { + ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; + ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; + }, + { + ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */; + ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; + }, + { + ProductGroup = ADBDB9201DFEBF0600ED6528 /* Products */; + ProjectRef = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */; + }, + { + ProductGroup = 9E0421381CB5131100D2C9C1 /* Products */; + ProjectRef = 6E7CF76670244BF8BD9F6FAD /* RCTCamera.xcodeproj */; + }, + { + ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; + ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; + }, + { + ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */; + ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; + }, + { + ProductGroup = 78C398B11ACF4ADC00677621 /* Products */; + ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; + }, + { + ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */; + ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; + }, + { + ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */; + ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; + }, + { + ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; + ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + }, + { + ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */; + ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; + }, + { + ProductGroup = 139FDEE71B06529A00C62182 /* Products */; + ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; + }, + { + ProductGroup = 146834001AC3E56700842450 /* Products */; + ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; + }, + { + ProductGroup = 9E0421291CB5131100D2C9C1 /* Products */; + ProjectRef = 9365FA91633D4242A938BBBD /* RNBlur.xcodeproj */; + }, + { + ProductGroup = 9E04213D1CB5131100D2C9C1 /* Products */; + ProjectRef = 71C2834D6880428CA06F4852 /* RNVectorIcons.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* noder */, + 00E356ED1AD99517003FC87E /* noderTests */, + 2D02E47A1E0B4A5D006451C7 /* noder-tvOS */, + 2D02E48F1E0B4A5D006451C7 /* noder-tvOSTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTActionSheet.a; + remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTGeolocation.a; + remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTImage.a; + remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTNetwork.a; + remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTVibration.a; + remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTSettings.a; + remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTWebSocket.a; + remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 146834041AC3E56700842450 /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3E841DF850E9000B6D8A /* libRCTImage-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTImage-tvOS.a"; + remoteRef = 3DAD3E831DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3E881DF850E9000B6D8A /* libRCTLinking-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTLinking-tvOS.a"; + remoteRef = 3DAD3E871DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3E8C1DF850E9000B6D8A /* libRCTNetwork-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTNetwork-tvOS.a"; + remoteRef = 3DAD3E8B1DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3E901DF850E9000B6D8A /* libRCTSettings-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTSettings-tvOS.a"; + remoteRef = 3DAD3E8F1DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3E941DF850E9000B6D8A /* libRCTText-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTText-tvOS.a"; + remoteRef = 3DAD3E931DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3E991DF850E9000B6D8A /* libRCTWebSocket-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTWebSocket-tvOS.a"; + remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EA31DF850E9000B6D8A /* libReact-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libReact-tvOS.a"; + remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTAnimation.a; + remoteRef = 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 5E9157351DD0AC6500FF2AA8 /* libRCTAnimation-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTAnimation-tvOS.a"; + remoteRef = 5E9157341DD0AC6500FF2AA8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTLinking.a; + remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTText.a; + remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 9E0421371CB5131100D2C9C1 /* libRNBlur.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRNBlur.a; + remoteRef = 9E0421361CB5131100D2C9C1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 9E04213C1CB5131100D2C9C1 /* libRCTCamera.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTCamera.a; + remoteRef = 9E04213B1CB5131100D2C9C1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 9E0421411CB5131100D2C9C1 /* libRNVectorIcons.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRNVectorIcons.a; + remoteRef = 9E0421401CB5131100D2C9C1 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 9E459D5E1CC7519600F6C61D /* libCodePush.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libCodePush.a; + remoteRef = 9E459D5D1CC7519600F6C61D /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTBlob.a; + remoteRef = ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 00E356EC1AD99517003FC87E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + 8F0A23C3FA6848FFAC679696 /* Entypo.ttf in Resources */, + 2CDDEA4C2BC9435CA628C2D1 /* EvilIcons.ttf in Resources */, + 0539EE701B94445A8DDF1F63 /* FontAwesome.ttf in Resources */, + 0DFA4E087D2C4407BE495FF5 /* Foundation.ttf in Resources */, + 09BB28342A2E4D7A9B8DAC2A /* Ionicons.ttf in Resources */, + 95F7C17B9DE042F8ACF316EF /* MaterialIcons.ttf in Resources */, + BE7FCBED6AF945FA87EB4FA9 /* Octicons.ttf in Resources */, + D3B2D6F8393B4EA9AB57CAFF /* Zocial.ttf in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D02E4791E0B4A5D006451C7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D02E48E1E0B4A5D006451C7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; + }; + 2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Bundle React Native Code And Images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00E356EA1AD99517003FC87E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 00E356F31AD99517003FC87E /* noderTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D02E4771E0B4A5D006451C7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */, + 2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D02E48C1E0B4A5D006451C7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2DCD954D1E0B4F2C00145EB5 /* noderTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* noder */; + targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; + }; + 2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2D02E47A1E0B4A5D006451C7 /* noder-tvOS */; + targetProxy = 2D02E4911E0B4A5D006451C7 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = noder; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 00E356F61AD99517003FC87E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = noderTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/noder.app/noder"; + }; + name = Debug; + }; + 00E356F71AD99517003FC87E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = noderTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/noder.app/noder"; + }; + name = Release; + }; + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../node_modules/react-native-blur/ios", + "$(SRCROOT)/../node_modules/react-native-camera/ios", + "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-code-push/ios/CodePush/**", + ); + INFOPLIST_FILE = noder/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.lingyong.me.noder; + PRODUCT_NAME = noder; + PROVISIONING_PROFILE = ""; + TARGETED_DEVICE_FAMILY = 1; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 1; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../node_modules/react-native-blur/ios", + "$(SRCROOT)/../node_modules/react-native-camera/ios", + "$(SRCROOT)/../node_modules/react-native-vector-icons/RNVectorIconsManager", + "$(SRCROOT)/../node_modules/react-native-code-push/ios/CodePush/**", + ); + INFOPLIST_FILE = noder/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.lingyong.me.noder; + PRODUCT_NAME = noder; + PROVISIONING_PROFILE = ""; + TARGETED_DEVICE_FAMILY = 1; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 2D02E4971E0B4A5E006451C7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "noder-tvOS/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.noder-tvOS"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.2; + }; + name = Debug; + }; + 2D02E4981E0B4A5E006451C7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "noder-tvOS/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.noder-tvOS"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.2; + }; + name = Release; + }; + 2D02E4991E0B4A5E006451C7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "noder-tvOSTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.noder-tvOSTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/noder-tvOS.app/noder-tvOS"; + TVOS_DEPLOYMENT_TARGET = 10.1; + }; + name = Debug; + }; + 2D02E49A1E0B4A5E006451C7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "noder-tvOSTests/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.noder-tvOSTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/noder-tvOS.app/noder-tvOS"; + TVOS_DEPLOYMENT_TARGET = 10.1; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Distribution: lingyong zhang (HT6H5U9WMQ)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: lingyong zhang (HT6H5U9WMQ)"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "noderTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00E356F61AD99517003FC87E /* Debug */, + 00E356F71AD99517003FC87E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "noder" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "noder-tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2D02E4971E0B4A5E006451C7 /* Debug */, + 2D02E4981E0B4A5E006451C7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "noder-tvOSTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2D02E4991E0B4A5E006451C7 /* Debug */, + 2D02E49A1E0B4A5E006451C7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "noder" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/ios/noder.xcodeproj/xcshareddata/xcschemes/noder-tvOS.xcscheme b/ios/noder.xcodeproj/xcshareddata/xcschemes/noder-tvOS.xcscheme new file mode 100644 index 00000000..1700bc56 --- /dev/null +++ b/ios/noder.xcodeproj/xcshareddata/xcschemes/noder-tvOS.xcscheme @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/noder.xcodeproj/xcshareddata/xcschemes/noder.xcscheme b/ios/noder.xcodeproj/xcshareddata/xcschemes/noder.xcscheme old mode 100755 new mode 100644 similarity index 84% rename from noder.xcodeproj/xcshareddata/xcschemes/noder.xcscheme rename to ios/noder.xcodeproj/xcshareddata/xcschemes/noder.xcscheme index 3ee2d638..13cbe074 --- a/noder.xcodeproj/xcshareddata/xcschemes/noder.xcscheme +++ b/ios/noder.xcodeproj/xcshareddata/xcschemes/noder.xcscheme @@ -3,9 +3,23 @@ LastUpgradeVersion = "0620" version = "1.3"> + + + + + buildForAnalyzing = "NO"> + shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + @@ -86,10 +93,10 @@ diff --git a/iOS/AppDelegate.h b/ios/noder/AppDelegate.h similarity index 100% rename from iOS/AppDelegate.h rename to ios/noder/AppDelegate.h diff --git a/ios/noder/AppDelegate.m b/ios/noder/AppDelegate.m new file mode 100644 index 00000000..72192c33 --- /dev/null +++ b/ios/noder/AppDelegate.m @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import "AppDelegate.h" +#import "CodePush.h" + +#import +#import + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + NSURL *jsCodeLocation; + +#ifdef DEBUG + jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; +#else + jsCodeLocation = [CodePush bundleURL]; +#endif + + RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation + moduleName:@"noder" + initialProperties:nil + launchOptions:launchOptions]; + rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; + + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIViewController *rootViewController = [UIViewController new]; + rootViewController.view = rootView; + self.window.rootViewController = rootViewController; + [self.window makeKeyAndVisible]; + return YES; +} + +@end diff --git a/iOS/Base.lproj/LaunchScreen.xib b/ios/noder/Base.lproj/LaunchScreen.xib similarity index 52% rename from iOS/Base.lproj/LaunchScreen.xib rename to ios/noder/Base.lproj/LaunchScreen.xib index 2ae859be..4e26c2d3 100644 --- a/iOS/Base.lproj/LaunchScreen.xib +++ b/ios/noder/Base.lproj/LaunchScreen.xib @@ -1,42 +1,36 @@ - + - + - + - - - + + - - - - + + + - + diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Contents.json b/ios/noder/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..b22f5b62 --- /dev/null +++ b/ios/noder/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,106 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-Small@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-Small@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-60@3x.png", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-Small.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-Small@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-40.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-76.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-83.5@2x.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-40.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-40.png new file mode 100644 index 00000000..1ff55fa8 Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-40.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png new file mode 100644 index 00000000..fbb55c17 Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png new file mode 100644 index 00000000..90c1fa03 Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png new file mode 100644 index 00000000..90c1fa03 Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png new file mode 100644 index 00000000..e8d047b5 Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-76.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-76.png new file mode 100644 index 00000000..339fc665 Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-76.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png new file mode 100644 index 00000000..4a693895 Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png new file mode 100644 index 00000000..1727247d Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-Small.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-Small.png new file mode 100644 index 00000000..0e199e4a Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-Small.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png new file mode 100644 index 00000000..66c5d49a Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png differ diff --git a/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png new file mode 100644 index 00000000..86cd7293 Binary files /dev/null and b/ios/noder/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png differ diff --git a/Source/logo/IOS/noder-Icon-450px.png b/ios/noder/Images.xcassets/AppIcon.appiconset/noder_icon.png similarity index 100% rename from Source/logo/IOS/noder-Icon-450px.png rename to ios/noder/Images.xcassets/AppIcon.appiconset/noder_icon.png diff --git a/ios/noder/Images.xcassets/Contents.json b/ios/noder/Images.xcassets/Contents.json new file mode 100644 index 00000000..2d92bd53 --- /dev/null +++ b/ios/noder/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/iOS/Images.xcassets/blog.imageset/Contents.json b/ios/noder/Images.xcassets/Image.imageset/Contents.json similarity index 53% rename from iOS/Images.xcassets/blog.imageset/Contents.json rename to ios/noder/Images.xcassets/Image.imageset/Contents.json index 69aef15c..31f960e7 100644 --- a/iOS/Images.xcassets/blog.imageset/Contents.json +++ b/ios/noder/Images.xcassets/Image.imageset/Contents.json @@ -2,18 +2,18 @@ "images" : [ { "idiom" : "universal", - "scale" : "1x", - "filename" : "blog@1x.png" + "filename" : "noderIcon@1x.png", + "scale" : "1x" }, { "idiom" : "universal", - "scale" : "2x", - "filename" : "blog@2x.png" + "filename" : "noderIcon@2x.png", + "scale" : "2x" }, { "idiom" : "universal", - "scale" : "3x", - "filename" : "blog@3x.png" + "filename" : "noderIcon@3x.png", + "scale" : "3x" } ], "info" : { diff --git a/iOS/Images.xcassets/logo.imageset/logo@1x.png b/ios/noder/Images.xcassets/Image.imageset/noderIcon@1x.png similarity index 100% rename from iOS/Images.xcassets/logo.imageset/logo@1x.png rename to ios/noder/Images.xcassets/Image.imageset/noderIcon@1x.png diff --git a/iOS/Images.xcassets/logo.imageset/logo@2x.png b/ios/noder/Images.xcassets/Image.imageset/noderIcon@2x.png similarity index 100% rename from iOS/Images.xcassets/logo.imageset/logo@2x.png rename to ios/noder/Images.xcassets/Image.imageset/noderIcon@2x.png diff --git a/iOS/Images.xcassets/logo.imageset/logo@3x.png b/ios/noder/Images.xcassets/Image.imageset/noderIcon@3x.png similarity index 100% rename from iOS/Images.xcassets/logo.imageset/logo@3x.png rename to ios/noder/Images.xcassets/Image.imageset/noderIcon@3x.png diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Contents.json b/ios/noder/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 00000000..4941cefc --- /dev/null +++ b/ios/noder/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,134 @@ +{ + "images" : [ + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "736h", + "filename" : "Default1242x2208.png", + "minimum-system-version" : "8.0", + "orientation" : "portrait", + "scale" : "3x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "736h", + "filename" : "Default2208x1242.png", + "minimum-system-version" : "8.0", + "orientation" : "landscape", + "scale" : "3x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "667h", + "filename" : "Default750x1334.png", + "minimum-system-version" : "8.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default640x960.png", + "scale" : "2x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "retina4", + "filename" : "Default640x1136.png", + "minimum-system-version" : "7.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default768x1024.png", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default1024x768.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default1536x2048.png", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default2048x1536.png", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "filename" : "Default320x480.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "filename" : "Default640x960.png", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "filename" : "Default640x1136.png", + "subtype" : "retina4", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "filename" : "Default768x1024.png", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "filename" : "Default1024x768.png", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "filename" : "Default1536x2048.png", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "filename" : "Default2048x1536.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default.png new file mode 100644 index 00000000..9e1c11fa Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default1024x768.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default1024x768.png new file mode 100644 index 00000000..9010dc48 Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default1024x768.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default1242x2208.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default1242x2208.png new file mode 100644 index 00000000..4bc153cf Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default1242x2208.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default1536x2048.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default1536x2048.png new file mode 100644 index 00000000..7c4790b9 Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default1536x2048.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default2048x1536.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default2048x1536.png new file mode 100644 index 00000000..391b0330 Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default2048x1536.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default2208x1242.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default2208x1242.png new file mode 100644 index 00000000..fc10842c Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default2208x1242.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default320x480.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default320x480.png new file mode 100644 index 00000000..6bf157a2 Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default320x480.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default640x1136.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default640x1136.png new file mode 100644 index 00000000..205e2ced Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default640x1136.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default640x960.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default640x960.png new file mode 100644 index 00000000..f64c0199 Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default640x960.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default750x1334.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default750x1334.png new file mode 100644 index 00000000..90086c48 Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default750x1334.png differ diff --git a/ios/noder/Images.xcassets/LaunchImage.launchimage/Default768x1024.png b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default768x1024.png new file mode 100644 index 00000000..d85bb474 Binary files /dev/null and b/ios/noder/Images.xcassets/LaunchImage.launchimage/Default768x1024.png differ diff --git a/ios/noder/Info.plist b/ios/noder/Info.plist new file mode 100644 index 00000000..e88f9c2d --- /dev/null +++ b/ios/noder/Info.plist @@ -0,0 +1,69 @@ + + + + + CFBundleDevelopmentRegion + zh_CN + CFBundleDisplayName + noder + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Noder + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + CodePushDeploymentKey + Q2A8khx6JV4mXXcS0usR0LipDz0Y410YoZxlZ + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UIViewControllerBasedStatusBarAppearance + + NSLocationWhenInUseUsageDescription + + UIAppFonts + + Entypo.ttf + EvilIcons.ttf + FontAwesome.ttf + Foundation.ttf + Ionicons.ttf + MaterialIcons.ttf + Octicons.ttf + Zocial.ttf + + NSAppTransportSecurity + + + NSAllowsArbitraryLoads + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + + + + + diff --git a/iOS/main.m b/ios/noder/main.m similarity index 100% rename from iOS/main.m rename to ios/noder/main.m diff --git a/ios/noderTests/Info.plist b/ios/noderTests/Info.plist new file mode 100644 index 00000000..886825cc --- /dev/null +++ b/ios/noderTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/ios/noderTests/noderTests.m b/ios/noderTests/noderTests.m new file mode 100644 index 00000000..fe937904 --- /dev/null +++ b/ios/noderTests/noderTests.m @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#import +#import + +#import +#import + +#define TIMEOUT_SECONDS 240 +#define TEXT_TO_LOOK_FOR @"Welcome to React Native!" + +@interface noderTests : XCTestCase + +@end + +@implementation noderTests + +- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test +{ + if (test(view)) { + return YES; + } + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; +} + +- (void)testRendersWelcomeScreen +{ + UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; + + __block NSString *redboxError = nil; + RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + if (level >= RCTLogLevelError) { + redboxError = message; + } + }); + + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + + foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } + + RCTSetLogFunction(RCTDefaultLogFunction); + + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); +} + + +@end diff --git a/noder.xcodeproj/project.pbxproj b/noder.xcodeproj/project.pbxproj deleted file mode 100755 index c5f6074f..00000000 --- a/noder.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1012 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 00E356F31AD99517003FC87E /* noderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* noderTests.m */; }; - 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; - 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; - 9EAD88F81B61342F005F1E9E /* main.jsbundle in Resources */ = {isa = PBXBuildFile; fileRef = 9EAD88F71B61342F005F1E9E /* main.jsbundle */; }; - 9EC98E641B0DC0A1006A460D /* libReactNativeIcons.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EC98E631B0DC07A006A460D /* libReactNativeIcons.a */; }; - 9EC98E8C1B0DC2D6006A460D /* FontAwesome.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9EC98E881B0DC2D6006A460D /* FontAwesome.otf */; }; - 9EC98E8D1B0DC2D6006A460D /* foundation-icons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9EC98E891B0DC2D6006A460D /* foundation-icons.ttf */; }; - 9EC98E8E1B0DC2D6006A460D /* ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9EC98E8A1B0DC2D6006A460D /* ionicons.ttf */; }; - 9EC98E8F1B0DC2D6006A460D /* zocial-regular-webfont.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9EC98E8B1B0DC2D6006A460D /* zocial-regular-webfont.ttf */; }; - 9EE1BBD41B3D0F8400B65649 /* libRNModal.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BBD31B3D0B3B00B65649 /* libRNModal.a */; }; - 9EE1BBD61B3D0FC400B65649 /* libRCTCamera.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EC98EBD1B131C19006A460D /* libRCTCamera.a */; }; - 9EE1BBD71B3D0FCC00B65649 /* libRCTAnimationExperimental.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EFC9A691B26E157009961F3 /* libRCTAnimationExperimental.a */; }; - 9EE1BBDE1B3D11B400B65649 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BBDD1B3D119A00B65649 /* libRCTActionSheet.a */; }; - 9EE1BC211B3D12CB00B65649 /* libART.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BBE41B3D11CF00B65649 /* libART.a */; }; - 9EE1BC221B3D12CB00B65649 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BBEA1B3D11EC00B65649 /* libRCTGeolocation.a */; }; - 9EE1BC231B3D12CB00B65649 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BBF01B3D11FF00B65649 /* libRCTImage.a */; }; - 9EE1BC241B3D12CB00B65649 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BBF61B3D121800B65649 /* libRCTLinking.a */; }; - 9EE1BC251B3D12CB00B65649 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BBFC1B3D122D00B65649 /* libRCTNetwork.a */; }; - 9EE1BC261B3D12CB00B65649 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BC021B3D124300B65649 /* libRCTPushNotification.a */; }; - 9EE1BC271B3D12CB00B65649 /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BC081B3D126000B65649 /* libRCTSettings.a */; }; - 9EE1BC281B3D12CB00B65649 /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BC0E1B3D128300B65649 /* libRCTTest.a */; }; - 9EE1BC291B3D12CB00B65649 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BC141B3D129700B65649 /* libRCTText.a */; }; - 9EE1BC2A1B3D12CB00B65649 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BC1A1B3D12AF00B65649 /* libRCTVibration.a */; }; - 9EE1BC2B1B3D12CB00B65649 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BC201B3D12C300B65649 /* libRCTWebSocket.a */; }; - 9EE1BC321B419C4700B65649 /* libRNKeyboardEvents.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE1BC311B419C1300B65649 /* libRNKeyboardEvents.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 13B07F861A680F5B00A75B9A; - remoteInfo = noder; - }; - 146834031AC3E56700842450 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; - remoteInfo = React; - }; - 9EC98E621B0DC07A006A460D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EC98E521B0DC07A006A460D /* ReactNativeIcons.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2F5A3EB81ACDBF8000439386; - remoteInfo = ReactNativeIcons; - }; - 9EC98EBC1B131C19006A460D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EC98EB81B131C19006A460D /* RCTCamera.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 4107012F1ACB723B00C6AA39; - remoteInfo = RCTCamera; - }; - 9EE1BBD21B3D0B3B00B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BBCE1B3D0B3B00B65649 /* RNModal.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RNModal; - }; - 9EE1BBDC1B3D119A00B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BBD81B3D119A00B65649 /* RCTActionSheet.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTActionSheet; - }; - 9EE1BBE31B3D11CF00B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BBDF1B3D11CE00B65649 /* ART.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 0CF68AC11AF0540F00FF9E5C; - remoteInfo = ART; - }; - 9EE1BBE91B3D11EC00B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BBE51B3D11EC00B65649 /* RCTGeolocation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTGeolocation; - }; - 9EE1BBEF1B3D11FF00B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BBEB1B3D11FF00B65649 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5115D1A9E6B3D00147676; - remoteInfo = RCTImage; - }; - 9EE1BBF51B3D121800B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BBF11B3D121800B65649 /* RCTLinking.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTLinking; - }; - 9EE1BBFB1B3D122D00B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BBF71B3D122D00B65649 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B511DB1A9E6C8500147676; - remoteInfo = RCTNetwork; - }; - 9EE1BC011B3D124300B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BBFD1B3D124200B65649 /* RCTPushNotification.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTPushNotification; - }; - 9EE1BC071B3D126000B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BC031B3D126000B65649 /* RCTSettings.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTSettings; - }; - 9EE1BC0D1B3D128300B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BC091B3D128300B65649 /* RCTTest.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 580C376F1AB104AF0015E709; - remoteInfo = RCTTest; - }; - 9EE1BC131B3D129700B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BC0F1B3D129600B65649 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5119B1A9E6C1200147676; - remoteInfo = RCTText; - }; - 9EE1BC191B3D12AF00B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BC151B3D12AF00B65649 /* RCTVibration.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 832C81801AAF6DEF007FA2F7; - remoteInfo = RCTVibration; - }; - 9EE1BC1F1B3D12C300B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BC1B1B3D12C300B65649 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3C86DF461ADF2C930047B81A; - remoteInfo = RCTWebSocket; - }; - 9EE1BC301B419C1300B65649 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EE1BC2C1B419C1300B65649 /* RNKeyboardEvents.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = F12AFB9B1ADAF8F800E0535D; - remoteInfo = RNKeyboardEvents; - }; - 9EFC9A681B26E157009961F3 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 9EFC9A641B26E157009961F3 /* RCTAnimationExperimental.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTAnimationExperimental; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 00E356EE1AD99517003FC87E /* noderTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = noderTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 00E356F21AD99517003FC87E /* noderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = noderTests.m; sourceTree = ""; }; - 13B07F961A680F5B00A75B9A /* noder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = noder.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = iOS/AppDelegate.h; sourceTree = ""; }; - 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = AppDelegate.m; path = iOS/AppDelegate.m; sourceTree = ""; }; - 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = iOS/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = iOS/Info.plist; sourceTree = ""; }; - 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = iOS/main.m; sourceTree = ""; }; - 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; - 9EAD88F71B61342F005F1E9E /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = iOS/main.jsbundle; sourceTree = ""; }; - 9EC98E521B0DC07A006A460D /* ReactNativeIcons.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeIcons.xcodeproj; path = "node_modules/react-native-icons/ios/ReactNativeIcons.xcodeproj"; sourceTree = ""; }; - 9EC98E881B0DC2D6006A460D /* FontAwesome.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = FontAwesome.otf; path = "node_modules/react-native-icons/ios/ReactNativeIcons/Libraries/FontAwesomeKit/FontAwesome.otf"; sourceTree = ""; }; - 9EC98E891B0DC2D6006A460D /* foundation-icons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "foundation-icons.ttf"; path = "node_modules/react-native-icons/ios/ReactNativeIcons/Libraries/FontAwesomeKit/foundation-icons.ttf"; sourceTree = ""; }; - 9EC98E8A1B0DC2D6006A460D /* ionicons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = ionicons.ttf; path = "node_modules/react-native-icons/ios/ReactNativeIcons/Libraries/FontAwesomeKit/ionicons.ttf"; sourceTree = ""; }; - 9EC98E8B1B0DC2D6006A460D /* zocial-regular-webfont.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "zocial-regular-webfont.ttf"; path = "node_modules/react-native-icons/ios/ReactNativeIcons/Libraries/FontAwesomeKit/zocial-regular-webfont.ttf"; sourceTree = ""; }; - 9EC98EB81B131C19006A460D /* RCTCamera.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTCamera.xcodeproj; path = "node_modules/react-native-camera/RCTCamera.xcodeproj"; sourceTree = ""; }; - 9EE1BBCE1B3D0B3B00B65649 /* RNModal.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNModal.xcodeproj; path = "node_modules/react-native-modal/RNModal.xcodeproj"; sourceTree = ""; }; - 9EE1BBD81B3D119A00B65649 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; - 9EE1BBDF1B3D11CE00B65649 /* ART.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ART.xcodeproj; path = "node_modules/react-native/Libraries/ART/ART.xcodeproj"; sourceTree = ""; }; - 9EE1BBE51B3D11EC00B65649 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; }; - 9EE1BBEB1B3D11FF00B65649 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; - 9EE1BBF11B3D121800B65649 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; - 9EE1BBF71B3D122D00B65649 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; - 9EE1BBFD1B3D124200B65649 /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = "node_modules/react-native/Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj"; sourceTree = ""; }; - 9EE1BC031B3D126000B65649 /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; - 9EE1BC091B3D128300B65649 /* RCTTest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTTest.xcodeproj; path = "node_modules/react-native/Libraries/RCTTest/RCTTest.xcodeproj"; sourceTree = ""; }; - 9EE1BC0F1B3D129600B65649 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; - 9EE1BC151B3D12AF00B65649 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; - 9EE1BC1B1B3D12C300B65649 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; - 9EE1BC2C1B419C1300B65649 /* RNKeyboardEvents.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNKeyboardEvents.xcodeproj; path = "node_modules/react-native-keyboardevents/RNKeyboardEvents.xcodeproj"; sourceTree = ""; }; - 9EFC9A641B26E157009961F3 /* RCTAnimationExperimental.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimationExperimental.xcodeproj; path = "node_modules/react-native/Libraries/Animation/RCTAnimationExperimental.xcodeproj"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 00E356EB1AD99517003FC87E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9EE1BC321B419C4700B65649 /* libRNKeyboardEvents.a in Frameworks */, - 9EE1BC211B3D12CB00B65649 /* libART.a in Frameworks */, - 9EE1BC221B3D12CB00B65649 /* libRCTGeolocation.a in Frameworks */, - 9EE1BC231B3D12CB00B65649 /* libRCTImage.a in Frameworks */, - 9EE1BC241B3D12CB00B65649 /* libRCTLinking.a in Frameworks */, - 9EE1BC251B3D12CB00B65649 /* libRCTNetwork.a in Frameworks */, - 9EE1BC261B3D12CB00B65649 /* libRCTPushNotification.a in Frameworks */, - 9EE1BC271B3D12CB00B65649 /* libRCTSettings.a in Frameworks */, - 9EE1BC281B3D12CB00B65649 /* libRCTTest.a in Frameworks */, - 9EE1BC291B3D12CB00B65649 /* libRCTText.a in Frameworks */, - 9EE1BC2A1B3D12CB00B65649 /* libRCTVibration.a in Frameworks */, - 9EE1BC2B1B3D12CB00B65649 /* libRCTWebSocket.a in Frameworks */, - 9EE1BBDE1B3D11B400B65649 /* libRCTActionSheet.a in Frameworks */, - 9EE1BBD71B3D0FCC00B65649 /* libRCTAnimationExperimental.a in Frameworks */, - 9EE1BBD61B3D0FC400B65649 /* libRCTCamera.a in Frameworks */, - 9EE1BBD41B3D0F8400B65649 /* libRNModal.a in Frameworks */, - 9EC98E641B0DC0A1006A460D /* libReactNativeIcons.a in Frameworks */, - 146834051AC3E58100842450 /* libReact.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 00E356EF1AD99517003FC87E /* noderTests */ = { - isa = PBXGroup; - children = ( - 00E356F21AD99517003FC87E /* noderTests.m */, - 00E356F01AD99517003FC87E /* Supporting Files */, - ); - path = noderTests; - sourceTree = ""; - }; - 00E356F01AD99517003FC87E /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 00E356F11AD99517003FC87E /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 13B07FAE1A68108700A75B9A /* noder */ = { - isa = PBXGroup; - children = ( - 9EAD88F71B61342F005F1E9E /* main.jsbundle */, - 13B07FAF1A68108700A75B9A /* AppDelegate.h */, - 13B07FB01A68108700A75B9A /* AppDelegate.m */, - 13B07FB51A68108700A75B9A /* Images.xcassets */, - 13B07FB61A68108700A75B9A /* Info.plist */, - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, - 13B07FB71A68108700A75B9A /* main.m */, - ); - name = noder; - sourceTree = ""; - }; - 146834001AC3E56700842450 /* Products */ = { - isa = PBXGroup; - children = ( - 146834041AC3E56700842450 /* libReact.a */, - ); - name = Products; - sourceTree = ""; - }; - 832341AE1AAA6A7D00B99B32 /* Libraries */ = { - isa = PBXGroup; - children = ( - 9EE1BC2C1B419C1300B65649 /* RNKeyboardEvents.xcodeproj */, - 9EE1BC1B1B3D12C300B65649 /* RCTWebSocket.xcodeproj */, - 9EE1BC151B3D12AF00B65649 /* RCTVibration.xcodeproj */, - 9EE1BC0F1B3D129600B65649 /* RCTText.xcodeproj */, - 9EE1BC091B3D128300B65649 /* RCTTest.xcodeproj */, - 9EE1BC031B3D126000B65649 /* RCTSettings.xcodeproj */, - 9EE1BBFD1B3D124200B65649 /* RCTPushNotification.xcodeproj */, - 9EE1BBF71B3D122D00B65649 /* RCTNetwork.xcodeproj */, - 9EE1BBF11B3D121800B65649 /* RCTLinking.xcodeproj */, - 9EE1BBEB1B3D11FF00B65649 /* RCTImage.xcodeproj */, - 9EE1BBE51B3D11EC00B65649 /* RCTGeolocation.xcodeproj */, - 9EE1BBDF1B3D11CE00B65649 /* ART.xcodeproj */, - 9EE1BBD81B3D119A00B65649 /* RCTActionSheet.xcodeproj */, - 9EE1BBCE1B3D0B3B00B65649 /* RNModal.xcodeproj */, - 9EFC9A641B26E157009961F3 /* RCTAnimationExperimental.xcodeproj */, - 9EC98EB81B131C19006A460D /* RCTCamera.xcodeproj */, - 9EC98E521B0DC07A006A460D /* ReactNativeIcons.xcodeproj */, - 146833FF1AC3E56700842450 /* React.xcodeproj */, - ); - name = Libraries; - sourceTree = ""; - }; - 83CBB9F61A601CBA00E9B192 = { - isa = PBXGroup; - children = ( - 9EC98E881B0DC2D6006A460D /* FontAwesome.otf */, - 9EC98E891B0DC2D6006A460D /* foundation-icons.ttf */, - 9EC98E8A1B0DC2D6006A460D /* ionicons.ttf */, - 9EC98E8B1B0DC2D6006A460D /* zocial-regular-webfont.ttf */, - 13B07FAE1A68108700A75B9A /* noder */, - 832341AE1AAA6A7D00B99B32 /* Libraries */, - 00E356EF1AD99517003FC87E /* noderTests */, - 83CBBA001A601CBA00E9B192 /* Products */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - }; - 83CBBA001A601CBA00E9B192 /* Products */ = { - isa = PBXGroup; - children = ( - 13B07F961A680F5B00A75B9A /* noder.app */, - 00E356EE1AD99517003FC87E /* noderTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 9EC98E531B0DC07A006A460D /* Products */ = { - isa = PBXGroup; - children = ( - 9EC98E631B0DC07A006A460D /* libReactNativeIcons.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EC98EB91B131C19006A460D /* Products */ = { - isa = PBXGroup; - children = ( - 9EC98EBD1B131C19006A460D /* libRCTCamera.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BBCF1B3D0B3B00B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BBD31B3D0B3B00B65649 /* libRNModal.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BBD91B3D119A00B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BBDD1B3D119A00B65649 /* libRCTActionSheet.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BBE01B3D11CE00B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BBE41B3D11CF00B65649 /* libART.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BBE61B3D11EC00B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BBEA1B3D11EC00B65649 /* libRCTGeolocation.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BBEC1B3D11FF00B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BBF01B3D11FF00B65649 /* libRCTImage.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BBF21B3D121800B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BBF61B3D121800B65649 /* libRCTLinking.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BBF81B3D122D00B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BBFC1B3D122D00B65649 /* libRCTNetwork.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BBFE1B3D124200B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BC021B3D124300B65649 /* libRCTPushNotification.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BC041B3D126000B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BC081B3D126000B65649 /* libRCTSettings.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BC0A1B3D128300B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BC0E1B3D128300B65649 /* libRCTTest.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BC101B3D129600B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BC141B3D129700B65649 /* libRCTText.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BC161B3D12AF00B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BC1A1B3D12AF00B65649 /* libRCTVibration.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BC1C1B3D12C300B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BC201B3D12C300B65649 /* libRCTWebSocket.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EE1BC2D1B419C1300B65649 /* Products */ = { - isa = PBXGroup; - children = ( - 9EE1BC311B419C1300B65649 /* libRNKeyboardEvents.a */, - ); - name = Products; - sourceTree = ""; - }; - 9EFC9A651B26E157009961F3 /* Products */ = { - isa = PBXGroup; - children = ( - 9EFC9A691B26E157009961F3 /* libRCTAnimationExperimental.a */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 00E356ED1AD99517003FC87E /* noderTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "noderTests" */; - buildPhases = ( - 00E356EA1AD99517003FC87E /* Sources */, - 00E356EB1AD99517003FC87E /* Frameworks */, - 00E356EC1AD99517003FC87E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 00E356F51AD99517003FC87E /* PBXTargetDependency */, - ); - name = noderTests; - productName = noderTests; - productReference = 00E356EE1AD99517003FC87E /* noderTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 13B07F861A680F5B00A75B9A /* noder */ = { - isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "noder" */; - buildPhases = ( - 13B07F871A680F5B00A75B9A /* Sources */, - 13B07F8C1A680F5B00A75B9A /* Frameworks */, - 13B07F8E1A680F5B00A75B9A /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = noder; - productName = "Hello World"; - productReference = 13B07F961A680F5B00A75B9A /* noder.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 83CBB9F71A601CBA00E9B192 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0610; - ORGANIZATIONNAME = Facebook; - TargetAttributes = { - 00E356ED1AD99517003FC87E = { - CreatedOnToolsVersion = 6.2; - TestTargetID = 13B07F861A680F5B00A75B9A; - }; - 13B07F861A680F5B00A75B9A = { - DevelopmentTeam = N4TN9TD34J; - }; - }; - }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "noder" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 83CBB9F61A601CBA00E9B192; - productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = 9EE1BBE01B3D11CE00B65649 /* Products */; - ProjectRef = 9EE1BBDF1B3D11CE00B65649 /* ART.xcodeproj */; - }, - { - ProductGroup = 9EE1BBD91B3D119A00B65649 /* Products */; - ProjectRef = 9EE1BBD81B3D119A00B65649 /* RCTActionSheet.xcodeproj */; - }, - { - ProductGroup = 9EFC9A651B26E157009961F3 /* Products */; - ProjectRef = 9EFC9A641B26E157009961F3 /* RCTAnimationExperimental.xcodeproj */; - }, - { - ProductGroup = 9EC98EB91B131C19006A460D /* Products */; - ProjectRef = 9EC98EB81B131C19006A460D /* RCTCamera.xcodeproj */; - }, - { - ProductGroup = 9EE1BBE61B3D11EC00B65649 /* Products */; - ProjectRef = 9EE1BBE51B3D11EC00B65649 /* RCTGeolocation.xcodeproj */; - }, - { - ProductGroup = 9EE1BBEC1B3D11FF00B65649 /* Products */; - ProjectRef = 9EE1BBEB1B3D11FF00B65649 /* RCTImage.xcodeproj */; - }, - { - ProductGroup = 9EE1BBF21B3D121800B65649 /* Products */; - ProjectRef = 9EE1BBF11B3D121800B65649 /* RCTLinking.xcodeproj */; - }, - { - ProductGroup = 9EE1BBF81B3D122D00B65649 /* Products */; - ProjectRef = 9EE1BBF71B3D122D00B65649 /* RCTNetwork.xcodeproj */; - }, - { - ProductGroup = 9EE1BBFE1B3D124200B65649 /* Products */; - ProjectRef = 9EE1BBFD1B3D124200B65649 /* RCTPushNotification.xcodeproj */; - }, - { - ProductGroup = 9EE1BC041B3D126000B65649 /* Products */; - ProjectRef = 9EE1BC031B3D126000B65649 /* RCTSettings.xcodeproj */; - }, - { - ProductGroup = 9EE1BC0A1B3D128300B65649 /* Products */; - ProjectRef = 9EE1BC091B3D128300B65649 /* RCTTest.xcodeproj */; - }, - { - ProductGroup = 9EE1BC101B3D129600B65649 /* Products */; - ProjectRef = 9EE1BC0F1B3D129600B65649 /* RCTText.xcodeproj */; - }, - { - ProductGroup = 9EE1BC161B3D12AF00B65649 /* Products */; - ProjectRef = 9EE1BC151B3D12AF00B65649 /* RCTVibration.xcodeproj */; - }, - { - ProductGroup = 9EE1BC1C1B3D12C300B65649 /* Products */; - ProjectRef = 9EE1BC1B1B3D12C300B65649 /* RCTWebSocket.xcodeproj */; - }, - { - ProductGroup = 146834001AC3E56700842450 /* Products */; - ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; - }, - { - ProductGroup = 9EC98E531B0DC07A006A460D /* Products */; - ProjectRef = 9EC98E521B0DC07A006A460D /* ReactNativeIcons.xcodeproj */; - }, - { - ProductGroup = 9EE1BC2D1B419C1300B65649 /* Products */; - ProjectRef = 9EE1BC2C1B419C1300B65649 /* RNKeyboardEvents.xcodeproj */; - }, - { - ProductGroup = 9EE1BBCF1B3D0B3B00B65649 /* Products */; - ProjectRef = 9EE1BBCE1B3D0B3B00B65649 /* RNModal.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - 13B07F861A680F5B00A75B9A /* noder */, - 00E356ED1AD99517003FC87E /* noderTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - 146834041AC3E56700842450 /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EC98E631B0DC07A006A460D /* libReactNativeIcons.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReactNativeIcons.a; - remoteRef = 9EC98E621B0DC07A006A460D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EC98EBD1B131C19006A460D /* libRCTCamera.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTCamera.a; - remoteRef = 9EC98EBC1B131C19006A460D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BBD31B3D0B3B00B65649 /* libRNModal.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRNModal.a; - remoteRef = 9EE1BBD21B3D0B3B00B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BBDD1B3D119A00B65649 /* libRCTActionSheet.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTActionSheet.a; - remoteRef = 9EE1BBDC1B3D119A00B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BBE41B3D11CF00B65649 /* libART.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libART.a; - remoteRef = 9EE1BBE31B3D11CF00B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BBEA1B3D11EC00B65649 /* libRCTGeolocation.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTGeolocation.a; - remoteRef = 9EE1BBE91B3D11EC00B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BBF01B3D11FF00B65649 /* libRCTImage.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTImage.a; - remoteRef = 9EE1BBEF1B3D11FF00B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BBF61B3D121800B65649 /* libRCTLinking.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTLinking.a; - remoteRef = 9EE1BBF51B3D121800B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BBFC1B3D122D00B65649 /* libRCTNetwork.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTNetwork.a; - remoteRef = 9EE1BBFB1B3D122D00B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BC021B3D124300B65649 /* libRCTPushNotification.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTPushNotification.a; - remoteRef = 9EE1BC011B3D124300B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BC081B3D126000B65649 /* libRCTSettings.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTSettings.a; - remoteRef = 9EE1BC071B3D126000B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BC0E1B3D128300B65649 /* libRCTTest.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTTest.a; - remoteRef = 9EE1BC0D1B3D128300B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BC141B3D129700B65649 /* libRCTText.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTText.a; - remoteRef = 9EE1BC131B3D129700B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BC1A1B3D12AF00B65649 /* libRCTVibration.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTVibration.a; - remoteRef = 9EE1BC191B3D12AF00B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BC201B3D12C300B65649 /* libRCTWebSocket.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTWebSocket.a; - remoteRef = 9EE1BC1F1B3D12C300B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EE1BC311B419C1300B65649 /* libRNKeyboardEvents.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRNKeyboardEvents.a; - remoteRef = 9EE1BC301B419C1300B65649 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 9EFC9A691B26E157009961F3 /* libRCTAnimationExperimental.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTAnimationExperimental.a; - remoteRef = 9EFC9A681B26E157009961F3 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - 00E356EC1AD99517003FC87E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F8E1A680F5B00A75B9A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 9EC98E8C1B0DC2D6006A460D /* FontAwesome.otf in Resources */, - 9EC98E8D1B0DC2D6006A460D /* foundation-icons.ttf in Resources */, - 9EC98E8E1B0DC2D6006A460D /* ionicons.ttf in Resources */, - 9EC98E8F1B0DC2D6006A460D /* zocial-regular-webfont.ttf in Resources */, - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - 9EAD88F81B61342F005F1E9E /* main.jsbundle in Resources */, - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 00E356EA1AD99517003FC87E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 00E356F31AD99517003FC87E /* noderTests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F871A680F5B00A75B9A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, - 13B07FC11A68108700A75B9A /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 13B07F861A680F5B00A75B9A /* noder */; - targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 13B07FB21A68108700A75B9A /* Base */, - ); - name = LaunchScreen.xib; - path = iOS; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 00E356F61AD99517003FC87E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = noderTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/noder.app/noder"; - }; - name = Debug; - }; - 00E356F71AD99517003FC87E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COPY_PHASE_STRIP = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); - INFOPLIST_FILE = noderTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/noder.app/noder"; - }; - name = Release; - }; - 13B07F941A680F5B00A75B9A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/node_modules/react-native/React/**", - ); - INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = noder; - PROVISIONING_PROFILE = ""; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 13B07F951A680F5B00A75B9A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/node_modules/react-native/React/**", - ); - INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = noder; - PROVISIONING_PROFILE = ""; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 83CBBA201A601CBA00E9B192 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/node_modules/react-native/React/**", - ); - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 83CBBA211A601CBA00E9B192 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/node_modules/react-native/React/**", - ); - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "noderTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 00E356F61AD99517003FC87E /* Debug */, - 00E356F71AD99517003FC87E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "noder" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 13B07F941A680F5B00A75B9A /* Debug */, - 13B07F951A680F5B00A75B9A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "noder" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83CBBA201A601CBA00E9B192 /* Debug */, - 83CBBA211A601CBA00E9B192 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} diff --git a/package.json b/package.json index d5796b09..f618df88 100644 --- a/package.json +++ b/package.json @@ -1,35 +1,119 @@ { "name": "noder", - "version": "0.0.1", - "private": true, + "version": "1.0.5", "scripts": { - "start": "gulp start" + "start": "node node_modules/react-native/local-cli/cli.js start", + "test": "jest", + "android": "node node_modules/react-native/local-cli/cli.js run-android", + "ios": "node node_modules/react-native/local-cli/cli.js run-ios", + "web": "node node_modules/react-web/local-cli/cli.js start web/webpack.config.js", + "log": "adb logcat *:S ReactNative:V ReactNativeJS:V", + "build-web": "node node_modules/react-web/local-cli/cli.js bundle web/webpack.config.js", + "build-ios": "react-native unbundle --entry-file index.ios.js --platform ios --dev false", + "build-android": "cd android && ./gradlew assembleRelease && open app/build/outputs/apk && cd ..", + "e2e-update-server-web": "webdriver-manager update --versions.standalone=3.7.1 --versions.gecko=v0.18.0 --versions.chrome=2.32", + "e2e-server-web": "touch node_modules/webdriver-manager/selenium/standalone-response.xml; touch node_modules/webdriver-manager/selenium/chrome-response.xml; webdriver-manager start --versions.standalone=3.7.1 --versions.gecko=v0.18.0 --versions.chrome=2.32", + "e2e-web": "codeceptjs run", + "e2e-server-native": "appium", + "e2e-android": "codeceptjs run --profile=android", + "e2e-ios": "codeceptjs run --profile=ios", + "checkversion": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json", + "postinstall": "npm run checkversion", + "push-android": "code-push release-react Noder android --deploymentName Staging", + "push-ios": "code-push release-react Noder ios --deploymentName Staging", + "push-android-prod": "code-push release-react Noder android --deploymentName Production", + "push-ios-prod": "code-push release-react Noder ios --deploymentName Production", + "push-key": "code-push deployment ls Noder -k", + "i-taobao": "npm i --registry=https://registry.npm.taobao.org", + "standard": "eslint --fix '**/*.js'" }, "dependencies": { + "fetch-detector": "^1.0.0", + "fetch-ie8": "^1.4.3", + "flux-standard-action": "^1.2.0", + "lodash": "^4.15.0", "markdown": "0.5.0", - "moment": "^2.10.6", - "query-string": "^2.4.0", - "react-native": "^0.8.0", - "react-native-blur": "^0.5.4", - "react-native-button": "1.2.0", - "react-native-camera": "0.3.3", - "react-native-html-render": "^1.0.2", - "react-native-icons": "^0.3.4", - "react-native-keyboardevents": "^0.4.5", - "react-native-modal": "0.3.8", - "react-native-scrollable-tab-view": "^0.1.10", - "rebound": "0.0.13", - "redux": "1.0.0-alpha" + "moment": "^2.14.1", + "query-string": "^4.2.3", + "react": "16.0.0", + "react-addons-pure-render-mixin": "15.6.2", + "react-dom": "16.0.0", + "react-native": "0.51.0", + "react-native-barcodescanner": "git+https://github.com/const-z/react-native-barcodescanner", + "react-native-blur": "3.2.2", + "react-native-button": "2.1.0", + "react-native-camera": "0.12.0", + "react-native-code-push": "^5.2.0-beta", + "react-native-deprecated-custom-components": "git+https://github.com/facebookarchive/react-native-custom-components", + "react-native-html-render": "git+https://github.com/soliury/react-native-html-render", + "react-native-scrollable-tab-view": "git+https://github.com/flyskywhy/react-native-scrollable-tab-view#0.6.6", + "react-native-vector-icons": "^4.0.1", + "react-redux": "4.4.8", + "react-web": "https://github.com/flyskywhy/react-web.git#99adb56", + "redux": "^3.5.2", + "redux-actions": "^2.0.1", + "redux-logger": "^3.0.1", + "redux-promise": "^0.5.3", + "redux-thunk": "^2.1.0" }, "devDependencies": { + "babel-eslint": "^7.2.1", + "babel-jest": "22.0.4", + "babel-loader": "^6.2.4", + "babel-polyfill": "^6.13.0", + "babel-preset-es2015": "^6.6.0", + "babel-preset-react": "^6.5.0", + "babel-preset-react-native": "4.0.0", + "babel-preset-stage-1": "^6.5.0", + "codeceptjs": "1.1.0", "coffee-script": "^1.9.2", "dev-ip": "^1.0.1", - "eslint": "^1.1.0", - "eslint-plugin-react": "^3.2.2", - "gulp": "^3.9.0", + "eslint": "^3.19.0", + "eslint-config-standard": "^10.2.0", + "eslint-config-standard-react": "^4.3.0", + "eslint-plugin-flowtype": "^2.30.4", + "eslint-plugin-promise": "^3.5.0", + "eslint-plugin-react": "^6.10.3", + "eslint-plugin-standard": "^3.0.1", + "file-loader": "^0.9.0", + "gulp": "^3.9.1", "gulp-replace": "^0.5.4", "gulp-util": "^3.0.4", - "run-sequence": "^1.1.0" + "haste-resolver-webpack-plugin": "^0.2.1", + "jest": "22.0.4", + "json-loader": "^0.5.4", + "mocha": "^4.0.1", + "react-hot-loader": "^3.1.3", + "react-native-cli": "^2.0.1", + "react-test-renderer": "16.0.0", + "redux-devtools": "^3.3.1", + "run-sequence": "^1.2.2", + "snazzy": "^7.0.0", + "standard": "^10.0.1", + "url-loader": "^0.5.7", + "webdriver-manager": "^12.0.6", + "webdriverio": "4.9.11", + "webpack": "^1.13.2", + "webpack-dev-server": "^1.14.1", + "webpack-html-plugin": "^0.1.1" }, - "bundleId": "org.reactjs.native.example.noder" + "jest": { + "preset": "react-native" + }, + "devEngines": { + "node": ">= 8.9.1", + "npm": ">= 5.x" + }, + "bundleId": "org.reactjs.native.example.noder", + "standard": { + "ignore": [], + "globals": [ + "__DEV__" + ], + "parser": "babel-eslint", + "plugins": [ + "flowtype", + "react" + ] + } } diff --git a/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 1.jpg b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 1.jpg new file mode 100644 index 00000000..c0e8129c Binary files /dev/null and b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 1.jpg differ diff --git a/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 2.jpg b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 2.jpg new file mode 100644 index 00000000..e7dbe4e2 Binary files /dev/null and b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 2.jpg differ diff --git a/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 3.jpg b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 3.jpg new file mode 100644 index 00000000..342855a4 Binary files /dev/null and b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 3.jpg differ diff --git a/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 4.jpg b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 4.jpg new file mode 100644 index 00000000..f52b63fd Binary files /dev/null and b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 4.jpg differ diff --git a/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 5.jpg b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 5.jpg new file mode 100644 index 00000000..c79b40f1 Binary files /dev/null and b/source/Screenshot_1.0_iOS/5.5-inch (iPhone 6+) - Screenshot 5.jpg differ diff --git a/source/logo/IOS/Brand Assets.png b/source/logo/IOS/Brand Assets.png new file mode 100644 index 00000000..d8eeb944 Binary files /dev/null and b/source/logo/IOS/Brand Assets.png differ diff --git a/source/logo/IOS/Default.png b/source/logo/IOS/Default.png new file mode 100644 index 00000000..9e1c11fa Binary files /dev/null and b/source/logo/IOS/Default.png differ diff --git a/source/logo/IOS/launchScreen.psd b/source/logo/IOS/launchScreen.psd new file mode 100644 index 00000000..ce5f9351 Binary files /dev/null and b/source/logo/IOS/launchScreen.psd differ diff --git a/Source/logo/IOS/noder-Icon-300px.png b/source/logo/IOS/noder-Icon-300px.png similarity index 100% rename from Source/logo/IOS/noder-Icon-300px.png rename to source/logo/IOS/noder-Icon-300px.png diff --git a/source/logo/IOS/noder-Icon-450px.png b/source/logo/IOS/noder-Icon-450px.png new file mode 100644 index 00000000..989c3d2f Binary files /dev/null and b/source/logo/IOS/noder-Icon-450px.png differ diff --git a/source/logo/IOS/noder-Icon.png b/source/logo/IOS/noder-Icon.png new file mode 100644 index 00000000..f66c3eaa Binary files /dev/null and b/source/logo/IOS/noder-Icon.png differ diff --git a/Source/logo/IOS/noder-Icon.psd b/source/logo/IOS/noder-Icon.psd similarity index 79% rename from Source/logo/IOS/noder-Icon.psd rename to source/logo/IOS/noder-Icon.psd index 19ca961a..5c30a6fc 100644 Binary files a/Source/logo/IOS/noder-Icon.psd and b/source/logo/IOS/noder-Icon.psd differ diff --git a/source/noder_icon/android/icon-yingyongbao.png b/source/noder_icon/android/icon-yingyongbao.png new file mode 100644 index 00000000..ec06ef84 Binary files /dev/null and b/source/noder_icon/android/icon-yingyongbao.png differ diff --git a/source/noder_icon/android/mipmap-hdpi/ic_launcher.png b/source/noder_icon/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..f948e794 Binary files /dev/null and b/source/noder_icon/android/mipmap-hdpi/ic_launcher.png differ diff --git a/source/noder_icon/android/mipmap-ldpi/ic_launcher.png b/source/noder_icon/android/mipmap-ldpi/ic_launcher.png new file mode 100644 index 00000000..a53c8266 Binary files /dev/null and b/source/noder_icon/android/mipmap-ldpi/ic_launcher.png differ diff --git a/source/noder_icon/android/mipmap-mdpi/ic_launcher.png b/source/noder_icon/android/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..8f1eaf4a Binary files /dev/null and b/source/noder_icon/android/mipmap-mdpi/ic_launcher.png differ diff --git a/source/noder_icon/android/mipmap-xhdpi/ic_launcher.png b/source/noder_icon/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..593d85f2 Binary files /dev/null and b/source/noder_icon/android/mipmap-xhdpi/ic_launcher.png differ diff --git a/source/noder_icon/android/mipmap-xxhdpi/ic_launcher.png b/source/noder_icon/android/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..53852d46 Binary files /dev/null and b/source/noder_icon/android/mipmap-xxhdpi/ic_launcher.png differ diff --git a/source/noder_icon/android/mipmap-xxxhdpi/ic_launcher.png b/source/noder_icon/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..eae25d24 Binary files /dev/null and b/source/noder_icon/android/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/source/noder_icon/android/playstore-icon.png b/source/noder_icon/android/playstore-icon.png new file mode 100644 index 00000000..ec0ea23f Binary files /dev/null and b/source/noder_icon/android/playstore-icon.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Contents.json b/source/noder_icon/ios/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..8d83298a --- /dev/null +++ b/source/noder_icon/ios/AppIcon.appiconset/Contents.json @@ -0,0 +1,86 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x", + "filename" : "Icon-Small@2x.png" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x", + "filename" : "Icon-Small@3x.png" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x", + "filename" : "Icon-40@2x.png" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x", + "filename" : "Icon-40@3x.png" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x", + "filename" : "Icon-60@2x.png" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x", + "filename" : "Icon-60@3x.png" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x", + "filename" : "Icon-Small.png" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x", + "filename" : "Icon-Small@2x.png" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x", + "filename" : "Icon-40.png" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x", + "filename" : "Icon-40@2x.png" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x", + "filename" : "Icon-76.png" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x", + "filename" : "Icon-76@2x.png" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x", + "filename" : "Icon-83.5@2x.png" + } + ], + "info" : { + "version" : 1, + "author" : "makeappicon" + } +} \ No newline at end of file diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-40.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-40.png new file mode 100644 index 00000000..1ff55fa8 Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-40.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-40@2x.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-40@2x.png new file mode 100644 index 00000000..fbb55c17 Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-40@2x.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-40@3x.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-40@3x.png new file mode 100644 index 00000000..90c1fa03 Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-40@3x.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-60@2x.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-60@2x.png new file mode 100644 index 00000000..90c1fa03 Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-60@2x.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-60@3x.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-60@3x.png new file mode 100644 index 00000000..e8d047b5 Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-60@3x.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-76.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-76.png new file mode 100644 index 00000000..339fc665 Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-76.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-76@2x.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-76@2x.png new file mode 100644 index 00000000..4a693895 Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-76@2x.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-83.5@2x.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-83.5@2x.png new file mode 100644 index 00000000..1727247d Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-83.5@2x.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-Small.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-Small.png new file mode 100644 index 00000000..0e199e4a Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-Small.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-Small@2x.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-Small@2x.png new file mode 100644 index 00000000..66c5d49a Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-Small@2x.png differ diff --git a/source/noder_icon/ios/AppIcon.appiconset/Icon-Small@3x.png b/source/noder_icon/ios/AppIcon.appiconset/Icon-Small@3x.png new file mode 100644 index 00000000..86cd7293 Binary files /dev/null and b/source/noder_icon/ios/AppIcon.appiconset/Icon-Small@3x.png differ diff --git a/source/noder_icon/ios/Icon-60.png b/source/noder_icon/ios/Icon-60.png new file mode 100644 index 00000000..b3f4cec2 Binary files /dev/null and b/source/noder_icon/ios/Icon-60.png differ diff --git a/source/noder_icon/ios/Icon-72.png b/source/noder_icon/ios/Icon-72.png new file mode 100644 index 00000000..f948e794 Binary files /dev/null and b/source/noder_icon/ios/Icon-72.png differ diff --git a/source/noder_icon/ios/Icon-72@2x.png b/source/noder_icon/ios/Icon-72@2x.png new file mode 100644 index 00000000..53852d46 Binary files /dev/null and b/source/noder_icon/ios/Icon-72@2x.png differ diff --git a/source/noder_icon/ios/Icon-Small-50.png b/source/noder_icon/ios/Icon-Small-50.png new file mode 100644 index 00000000..18b4f887 Binary files /dev/null and b/source/noder_icon/ios/Icon-Small-50.png differ diff --git a/source/noder_icon/ios/Icon-Small-50@2x.png b/source/noder_icon/ios/Icon-Small-50@2x.png new file mode 100644 index 00000000..fc716c25 Binary files /dev/null and b/source/noder_icon/ios/Icon-Small-50@2x.png differ diff --git a/source/noder_icon/ios/Icon.png b/source/noder_icon/ios/Icon.png new file mode 100644 index 00000000..f63da742 Binary files /dev/null and b/source/noder_icon/ios/Icon.png differ diff --git a/source/noder_icon/ios/Icon@2x.png b/source/noder_icon/ios/Icon@2x.png new file mode 100644 index 00000000..e34d88c0 Binary files /dev/null and b/source/noder_icon/ios/Icon@2x.png differ diff --git a/source/noder_icon/ios/README.md b/source/noder_icon/ios/README.md new file mode 100644 index 00000000..6b3251ad --- /dev/null +++ b/source/noder_icon/ios/README.md @@ -0,0 +1,24 @@ +## iTunesArtwork & iTunesArtwork@2x (App Icon) file extension: + +PNG extension is prepended to these two files - + +While Apple suggested to omit the extension for these files, +the '.png' extension is actually required for iTunesConnect submission. + +This is done for you so you don't have to. + +However, for Ad_hoc or Enterprise distirbution, the extension should be removed +from the files before adding to XCode to avoid error. + +refs: https://developer.apple.com/library/ios/qa/qa1686/_index.html + +## iTunesArtwork & iTunesArtwork@2x (App Icon) transparency handling: + +As images with alpha channels or transparencies cannot be set as an application's icon on +iTunesConnect, all transparent pixels in your images will be converted into +solid blacks. + +To achieve the best result, you're advised to adjust the transparency settings +in your source files before converting them with makeAppIcon. + +refs: https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/AppIcons.html diff --git a/source/noder_icon/ios/iTunesArtwork.png b/source/noder_icon/ios/iTunesArtwork.png new file mode 100644 index 00000000..3af4cc60 Binary files /dev/null and b/source/noder_icon/ios/iTunesArtwork.png differ diff --git a/source/noder_icon/ios/iTunesArtwork@2x.png b/source/noder_icon/ios/iTunesArtwork@2x.png new file mode 100644 index 00000000..4632c5cf Binary files /dev/null and b/source/noder_icon/ios/iTunesArtwork@2x.png differ diff --git a/source/noder_icon/watchkit/AppIcon.appiconset/Contents.json b/source/noder_icon/watchkit/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..c48be84c --- /dev/null +++ b/source/noder_icon/watchkit/AppIcon.appiconset/Contents.json @@ -0,0 +1,70 @@ +{ + "images" : [ + { + "size" : "24x24", + "idiom" : "watch", + "scale" : "2x", + "filename" : "Icon-24@2x.png", + "role" : "notificationCenter", + "subtype" : "38mm" + }, + { + "size" : "27.5x27.5", + "idiom" : "watch", + "scale" : "2x", + "filename" : "Icon-27.5@2x.png", + "role" : "notificationCenter", + "subtype" : "42mm" + }, + { + "size" : "29x29", + "idiom" : "watch", + "filename" : "Icon-29@2x.png", + "role" : "companionSettings", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "watch", + "filename" : "Icon-29@3x.png", + "role" : "companionSettings", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "watch", + "scale" : "2x", + "filename" : "Icon-40@2x.png", + "role" : "appLauncher", + "subtype" : "38mm" + }, + { + "size" : "44x44", + "idiom" : "watch", + "scale" : "2x", + "filename" : "Icon-44@2x.png", + "role" : "longLook", + "subtype" : "42mm" + }, + { + "size" : "86x86", + "idiom" : "watch", + "scale" : "2x", + "filename" : "Icon-86@2x.png", + "role" : "quickLook", + "subtype" : "38mm" + }, + { + "size" : "98x98", + "idiom" : "watch", + "scale" : "2x", + "filename" : "Icon-98@2x.png", + "role" : "quickLook", + "subtype" : "42mm" + } + ], + "info" : { + "version" : 1, + "author" : "makeappicon" + } +} \ No newline at end of file diff --git a/source/noder_icon/watchkit/AppIcon.appiconset/Icon-24@2x.png b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-24@2x.png new file mode 100644 index 00000000..8f1eaf4a Binary files /dev/null and b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-24@2x.png differ diff --git a/source/noder_icon/watchkit/AppIcon.appiconset/Icon-27.5@2x.png b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-27.5@2x.png new file mode 100644 index 00000000..9f56a115 Binary files /dev/null and b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-27.5@2x.png differ diff --git a/source/noder_icon/watchkit/AppIcon.appiconset/Icon-29@2x.png b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-29@2x.png new file mode 100644 index 00000000..66c5d49a Binary files /dev/null and b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-29@2x.png differ diff --git a/source/noder_icon/watchkit/AppIcon.appiconset/Icon-29@3x.png b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-29@3x.png new file mode 100644 index 00000000..86cd7293 Binary files /dev/null and b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-29@3x.png differ diff --git a/source/noder_icon/watchkit/AppIcon.appiconset/Icon-40@2x.png b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-40@2x.png new file mode 100644 index 00000000..fbb55c17 Binary files /dev/null and b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-40@2x.png differ diff --git a/source/noder_icon/watchkit/AppIcon.appiconset/Icon-44@2x.png b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-44@2x.png new file mode 100644 index 00000000..b7a2ef25 Binary files /dev/null and b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-44@2x.png differ diff --git a/source/noder_icon/watchkit/AppIcon.appiconset/Icon-86@2x.png b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-86@2x.png new file mode 100644 index 00000000..06045f39 Binary files /dev/null and b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-86@2x.png differ diff --git a/source/noder_icon/watchkit/AppIcon.appiconset/Icon-98@2x.png b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-98@2x.png new file mode 100644 index 00000000..f91d0c3f Binary files /dev/null and b/source/noder_icon/watchkit/AppIcon.appiconset/Icon-98@2x.png differ diff --git a/src/actions/index.js b/src/actions/index.js new file mode 100644 index 00000000..6a5a4da9 --- /dev/null +++ b/src/actions/index.js @@ -0,0 +1,11 @@ +import * as user from './user' +import * as utils from './utils' +import * as message from './message' +import * as topic from './topic' + +export default { + ...user, + ...utils, + ...message, + ...topic +} diff --git a/src/actions/message.js b/src/actions/message.js new file mode 100644 index 00000000..3fc81228 --- /dev/null +++ b/src/actions/message.js @@ -0,0 +1,25 @@ +import {createAction} from 'redux-actions' +import * as types from '../constants/ActionTypes' +import * as messageService from '../services/messageService' + +export const getUnreadMessageCount = createAction(types.GET_UNREAD_MESSAGE_COUNT, async() => { + return await messageService.getUnreadMessageCount() +}) + +export const markAsRead = createAction(types.MARK_AS_READ, async() => { + return await messageService.markAsRead() +}, function (resolved, rejected) { + return { + resolved, + rejected, + sync: 'message' + } +}) + +export const getMessageList = createAction(types.GET_MESSAGES_LIST, async() => { + return await messageService.getMessages() +}, () => { + return { + sync: 'message' + } +}) diff --git a/src/actions/topic.js b/src/actions/topic.js new file mode 100644 index 00000000..fabba35f --- /dev/null +++ b/src/actions/topic.js @@ -0,0 +1,64 @@ +import {createAction} from 'redux-actions' +import * as markdown from 'markdown' +import * as types from '../constants/ActionTypes' +import * as topicService from '../services/topicService' + +export const getTopicsByTab = createAction(types.GET_TOPICS_BY_TAB, async(tab, params) => { + return await topicService.getTopicsByTab(tab, params) +}, (tab) => { + return { + tab + } +}) + +export const updateTopicsByTab = createAction(types.UPDATE_TOPICS_BY_TAB, async(tab) => { + return await topicService.getTopicsByTab(tab, { + page: 1 + }) +}, (tab) => { + return { + tab, + sync: 'topic' + } +}) + +export const getTopicById = createAction(types.GET_TOPIC_BY_ID, topicService.getTopicById, (id) => { + return { + id, + sync: 'topic' + } +}) + +export const removeTopicCacheById = createAction(types.REMOVE_TOPIC_CACHE_BY_ID, (id) => { + return { + id + } +}) + +export const replyTopicById = createAction(types.REPLY_TOPIC_BY_ID, topicService.reply, ({topicId, content, replyId, user}, resolved, rejected) => { + return { + id: topicId, + content: markdown.parse(content), + replyId, + resolved, + rejected, + user + } +}) + +export const upReply = createAction(types.UP_REPLY, topicService.upReply, ({topicId, replyId, userId, resolved, rejected}) => { + return { + id: topicId, + replyId, + userId, + resolved, + rejected + } +}) + +export const publish = createAction(types.PUBLISH, topicService.publish, ({resolved, rejected}) => { + return { + resolved, + rejected + } +}) diff --git a/src/actions/user.js b/src/actions/user.js new file mode 100644 index 00000000..409f2df6 --- /dev/null +++ b/src/actions/user.js @@ -0,0 +1,74 @@ +import {createAction} from 'redux-actions' +import * as types from '../constants/ActionTypes' +import * as userService from '../services/userService' +import * as tokenService from '../services/token' +import * as storageService from '../services/storage' + +export const checkToken = createAction(types.CHECK_TOKEN, async(token) => { + const userLoginInfo = await userService.checkToken(token) + const user = await userService + .getUserInfo(userLoginInfo.loginname) + .then((data) => { + return { + secret: userLoginInfo, + publicInfo: data + } +}) + tokenService.setToken(token) + return user +}, (token, resolved) => { + return { + resolved: resolved, + sync: 'user' + } +}) + +export const updateClientUserInfo = createAction(types.UPDATE_CLIENT_USER_INFO, async(user) => { + return await userService.getUserInfo(user.secret.loginname) + .then(userInfo => { + if (userInfo) { + return userInfo + } + throw 'getUserInfoError' +}) +}, () => { + return { + sync: 'user' + } +}) + +export const getUserInfo = createAction(types.GET_USER_INFO, async(loginName) => { + return await userService.getUserInfo(loginName) + .then(userInfo => { + if (userInfo) { + return userInfo + } + throw 'getUserInfoError' +}) +}, (userName) => { + return { + userName, + sync: 'user' + } +}) + +export const logout = function () { + return { + type: types.LOGOUT, + meta: { + sync: 'user' + } + } +} + +export const clear = function () { + try { + storageService.removeItem('topic') + storageService.removeItem('message') + } catch (err) { + console.warn(err) + } + return { + type: types.CLEAR + } +} diff --git a/src/actions/utils.js b/src/actions/utils.js new file mode 100644 index 00000000..d42c5dbe --- /dev/null +++ b/src/actions/utils.js @@ -0,0 +1,35 @@ +import {createAction} from 'redux-actions' +import * as types from '../constants/ActionTypes' +import * as storageService from '../services/storage' + +const syncReducer = ['user', 'message', 'topic'] + +export const toast = createAction(types.TOAST, (text, timeout) => { + return { + text, + timeout, + id: new Date().getTime() + } +}) + +export const getReducerFromAsyncStorage = createAction(types.GET_REDUCER_FROM_ASYNC_STORAGE, async() => { + return storageService.multiGet(syncReducer) + .then(arr => { + let ob = {} + arr.forEach(item => { + ob[item[0]] = item[1] + }) + if (ob.user && ob.user.secret) { + global.token = ob.user.secret.token + } + return ob +}) + .catch(err => { + console.warn(err) +}) +}, (resolved, rejected) => { + return { + resolved, + rejected + } +}) diff --git a/src/components/CommentHtml.js b/src/components/CommentHtml.js new file mode 100644 index 00000000..8cb0ae3e --- /dev/null +++ b/src/components/CommentHtml.js @@ -0,0 +1,176 @@ +import React, {Component} from 'react' +import {StyleSheet, Image, Dimensions} from 'react-native' +import Html from './base/Html' + +const {width} = Dimensions.get('window') + +class CommentHtml extends Component { + constructor (props) { + super(props) + if (this.props.style) { + this.styles = Object.assign({}, styles, this.props.style) + } + } + + render () { + return ( + + ) + } +} + +const fontSize = 14 +const titleMargin = 5 + +const styles = StyleSheet.create({ + p: { + // lineHeight: fontSize * 1.4, + fontSize: fontSize, + color: 'rgba(0,0,0,0.8)' + }, + pwrapper: { + marginTop: 5, + marginBottom: 5 + }, + + a: { + color: '#3498DB', + fontSize: fontSize, + paddingLeft: 4, + paddingRight: 4, + marginRight: 10, + marginLeft: 10 + }, + h1: { + fontSize: fontSize * 1.6, + fontWeight: 'bold', + color: 'rgba(0,0,0,0.8)' + }, + h1wrapper: { + marginTop: titleMargin, + marginBottom: titleMargin + }, + h2: { + fontSize: fontSize * 1.5, + fontWeight: 'bold', + color: 'rgba(0,0,0,0.85)' + }, + h2wrapper: { + marginBottom: titleMargin, + marginTop: titleMargin + }, + h3: { + fontWeight: 'bold', + fontSize: fontSize * 1.4, + color: 'rgba(0,0,0,0.8)' + }, + h3wrapper: { + marginBottom: titleMargin - 2, + marginTop: titleMargin - 2 + }, + h4: { + fontSize: fontSize * 1.3, + color: 'rgba(0,0,0,0.7)', + fontWeight: 'bold' + }, + h4wrapper: { + marginBottom: titleMargin - 2, + marginTop: titleMargin - 2 + }, + h5: { + fontSize: fontSize * 1.2, + color: 'rgba(0,0,0,0.7)', + fontWeight: 'bold' + }, + h5wrapper: { + marginBottom: titleMargin - 3, + marginTop: titleMargin - 3 + }, + h6: { + fontSize: fontSize * 1.1, + color: 'rgba(0,0,0,0.7)', + fontWeight: 'bold' + }, + h6wrapper: { + marginBottom: titleMargin - 3, + marginTop: titleMargin - 3 + }, + li: { + fontSize: fontSize * 0.9, + color: 'rgba(0,0,0,0.7)' + }, + liwrapper: { + paddingLeft: 20, + marginBottom: 10 + }, + strong: { + fontWeight: 'bold' + }, + em: { + fontStyle: 'italic' + }, + codeScrollView: { + backgroundColor: '#333', + flexDirection: 'column', + marginBottom: 15 + }, + codeRow: { + flex: 1, + flexDirection: 'row', + height: 25, + alignItems: 'center' + }, + codeFirstRow: { + paddingTop: 20, + height: 25 + 20 + }, + codeLastRow: { + paddingBottom: 20, + height: 25 + 20 + }, + codeFirstAndLastRow: { + paddingBottom: 20, + height: 25 + 40, + paddingTop: 20 + }, + lineNum: { + width: 55, + color: 'rgba(255,255,255,0.5)' + }, + lineNumWrapper: { + width: 55, + height: 25, + backgroundColor: 'rgba(0,0,0,0.1)', + flexDirection: 'row', + alignItems: 'center', + paddingLeft: 20 + }, + codeWrapper: { + flexDirection: 'column' + }, + codeLineWrapper: { + height: 25, + flexDirection: 'row', + alignItems: 'center', + paddingLeft: 20, + paddingRight: 20 + }, + blockquotewrapper: { + paddingLeft: 20, + borderLeftColor: '#3498DB', + borderLeftWidth: 3 + }, + img: { + width: width - 80 - 20, + height: width - 80 - 20, + resizeMode: Image.resizeMode.contain, + margin: 10 + } +}) + +export default CommentHtml diff --git a/src/components/CommentList.js b/src/components/CommentList.js new file mode 100644 index 00000000..c1d321cd --- /dev/null +++ b/src/components/CommentList.js @@ -0,0 +1,293 @@ +import React, {Component} from 'react' +import {Dimensions, View, Text, ListView, StyleSheet, Image, TouchableOpacity, RefreshControl} from 'react-native' +import PropTypes from 'prop-types' +import PureRenderMixin from 'react-addons-pure-render-mixin' +import Icon from 'react-native-vector-icons/Ionicons' +import moment from 'moment' +import CommentHtml from './CommentHtml' +import CommentUp from './CommentUp' +import * as Constants from '../constants' + +import {parseImgUrl} from '../utils' + +const {width} = Dimensions.get('window') + +class CommentList extends Component { + static propTypes = { + data: PropTypes.array, + focusedReply: PropTypes.string, + router: PropTypes.object, + user: PropTypes.object, + onReplyPress: PropTypes.func, + onAuthorNamePress: PropTypes.func, + onPullRefresh: PropTypes.func, + pending: PropTypes.bool + }; + + static defaultProps = { + onReplyPress: () => null, + onAuthorNamePress: () => null, + pending: false + }; + + constructor (props) { + super(props) + const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) + this.state = { + ds: ds.cloneWithRows(props.data.concat([]).reverse()) + } + this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this) + } + + componentWillReceiveProps (nextProps) { + if (nextProps.data !== this.props.data) { + this.setState({ + ds: this.state.ds.cloneWithRows(nextProps.data.concat([]).reverse()) + }) + } + } + + componentDidMount () { + setTimeout(() => this._scrollToReply(), 0) + } + + scrollToTop () { + this._listView.scrollTo({ + x: 0, + y: 0 + }) + } + + _scrollToReply () { + const {focusedReply} = this.props + if (focusedReply) { + let row = this[focusedReply] + if (row && row.measure) { + row.measure((x, y, width, height, pageX, pageY) => { + this._listView.setNativeProps({ + contentOffset: { + x: 0, + y: y + } + }) + }) + + row.setNativeProps({ + styles: { + backgroundColor: 'red' + } + }) + } + } + } + + _renderFooter (comment, authorName) { + if (this.props.user) { + return ( + + + this.props.onReplyPress(comment.id, authorName)}> + + + + ) + } + } + + _renderRow (comment, sectionID, rowID, highlightRow) { + const authorName = comment.author.loginname + const date = moment(comment.create_at).startOf('minute').fromNow() + const commentNum = this.props.data.length - parseInt(rowID) + let focusStyle = {} + if (this.props.focusedReply) { + let replyId = this.props.focusedReply + if (replyId === comment.id) { + focusStyle = { + backgroundColor: 'rgba(0,2,125,0.07)' + } + } + } + + return ( + this[comment.id] = view} + key={comment.id} + style={[styles.commentWrapper, focusStyle]}> + + { + this.props.router.toUser({ + userName: authorName + }) + }}> + + + + + {commentNum} 楼 + + + + + + + this.props.onAuthorNamePress(authorName)}> + + {authorName} + + + + + + + {date} + + + + + + + { this._renderFooter(comment, authorName) } + + + ) + } + + render () { + return ( + this._listView = view} + style={{backgroundColor: 'rgba(255,255,255,1)'}} + showsVerticalScrollIndicator + initialListSize={10} + pagingEnabled={false} + removeClippedSubviews + dataSource={this.state.ds} + renderRow={this._renderRow.bind(this)} + refreshControl={ + + } + /> + ) + } +} + +const authorImgSize = 35 +const commentContentOffset = 15 * 2 + authorImgSize +const commentIconSize = 12 + +const commentHtmlStyle = StyleSheet.create({ + img: { + width: width - commentContentOffset - 15, + height: width - commentContentOffset - 15, + resizeMode: Image.resizeMode.contain + } +}) + +const styles = StyleSheet.create({ + commentWrapper: { + borderBottomColor: 'rgba(0,0,0,0.02)', + borderBottomWidth: 1, + padding: 15, + flexDirection: 'row' + }, + + commentHeader: { + flexDirection: 'row', + alignItems: 'center' + }, + + date: { + flexDirection: 'row', + flex: 1 + }, + + author: { + flex: 1 + }, + authorText: { + color: 'rgba(0,0,0,0.3)', + fontSize: 12 + }, + + dateIcon: { + height: commentIconSize, + width: commentIconSize, + flexDirection: 'row' + }, + + dateText: { + color: 'rgba(0,0,0,0.3)', + fontSize: 12, + textAlign: 'right', + flex: 1 + }, + + commentIcon: { + height: commentIconSize, + width: commentIconSize + }, + + imageWrapper: { + width: authorImgSize + 15 + }, + + commentNumText: { + marginTop: 15, + fontSize: 12, + color: 'rgba(0,0,0,0.3)', + textAlign: 'center', + width: authorImgSize + + }, + + commentContentWrapper: { + width: width - commentContentOffset - 15 + }, + + authorImg: { + height: authorImgSize, + width: authorImgSize, + borderRadius: authorImgSize / 2 + + }, + commentFooter: { + flexDirection: 'row', + flex: 1, + justifyContent: 'space-between', + alignItems: 'flex-end' + }, + replyIcon: { + width: 15, + flex: 1 + }, + up: { + width: 40, + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center' + } +}) + +export default CommentList diff --git a/src/components/CommentOverlay.js b/src/components/CommentOverlay.js new file mode 100644 index 00000000..f6a3f1b2 --- /dev/null +++ b/src/components/CommentOverlay.js @@ -0,0 +1,73 @@ +import React, {Component} from 'react' +import {View, StyleSheet, Text} from 'react-native' +import PropTypes from 'prop-types' +import Icon from 'react-native-vector-icons/Ionicons' +import OverlayButton from './base/OverlayButton' + +const overlaySize = 45 +const iconSize = 12 + +class CommentOverlay extends Component { + static propTypes = { + onPress: PropTypes.func, + replyCount: PropTypes.number + }; + + static defaultProps = { + replyCount: 0 + }; + + _renderCommentReplyCount (count) { + if (count > 999) { + return '1k+' + } + return count + } + + render () { + return ( + + + + + {this._renderCommentReplyCount(this.props.replyCount)} + + + + ) + } +} + +const styles = StyleSheet.create({ + position: { + right: 20, + bottom: 20 + }, + commentText: { + textAlign: 'center', + color: 'white', + fontSize: 12, + paddingLeft: 4 + }, + content: { + height: overlaySize, + width: overlaySize, + borderRadius: overlaySize / 2, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center' + }, + commentIcon: { + height: iconSize, + width: iconSize + } +}) + +export default CommentOverlay diff --git a/src/components/CommentUp.js b/src/components/CommentUp.js new file mode 100644 index 00000000..a27a6f88 --- /dev/null +++ b/src/components/CommentUp.js @@ -0,0 +1,103 @@ +import React, {Component} from 'react' +import {View, TouchableOpacity, StyleSheet, Text} from 'react-native' +import PropTypes from 'prop-types' +import PureRenderMixin from 'react-addons-pure-render-mixin' +import Icon from 'react-native-vector-icons/Ionicons' +import Spinner from './base/Spinner' + +class CommentUp extends Component { + static propTypes = { + pending: PropTypes.bool, + disabled: PropTypes.bool, + replyId: PropTypes.string, + ups: PropTypes.array, + userId: PropTypes.string + }; + + static defaultProps = { + pending: false, + disabled: false, + ups: [] + }; + + constructor (props) { + super(props) + this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this) + } + + _onUpPress () { + const {disabled, pending, upReply, replyId, userId, topicId} = this.props + if (disabled) { + return window.alert('不能给自己点赞哦!') + } + if (pending) { return } + + upReply({ + replyId, + userId, + topicId + }) + } + + _isUped () { + return this.props.ups.some(item => { + return item === this.props.userId + }) + } + + _renderUpIcon () { + if (this.props.pending) { + return ( + + ) + } + return ( + + ) + } + + render () { + const {ups} = this.props + let count = ups.length + return ( + + + + {this._renderUpIcon()} + + {count === 0 ? null : ( + + {count} + + )} + + + ) + } +} + +const styles = StyleSheet.create({ + textWrapper: { + paddingLeft: 7 + }, + text: { + fontSize: 12, + color: 'rgba(0,0,0,0.2)', + height: 12 + }, + loading: { + height: 12, + width: 16 + } +}) + +export default CommentUp diff --git a/src/components/MarkAsReadOverlay.js b/src/components/MarkAsReadOverlay.js new file mode 100644 index 00000000..840ae6ee --- /dev/null +++ b/src/components/MarkAsReadOverlay.js @@ -0,0 +1,70 @@ +import React, {Component} from 'react' +import {View, StyleSheet, Text} from 'react-native' +import PropTypes from 'prop-types' +import OverlayButton from './base/OverlayButton' +import Spinner from './base/Spinner' + +const overlaySize = 45 + +class MarkAsReadOverlay extends Component { + static propTypes = { + hasNotRead: PropTypes.array, + markAsRead: PropTypes.func, + pending: PropTypes.bool + }; + + _onPress () { + if (this.props.hasNotRead.length === 0) { + window.alert('暂无未读消息!') + } else { + this.props.markAsRead() + } + } + + _renderContent () { + if (this.props.pending) { + return ( + + ) + } + return ( + + 已读 + + ) + } + + render () { + return ( + + + {this._renderContent()} + + + ) + } +} + +const styles = StyleSheet.create({ + position: { + right: 20, + bottom: 20 + }, + text: { + textAlign: 'center', + color: 'white', + fontSize: 12 + }, + content: { + height: overlaySize, + width: overlaySize, + borderRadius: overlaySize / 2, + flexDirection: 'column', + justifyContent: 'center' + } +}) + +export default MarkAsReadOverlay diff --git a/src/components/MessageList.js b/src/components/MessageList.js new file mode 100644 index 00000000..987a58b2 --- /dev/null +++ b/src/components/MessageList.js @@ -0,0 +1,226 @@ +import React, {Component} from 'react' +import {View, StyleSheet, Text, Image, ListView, TouchableHighlight, Dimensions, RefreshControl} from 'react-native' +import PropTypes from 'prop-types' +import moment from 'moment' +import {parseImgUrl} from '../utils' +import * as Constants from '../constants' + +const {height, width} = Dimensions.get('window') + +class MessageList extends Component { + static propTypes = { + data: PropTypes.array, + pending: PropTypes.bool, + getMessageList: PropTypes.func, + didFocus: PropTypes.bool + }; + + static defaultProps = { + pending: false, + didFocus: false, + data: [] + }; + + constructor (props) { + super(props) + this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) + this.state = { + ds: this.ds.cloneWithRows(props.data) + } + } + + componentWillReceiveProps (nextProps) { + if (nextProps.data !== this.props.data) { + this.setState({ + ds: this.state.ds.cloneWithRows(nextProps.data) + }) + } + } + + _onRowPress (message) { + this.props.router.toComment({ + topic: message.topic, + from: 'message', + reply: message.reply, + id: message.topic.id + }) + } + + _renderRowFooter (message) { + const date = moment(message.reply.create_at).startOf('minute').fromNow() + + return ( + + + + {message.author.loginname} + + + {message.type == 'reply' ? ' 回复' : ' @'} + + + + + {date} + + + ) + } + + _renderRow (message) { + var topic = message.topic + + return ( + { this._onRowPress(message) }} + underlayColor='#3498DB' + key={message.id}> + + + + + + {topic.title} + + + + {this._renderRowFooter(message)} + + + + + ) + } + + _renderHeader () { + const {data, didFocus} = this.props + if (!data.length && didFocus) { + return ( + + + 空空哒 + + + ) + } + return null + } + + render () { + const {pending, didFocus, getMessageList} = this.props + return ( + { getMessageList() }} + {...Constants.refreshControl} + /> + } + /> + ) + } +} + +const styles = StyleSheet.create({ + 'row': { + 'height': 90, + 'flexDirection': 'row', + 'borderBottomColor': 'rgba(0, 0, 0, 0.02)', + 'borderBottomWidth': 1, + 'paddingTop': 25, + 'paddingRight': 20, + 'paddingBottom': 25, + 'paddingLeft': 20, + alignItems: 'center' + }, + 'img': { + 'height': 40, + 'width': 40, + 'borderRadius': 20, + marginRight: 20 + }, + 'topic': { + flexDirection: 'column', + width: width - 20 * 3 - 40 + }, + 'title': { + 'fontSize': 15 + }, + 'topicFooter': { + 'marginTop': 10, + 'flexDirection': 'row', + width: width - (20 + 90) + }, + 'topicFooter text': { + 'fontSize': 11, + 'color': 'rgba(0, 0, 0, 0.4)' + }, + 'topicFooter date': { + 'position': 'absolute', + 'right': 0, + 'top': 0 + }, + 'topicFooter count': { + 'marginRight': 15 + }, + 'topicFooter top': { + 'fontSize': 11, + 'marginTop': 1, + 'marginRight': 0, + 'marginBottom': 0, + 'marginLeft': 10, + 'color': '#E74C3C' + }, + 'topicFooter good': { + 'fontSize': 11, + 'marginTop': 1, + 'marginRight': 0, + 'marginBottom': 0, + 'marginLeft': 10, + 'color': '#2ECC71' + }, + 'topicFooter tab': { + 'fontSize': 11, + 'marginTop': 1, + 'marginRight': 0, + 'marginBottom': 0, + 'marginLeft': 10 + }, + 'loading': { + 'marginTop': 250 + }, + rowFooterText: { + fontSize: 13, + color: 'rgba(0,0,0,0.7)' + }, + atText: { + color: '#E74C3C' + }, + replyText: { + color: '#2980B9' + }, + emptyMessage: { + marginTop: 80, + flex: 1 + }, + emptyMessageText: { + textAlign: 'center', + color: '#3498DB', + fontSize: 24 + } + +}) + +export default MessageList diff --git a/src/components/MessageOverlay.js b/src/components/MessageOverlay.js new file mode 100644 index 00000000..a0425c9e --- /dev/null +++ b/src/components/MessageOverlay.js @@ -0,0 +1,103 @@ +import React, {Component} from 'react' +import {View, Text, StyleSheet, Dimensions} from 'react-native' +import PropTypes from 'prop-types' +import OverlayButton from './base/OverlayButton' +import Icon from 'react-native-vector-icons/Ionicons' + +class MessageOverlay extends Component { + static propTypes = { + count: PropTypes.number, + toMessage: PropTypes.func + }; + + static defaultProps = { + count: 0, + toMessage: () => null + }; + + _renderMessageCount () { + const count = this.props.count + + if (count > 0) { + return ( + + + {count > 999 ? '1k+' : count} + + + ) + } + + return null + } + + render () { + if (this.props.user) { + return ( + this.props.toMessage()}> + + + + + {this._renderMessageCount()} + + ) + } + return null + } +} + +const overlaySize = 45 +const countBoxSize = 20 +const countTextSize = 10 + +const styles = StyleSheet.create({ + iconWrapper: { + height: overlaySize, + width: overlaySize, + borderRadius: overlaySize / 2, + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center' + }, + icon: { + flex: 1, + textAlign: 'center' + }, + countWrapper: { + height: countBoxSize, + width: countBoxSize, + borderRadius: countBoxSize / 2, + backgroundColor: 'red', + position: 'absolute', + right: -5, + top: -5 + }, + countText: { + color: 'rgba(255,255,255,0.8)', + fontSize: countTextSize, + lineHeight: countBoxSize - countTextSize / 2, + textAlign: 'center', + height: countBoxSize, + width: countBoxSize, + borderRadius: countBoxSize / 2, + backgroundColor: 'transparent' + }, + position: { + right: 20, + bottom: 20 + }, + container: { + backgroundColor: 'blue', + borderRadius: overlaySize / 2 + } +}) + +export default MessageOverlay diff --git a/src/components/Nav.js b/src/components/Nav.js new file mode 100644 index 00000000..ebfed161 --- /dev/null +++ b/src/components/Nav.js @@ -0,0 +1,93 @@ +import React, {Component} from 'react' +import {View, Text, StyleSheet, TouchableOpacity, Dimensions, Platform} from 'react-native' + +const {height, width} = Dimensions.get('window') + +class Nav extends Component { + _renderNavContent () { + let navs = this.props.navs || {} + + return ['Left', 'Center', 'Right'].map((position) => { + let nav = navs[position] + if (nav) { + return ( + + + + {nav.text} + + + + ) + } + return ( + + + + ) + }) + } + + render () { + return ( + this.nav = view} + style={styles.nav}> + + {this._renderNavContent()} + + + ) + } +} + +const navHeight = 55 +const statusBarHeight = Platform.OS === 'ios' ? 20 : 0 + +const styles = StyleSheet.create({ + nav: { + height: navHeight + statusBarHeight, + width: width, + borderBottomColor: 'rgba(0,0,0,0.03)', + backgroundColor: '#292829', + borderBottomWidth: 1, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + paddingTop: statusBarHeight, + paddingLeft: 15, + paddingRight: 15 + }, + navItem: { + color: 'rgba(255,255,255,0.7)', + fontSize: 16 + }, + textWrapper: { + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center' + }, + textWrapperRight: { + flex: 1, + alignItems: 'flex-end' + }, + textWrapperLeft: { + flex: 1, + alignItems: 'flex-start' + }, + textWrapperCenter: { + flex: 2 + }, + navLeft: {}, + navRight: {}, + navCenter: { + color: 'rgba(241,196,15,0.9)' + } +}) + +Nav.navHeight = navHeight + +export default Nav diff --git a/src/components/ScrollableTabs.js b/src/components/ScrollableTabs.js new file mode 100644 index 00000000..7223f568 --- /dev/null +++ b/src/components/ScrollableTabs.js @@ -0,0 +1,303 @@ +import React, {Component} from 'react' +import { + View, + Dimensions, + StyleSheet, + TouchableOpacity, + Text, + Platform, + ScrollView, + Animated, + ViewPagerAndroid +} from 'react-native' +import PropTypes from 'prop-types' +import PureRenderMixin from 'react-addons-pure-render-mixin' + +const {height, width} = Dimensions.get('window') + +class ScrollableTabs extends Component { + static propTypes = { + tabs: PropTypes.array, + tabNavItemWidth: PropTypes.number, + index: PropTypes.number, + onPageChanged: PropTypes.func, + onPageChangedAndAnimateEnd: PropTypes.func + }; + + static defaultProps = { + tabs: [], + tabNavItemWidth: 60 + }; + + constructor (props) { + super(props) + const {tabNavItemWidth, tabs} = props + this.space = (width - tabNavItemWidth * 3) / 2 + this.navContentWidth = (tabs.length + 2) * tabNavItemWidth + this.space * (tabs.length + 1) + this.index = props.index || Math.floor(tabs.length / 2) + const offset = this.index * (this.space + tabNavItemWidth) + this.state = { + x: new Animated.Value(-offset) + } + this.state.x.addListener((e) => { + if (e.value % (this.space + tabNavItemWidth) === 0) { + let index = Math.abs(e.value / (this.space + tabNavItemWidth)) + this._scrolling = false + typeof this.props.onPageChangedAndAnimateEnd === 'function' && this.props.onPageChangedAndAnimateEnd(index, this.isScrolling()) + } + }) + this._navs = {} + this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this) + } + + isScrolling () { + return () => this._scrolling + } + + _updateNavScale (offset) { + const space = this.space + this.props.tabNavItemWidth + this.props.tabs.forEach((item, index) => { + let min = (index - 1) * space + let max = (index + 1) * space + let center = index * space + + let scale = 0 + if (offset > min && offset < center) { + scale = (offset - min) / space + } + if (offset > center && offset < max) { + scale = (max - offset) / space + } + + if (offset === center) { + scale = 1 + } + this._navs[index].setNativeProps({ + style: this._getActiveNavItemStyle(scale) + }) + } + ) + } + + _animateScroll (x) { + const {tabNavItemWidth} = this.props + const navContentOffset = (this.space + tabNavItemWidth) / width * x + Animated.event( + [{ + offset: this.state.x + }] + )({ + offset: -navContentOffset +}) + this._updateNavScale(navContentOffset) + } + + _onScroll (e) { + const {contentSize = {}} = e.nativeEvent + + // 一下一行代码为解决一个奇葩的bug + if (contentSize.height === 0 && contentSize.width === 0) { return } + + const {x} = e.nativeEvent.contentOffset + this._scrolling = true + this._animateScroll(x) + } + + _onMomentumScrollBegin (e) { + this._scrolling = true + const offsetX = e.nativeEvent.contentOffset.x + this._animateScroll(offsetX) + } + + _onMomentumScrollEnd (e) { + this._scrolling = true + const offsetX = e.nativeEvent.contentOffset.x + const page = parseInt(offsetX / width, 10) + this._animateScroll(offsetX) + if (page !== this.index) { + typeof this.props.onPageChanged === 'function' && this.props.onPageChanged(page, this.isScrolling()) + } + this.index = page + } + + _onPageSelected (e) { + const {position} = e.nativeEvent + this.index = position + if (position === undefined) { + return + } + typeof this.props.onPageChanged === 'function' && this.props.onPageChanged(position, this.isScrolling()) + } + + _onAndroidPageScroll (e) { + const {offset, position} = e.nativeEvent + let x = (position + offset) * width + this._animateScroll(x) + } + + _onNavItemPress (index) { + if (Platform.OS === 'ios') { + this.scrollView.scrollTo({ + x: width * index, + y: 0, + animated: true + }) + } else { + this.viewPager.setPage(index) + } + } + + _getActiveNavItemStyle (opacity) { + return { + borderTopColor: 'rgba(241,196,15,' + opacity + ')' + } + } + + _renderNavs () { + return this.props.tabs.map((item, index) => { + let activeStyle = this._getActiveNavItemStyle(0) + if (index === this.index) { + activeStyle = this._getActiveNavItemStyle(1) + } + + return ( + + this._navs[index] = view} key={index} + style={[styles.navItem, { width: this.props.tabNavItemWidth }, activeStyle]}> + + + { item } + + + + + ) + }) + } + + _renderChildren () { + return this.props.children.map((pageContent, index) => { + return ( + + { pageContent } + + ) + }) + } + + _renderPageScroll () { + const initContentOffset = { + x: this.index * width, + y: 0 + } + + if (Platform.OS === 'ios') { + return ( + this.scrollView = view} + contentOffset={initContentOffset} + alwaysBounceVertical={false} + automaticallyAdjustContentInsets={false} + showsHorizontalScrollIndicator={false} + showsVerticalScrollIndicator={false} + scrollsToTop={false} + scrollEventThrottle={16} + onScroll={this._onScroll.bind(this)} + onMomentumScrollBegin={this._onMomentumScrollBegin.bind(this)} + onMomentumScrollEnd={this._onMomentumScrollEnd.bind(this)} + keyboardDismissMode='on-drag' + > + + { this._renderChildren() } + + + ) + } + return ( + this.viewPager = view} + initialPage={this.index} + style={styles.scrollableContentAndroid} + onPageSelected={this._onPageSelected.bind(this)} + onPageScroll={this._onAndroidPageScroll.bind(this)}> + + { this._renderChildren() } + + + ) + } + + render () { + return ( + + + + + + + { this._renderNavs() } + + + + + + { this._renderPageScroll() } + + + ) + } +} + +const statusBarSpace = Platform.OS === 'ios' ? 20 : 0 + +const styles = StyleSheet.create({ + navWrapper: { + height: 40 + statusBarSpace, + backgroundColor: 'rgba(0,0,0,0.8)' + }, + statusBarSpace: { + height: statusBarSpace + }, + nav: { + height: 40, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between' + }, + navItem: { + height: 40, + borderTopWidth: 4, + borderTopColor: 'transparent', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center' + }, + itemText: { + textAlign: 'center', + color: 'rgba(255,255,255,0.7)', + flex: 1 + }, + page: { + width, + backgroundColor: 'white' + }, + scrollableContentAndroid: { + flex: 1, + backgroundColor: 'white' + }, + container: { + flex: 1 + } +}) + +export default ScrollableTabs diff --git a/src/components/Setting.js b/src/components/Setting.js new file mode 100644 index 00000000..39e24e59 --- /dev/null +++ b/src/components/Setting.js @@ -0,0 +1,185 @@ +import React, {Component} from 'react' +import {View, StyleSheet, Text, TouchableOpacity, Dimensions, Platform} from 'react-native' +import PropTypes from 'prop-types' +import Icon from 'react-native-vector-icons/Ionicons' +import Modal from './base/Modal' +import Button from 'react-native-button' +import Row from './base/Row' + +const {height, width} = Dimensions.get('window') +const iconSize = 17 +const rowHeight = 50 + +class Setting extends Component { + static propTypes = { + router: PropTypes.object, + actions: PropTypes.object + }; + + constructor (props) { + super(props) + this.state = { + visible: false + } + } + + onAboutPress () { + this.props.router.toAbout() + } + + onLogoutPress () { + this.props.router.pop() + this.props.actions.logout() + } + + onClearPress () { + const {actions} = this.props + actions.clear() + actions.toast('缓存清除成功') + } + + show () { + this.setState({ + visible: true + }) + } + + render () { + if (!this.state.visible) { return null } + return ( + + + + + + + + 设置 + + + + + + + + + 关于 + + + + + + + + + 清除缓存 + + + + + + + + + 退出 + + + + + + this.setState({ visible: false })}> + + + + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center' + }, + modalStyle: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center' + }, + contentWrapper: { + flex: 4, + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: Platform.OS === 'ios' ? 'rgba(0,0,0,0.3)' : '#292829', + borderRadius: 3, + margin: 30 + }, + body: { + flex: 1, + height: rowHeight * 6, + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center' + }, + closeButton: { + flex: 1, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center' + }, + row: { + flex: 1, + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + borderRadius: 2, + paddingLeft: 20, + backgroundColor: 'rgba(0,0,0,0.1)', + width: width - 30 * 2 + }, + rowText: { + color: 'rgba(255,255,255,0.7)' + }, + rowTextWrapper: { + paddingLeft: 20 + }, + logoutText: { + color: '#E74C3C' + }, + header: { + backgroundColor: 'rgba(0,0,0,0.5)' + }, + closeIcon: { + height: 30, + width: 30, + borderRadius: 30 / 2, + borderColor: 'rgba(255,255,255,0.2)', + textAlign: 'center' + } +}) + +export default Setting diff --git a/src/components/TabBar.js b/src/components/TabBar.js new file mode 100644 index 00000000..c1aff8a6 --- /dev/null +++ b/src/components/TabBar.js @@ -0,0 +1,93 @@ +import React, {Component} from 'react' +import {StyleSheet, Text, TouchableOpacity, View, Dimensions, Animated} from 'react-native' +import PropTypes from 'prop-types' + +const { width } = Dimensions.get('window') +const underLineColor = '#3498DB' +const activeTabTextColor = 'rgba(0,0,0,9)' +const normalTabTextColor = 'rgba(0,0,0,0.4)' + +class TabBar extends Component { + static propTypes = { + goToPage: PropTypes.func, + activeTab: PropTypes.number, + tabs: PropTypes.array, + tabStyle: PropTypes.object, + tabTextStyle: PropTypes.object, + activeTabTextColor: PropTypes.string, + normalTabTextColor: PropTypes.string + }; + + static defaultProps = { + activeTabTextColor, + normalTabTextColor + }; + + constructor (props) { + super(props) + } + + renderTabOption (name, page) { + const isTabActive = this.props.activeTab === page + const textStyle = { + color: isTabActive ? this.props.activeTabTextColor : this.props.normalTabTextColor, + fontWeight: isTabActive ? 'bold' : 'normal' + } + + return ( + this.props.goToPage(page)}> + + + { name } + + + + ) + } + + render () { + var numberOfTabs = this.props.tabs.length + var tabUnderlineStyle = { + position: 'absolute', + width: width / numberOfTabs, + height: 4, + backgroundColor: underLineColor, + bottom: 0 + } + + var left = this.props.scrollValue.interpolate({ + inputRange: [0, 1], outputRange: [0, width / numberOfTabs] + }) + + return ( + + {this.props.tabs.map((tab, i) => this.renderTabOption(tab, i))} + + + ) + } +} + +const styles = StyleSheet.create({ + tab: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + paddingBottom: 10, + paddingTop: 10 + }, + + tabs: { + height: 50 + 4, + flexDirection: 'row', + marginTop: 0, + borderWidth: 1, + borderTopWidth: 0, + borderLeftWidth: 0, + borderRightWidth: 0, + borderBottomColor: 'rgba(0,0,0,0.06)', + justifyContent: 'space-around' + } +}) + +export default TabBar diff --git a/src/components/TopicRow.js b/src/components/TopicRow.js new file mode 100644 index 00000000..961929b8 --- /dev/null +++ b/src/components/TopicRow.js @@ -0,0 +1,90 @@ +import React, {Component} from 'react' +import {View, StyleSheet, Text, Image, TouchableHighlight, Dimensions} from 'react-native' +import PropTypes from 'prop-types' +import { parseImgUrl } from '../utils' + +const { width } = Dimensions.get('window') + +class TopicRow extends Component { + static propTypes = { + topic: PropTypes.object, + footer: PropTypes.node, + onPress: PropTypes.func + }; + + static defaultProps = { + onPress: () => null + }; + + render () { + const { topic } = this.props + + return ( + { this.props.onPress(topic) }} + underlayColor='#3498DB' + key={topic.id}> + + + + this.imgView = view} + style={styles.img} + source={{uri: parseImgUrl(topic.author.avatar_url) }} /> + + + + this.titleText = view} + numberOfLines={1} + style={[styles.title]}> + { topic.title } + + + + { this.props.footer } + + + + + ) + } +} + +var styles = StyleSheet.create({ + 'row': { + 'height': 90, + 'flexDirection': 'row', + 'borderBottomColor': 'rgba(0, 0, 0, 0.02)', + 'borderBottomWidth': 1, + 'paddingTop': 25, + 'paddingRight': 0, + 'paddingBottom': 25, + 'paddingLeft': 20 + }, + 'imgWrapper': { + 'width': 90, + 'position': 'absolute', + 'left': 20, + 'top': 25, + 'height': 65 + }, + 'img': { + 'height': 40, + 'width': 40, + 'borderRadius': 20 + }, + 'topic': { + 'marginLeft': 60, + width: width - 100 + }, + 'title': { + 'fontSize': 15 + }, + 'topicFooter': { + 'marginTop': 12, + 'flexDirection': 'row' + } +}) + +export default TopicRow diff --git a/src/components/UserOverlay.js b/src/components/UserOverlay.js new file mode 100644 index 00000000..d3b94170 --- /dev/null +++ b/src/components/UserOverlay.js @@ -0,0 +1,79 @@ +import React, {Component} from 'react' +import {StyleSheet, Image, View} from 'react-native' +import PropTypes from 'prop-types' +import Icon from 'react-native-vector-icons/Ionicons.js' +import OverlayButton from './base/OverlayButton' +import { parseImgUrl } from '../utils' + +class UserOverlay extends Component { + static propTypes = { + toLogin: PropTypes.func, + toUser: PropTypes.func + }; + + _onPress () { + const { user, toLogin, toUser } = this.props + if (user) { + toUser() + } else { + toLogin() + } + } + + _renderOverlayContent () { + if (this.props.user) { + const uri = parseImgUrl(this.props.user.avatar_url) + return ( + + ) + } + + return ( + + + + ) + } + + render () { + return ( + + {this._renderOverlayContent()} + + ) + } +} + +const styles = StyleSheet.create({ + userImg: { + borderWidth: 2, + borderColor: 'rgba(241,196,15,0.9)', + width: 45, + height: 45, + borderRadius: 45 / 2 + }, + iconWrapper: { + flex: 1, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + height: 45, + width: 45 + }, + icon: { + flex: 1, + textAlign: 'center' + } +}) + +export default UserOverlay diff --git a/src/components/UserTopicList.js b/src/components/UserTopicList.js new file mode 100644 index 00000000..8010ee6b --- /dev/null +++ b/src/components/UserTopicList.js @@ -0,0 +1,99 @@ +import React, {Component} from 'react' +import {View, StyleSheet, Text, ListView, Dimensions} from 'react-native' +import moment from 'moment' +import TopicRow from './TopicRow' + +const { width } = Dimensions.get('window') + +class UserTopicList extends Component { + constructor (props) { + super(props) + this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) + this.data = this.props.data || [] + this.state = { + ds: this.ds.cloneWithRows(this.data) + } + } + + componentWillReceiveProps (nextProps) { + if (nextProps.data != this.props.data) { + this.setState({ + ds: this.ds.cloneWithRows(nextProps.data) + }) + } + } + + _onRowPress (topic) { + this.props.router.toTopic({ + topic: topic, + id: topic.id + }) + } + + _renderRowFooter (topic) { + var date = moment(topic.last_reply_at).startOf('minute').fromNow() + let dateItem = ( + + {date} + + ) + + let authorItem = ( + + {topic.author.loginname} + + ) + + return [dateItem, authorItem] + } + + _renderRow (topic) { + return ( + + ) + } + + render () { + return ( + + + + ) + } +} + +var styles = StyleSheet.create({ + container: { + width: width + }, + 'topicFooter text': { + 'fontSize': 11, + 'color': 'rgba(0, 0, 0, 0.3)' + }, + 'topicFooter date': { + 'position': 'absolute', + 'right': 0, + 'top': 0 + }, + 'topicFooter author': { + position: 'absolute', + left: 0, + top: 0 + } +}) + +export default UserTopicList diff --git a/src/components/base/CustomImage.js b/src/components/base/CustomImage.js new file mode 100644 index 00000000..7313a993 --- /dev/null +++ b/src/components/base/CustomImage.js @@ -0,0 +1,128 @@ +import React, { + Component +} from 'react' +import { + Image, + View, + StyleSheet, + Text, + TouchableOpacity +} from 'react-native' +import PropTypes from 'prop-types' +import Icon from 'react-native-vector-icons/Ionicons' +import PureRenderMixin from 'react-addons-pure-render-mixin' + +export default class CustomImage extends Component { + static propTypes = { + defaultSize: PropTypes.object, + maxImageWidth: PropTypes.number, + uri: PropTypes.string + }; + + static defaultProps = { + defaultSize: { + height: 200, + width: 200 + } + }; + + constructor (props) { + super(props) + this.state = { + size: props.defaultSize, + isLoaded: false, + error: false + } + this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this) + this._loadImg(props.uri, props.maxImageWidth) + } + + _loadImg (uri, maxImageWidth) { + if (!uri) { return } + const startTime = new Date().getTime() + Image.getSize(uri, (w, h) => { + if (w >= maxImageWidth) { + h = (maxImageWidth / w) * h + w = maxImageWidth + } + let leftTime = 500 - (new Date().getTime() - startTime) + if (leftTime > 0) { + setTimeout(() => { + this.setState({ + size: { + width: w, + height: h + }, + isLoaded: true + }) + }, leftTime) + } else { + this.setState({ + size: { + width: w, + height: h + }, + isLoaded: true + }) + } + }, () => { + this.setState({ + error: true + }) + }) + } + + render () { + const {uri, style} = this.props + const {size, isLoaded, error} = this.state + if (isLoaded) { + return ( + + ) + } + + if (error) { + return ( + this._loadImg(this.props.uri, this.props.maxImageWidth)}> + + + + 点击重新加载图片 + + + + ) + } + + return ( + + + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + backgroundColor: 'rgba(0,0,0,0.05)', + borderRadius: 5, + margin: 10 + }, + icon: { + color: 'rgba(0,0,0,0.5)' + } +}) diff --git a/src/components/base/ErrorHandle.js b/src/components/base/ErrorHandle.js new file mode 100644 index 00000000..596026c1 --- /dev/null +++ b/src/components/base/ErrorHandle.js @@ -0,0 +1,61 @@ +import React, {Component} from 'react' +import {View, StyleSheet, TouchableOpacity, Text} from 'react-native' +import PropTypes from 'prop-types' + +class ErrorHandle extends Component { + static propTypes = { + infoText: PropTypes.string, + onPress: PropTypes.func, + buttonText: PropTypes.string + }; + + static defaultProps = { + infoText: '网络出错啦, 请点击按钮重新加载', + buttonText: '重新获取' + }; + + render () { + return ( + + + { this.props.infoText } + + + + + { this.props.buttonText } + + + + + ) + } +} + +const styles = StyleSheet.create({ + container: { + height: 130, + flexDirection: 'column', + justifyContent: 'space-between', + alignItems: 'center', + backgroundColor: 'white', + padding: 20 + }, + button: { + width: 150, + height: 40, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + borderRadius: 5, + backgroundColor: '#E74C3C' + }, + infoText: { + fontSize: 20 + }, + buttonText: { + color: 'white' + } +}) + +export default ErrorHandle diff --git a/src/components/base/Html.js b/src/components/base/Html.js new file mode 100644 index 00000000..e4c3cdac --- /dev/null +++ b/src/components/base/Html.js @@ -0,0 +1,119 @@ +import React, {Component} from 'react' +import {StyleSheet, Image, Dimensions} from 'react-native' +import PropTypes from 'prop-types' +import _ from 'lodash' +import HtmlRender from 'react-native-html-render' +import PureRenderMixin from 'react-addons-pure-render-mixin' +import CustomImage from './CustomImage' +import {parseImgUrl, link} from '../../utils' + +const {width} = Dimensions.get('window') +const defaultMaxImageWidth = width - 30 - 20 + +const regs = { + http: { + topic: /^https?:\/\/cnodejs\.org\/topic\/\w*/, + user: /^https?:\/\/cnodejs\.org\/user\/\w*/ + }, + gif: /.*\.gif$/ +} + +const styles = StyleSheet.create({ + defaultImg: { + height: defaultMaxImageWidth, + width: defaultMaxImageWidth, + resizeMode: Image.resizeMode.cover, + borderRadius: 5, + margin: 10 + } +}) + +class Html extends Component { + static propTypes = { + router: PropTypes.object, + imgStyle: PropTypes.object + }; + + static defaultProps = { + maxImageWidth: defaultMaxImageWidth + }; + + constructor (props) { + super(props) + this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this) + } + + _onLinkPress (url) { + let router = this.props.router + + if (/^\/user\/\w*/.test(url)) { + let authorName = url.replace(/^\/user\//, '') + + router.toUser({ + userName: authorName + }) + } + + if (/^https?:\/\/.*/.test(url)) { + if (regs.http.topic.test(url)) { + let topicId = url.replace(/^https?:\/\/cnodejs\.org\/topic\//, '') + + return router.toTopic({ + id: topicId + }) + } + + if (regs.http.user.test(url)) { + let userName = url.replace(/^https?:\/\/cnodejs\.org\/user\//, '') + + return router.toUser({ + userName: userName + }) + } + + link(url) + } + + if (/^mailto:\w*/.test(url)) { + link(url) + } + } + + _renderNode (node, index, parent, type) { + const name = node.name + const {imgStyle = styles.defaultImg, maxImageWidth} = this.props + + if (node.type === 'block' && type === 'block') { + if (name === 'img') { + const uri = parseImgUrl(node.attribs.src) + if (regs.gif.test(uri)) { return null } + const imageId = _.uniqueId('image_') + return ( + + ) + } + } + } + + render () { + return ( + + ) + } +} + +export default Html diff --git a/src/components/base/Loading.js b/src/components/base/Loading.js new file mode 100644 index 00000000..95419b70 --- /dev/null +++ b/src/components/base/Loading.js @@ -0,0 +1,59 @@ +import React, {Component} from 'react' +import {StyleSheet, Dimensions, Animated} from 'react-native' +import PropTypes from 'prop-types' +import Spinner from './Spinner' + +const { height, width } = Dimensions.get('window') +const toastWidth = width * 0.7 + +class Loading extends Component { + static propTypes = { + show: PropTypes.bool + }; + + static defaultProps = { + show: false + }; + + constructor (props) { + super(props) + this.state = { + fadeAnim: new Animated.Value(0.4) + } + } + + render () { + const opacity = { + opacity: this.state.fadeAnim + } + if (!this.props.show) { return null } + return ( + + + + ) + } +} + +const styles = StyleSheet.create({ + container: { + position: 'absolute', + backgroundColor: 'rgba(0,0,0,0.8)', + borderRadius: 5, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + width: toastWidth, + left: (width - toastWidth) / 2, + top: (height - 60) / 2, + padding: 20 + }, + text: { + flex: 1, + color: 'white', + fontSize: 16, + textAlign: 'center' + } +}) + +export default Loading diff --git a/src/components/base/Modal.js b/src/components/base/Modal.js new file mode 100644 index 00000000..b9f6d11b --- /dev/null +++ b/src/components/base/Modal.js @@ -0,0 +1,93 @@ +import React, {Component} from 'react' +import {Dimensions, View, StyleSheet, Animated, Easing, Platform, TouchableWithoutFeedback} from 'react-native' +import PropTypes from 'prop-types' + +if (Platform.OS !== 'web') { + var BlurView = require('react-native-blur').BlurView +} + +const {height, width} = Dimensions.get('window') + +class Modal extends Component { + static propTypes = { + blur: PropTypes.bool, + blurType: PropTypes.string, + onPressBackdrop: PropTypes.func + }; + + static defaultProps = { + blur: false, + blurType: 'dark' + }; + + constructor (props) { + super(props) + this.state = { + fadeAnim: new Animated.Value(0.2) + } + } + + componentDidMount () { + Animated.timing(this.state.fadeAnim, { + toValue: 1, + easing: Easing.quad, + duration: 100 + }).start() + } + + _onPress (e) { + const {pageY} = e.nativeEvent + const {onPressBackdrop} = this.props + if (height - pageY > 200) { + typeof onPressBackdrop === 'function' && onPressBackdrop() + } + } + + _renderChildren () { + if (this.props.blur) { + if (Platform.OS === 'ios') { + return ( + + { this.props.children } + + ) + } + return ( + + { this.props.children } + + ) + } + return this.props.children + } + + render () { + return ( + + + { this._renderChildren() } + + + ) + } +} + +const styles = StyleSheet.create({ + container: { + position: 'absolute', + flex: 1, + top: 0, + left: 0, + height, + width + }, + blur: { + height, + width + }, + opacity: { + backgroundColor: 'rgba(0,0,0,0.4)' + } +}) + +export default Modal diff --git a/src/components/base/OverlayButton.js b/src/components/base/OverlayButton.js new file mode 100644 index 00000000..cd2ac799 --- /dev/null +++ b/src/components/base/OverlayButton.js @@ -0,0 +1,37 @@ +import React, {Component} from 'react' +import {View, StyleSheet, TouchableOpacity} from 'react-native' + +const overlayButtonSize = 45 + +class OverlayButton extends Component { + render () { + return ( + + + {this.props.children} + + + ) + } +} + +const styles = StyleSheet.create({ + container: { + height: overlayButtonSize, + width: overlayButtonSize, + position: 'absolute', + borderRadius: overlayButtonSize / 2, + backgroundColor: 'rgba(0,0,0,0.7)', + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center' + }, + defaultPosition: { + left: 20, + bottom: 20 + } +}) + +export default OverlayButton diff --git a/src/components/base/Return.js b/src/components/base/Return.js new file mode 100644 index 00000000..f1a7074a --- /dev/null +++ b/src/components/base/Return.js @@ -0,0 +1,44 @@ +import React, {Component} from 'react' +import {StyleSheet, View} from 'react-native' +import OverlayButton from './OverlayButton' +import Icon from 'react-native-vector-icons/Ionicons' + +const returnSize = 45 + +class Return extends Component { + _onPress () { + this.props.router && this.props.router.pop && this.props.router.pop() + } + + render () { + return ( + + + + + + ) + } +} + +const styles = StyleSheet.create({ + returnIcon: { + flex: 1, + textAlign: 'center' + }, + iconWrapper: { + flex: 1, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + height: returnSize, + width: returnSize + } +}) + +export default Return diff --git a/src/components/base/Row.js b/src/components/base/Row.js new file mode 100644 index 00000000..36955151 --- /dev/null +++ b/src/components/base/Row.js @@ -0,0 +1,29 @@ +import React, {Component} from 'react' +import {View, StyleSheet, TouchableHighlight} from 'react-native' + +class Row extends Component { + render () { + return ( + + + { this.props.children } + + + ) + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center' + }, + content: { + flex: 1, + flexDirection: 'row' + } +}) + +export default Row diff --git a/src/components/base/Spinner.js b/src/components/base/Spinner.js new file mode 100644 index 00000000..984eb2ff --- /dev/null +++ b/src/components/base/Spinner.js @@ -0,0 +1,18 @@ +import React, {Component} from 'react' +import {ActivityIndicator} from 'react-native' + +class Spinner extends Component { + static defaultProps={ + color: 'rgba(241,196,15, 1.0)' + }; + + render () { + return ( + + ) + } +} + +export default Spinner diff --git a/src/components/base/Toast.js b/src/components/base/Toast.js new file mode 100644 index 00000000..6480cdd5 --- /dev/null +++ b/src/components/base/Toast.js @@ -0,0 +1,95 @@ +import React, {Component} from 'react' +import {StyleSheet, Text, Dimensions, Animated} from 'react-native' +import PropTypes from 'prop-types' + +const {height, width} = Dimensions.get('window') +const toastWidth = width * 0.7 +const defaultText = 'Toast' +const defaultTimeout = 2000 + +class Toast extends Component { + static propTypes = { + duration: PropTypes.number + }; + + static defaultProps = { + duration: 300 + }; + + constructor (props) { + super(props) + this.state = { + fadeAnim: new Animated.Value(0.4), + show: false, + text: defaultText, + timeout: defaultTimeout + } + } + + componentWillUnmount () { + clearTimeout(this.timeout) + } + + show (text = defaultText, timeout = defaultTimeout) { + const {duration} = this.props + Animated.timing(this.state.fadeAnim, { + toValue: 1, + duration: duration + }).start() + + this.setState({ + show: true, + text, + timeout + }) + + this.timeout = setTimeout(() => { + Animated.timing(this.state.fadeAnim, { + toValue: 0, + duration: duration + }).start(() => { + this.setState({ + show: false + }) + }) + }, timeout - duration) + } + + render () { + const opacity = { + opacity: this.state.fadeAnim + } + if (!this.state.show) { return null } + return ( + + + {this.state.text} + + + ) + } +} + +const styles = StyleSheet.create({ + container: { + position: 'absolute', + backgroundColor: 'rgba(0,0,0,0.8)', + borderRadius: 5, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + width: toastWidth, + left: (width - toastWidth) / 2, + top: (height - 60) / 2, + padding: 20 + }, + text: { + flex: 1, + color: 'white', + fontSize: 16, + textAlign: 'center', + lineHeight: 16 * 1.5 + } +}) + +export default Toast diff --git a/src/configs/Router.js b/src/configs/Router.js new file mode 100644 index 00000000..91747b09 --- /dev/null +++ b/src/configs/Router.js @@ -0,0 +1,115 @@ +import React from 'react' +import ReactNative from 'react-native' +import {Platform, BackHandler} from 'react-native' +import {Navigator} from 'react-native-deprecated-custom-components' +import _ from 'lodash' +import * as About from '../layouts/About' +import * as QRCode from '../layouts/QRCode' +import * as Login from '../layouts/Login' +import * as User from '../layouts/User' +import * as Message from '../layouts/Message' +import * as Topic from '../layouts/Topic' +import * as Comment from '../layouts/Comment' +import * as Publish from '../layouts/Publish' +import * as HomeComponent from '../layouts/Home' +import * as CustomSceneConfigs from '../configs/sceneConfig' +import connectComponent from '../utils/connectComponent' + +const Home = connectComponent(HomeComponent) + +const { + SceneConfigs +} = ReactNative + +class Router { + constructor (navigator) { + this.navigator = navigator + if (Platform.OS === 'android') { + BackHandler.addEventListener('hardwareBackPress', () => { + const routesList = this.navigator.getCurrentRoutes() + const currentRoute = routesList[routesList.length - 1] + if (currentRoute.name !== 'home') { + navigator.pop() + return true + } + return false + }) + } + } + + push (props = {}, route) { + let routesList = this.navigator.getCurrentRoutes() + let nextIndex = routesList[routesList.length - 1].index + 1 + route.props = props + route.index = nextIndex + route.sceneConfig = route.sceneConfig ? route.sceneConfig : CustomSceneConfigs.customFloatFromRight + route.id = _.uniqueId() + route.component = connectComponent(route.component) + this.navigator.push(route) + } + + pop () { + this.navigator.pop() + } + + toAbout (props) { + this.push(props, { + component: About, + name: 'about', + sceneConfig: CustomSceneConfigs.customFloatFromBottom + }) + } + + toLogin (props) { + this.push(props, { + component: Login, + name: 'login', + sceneConfig: CustomSceneConfigs.customFloatFromBottom + }) + } + + toQRCode (props) { + this.push(props, { + component: QRCode, + name: 'qrcode', + sceneConfig: CustomSceneConfigs.customFloatFromBottom + }) + } + + toUser (props) { + this.push(props, { + component: User, + name: 'user' + }) + } + + toMessage (props) { + this.push(props, { + component: Message, + name: 'message' + }) + } + + toTopic (props) { + this.push(props, { + component: Topic, + name: 'topic' + }) + } + + toComment (props) { + this.push(props, { + component: Comment, + name: 'comment' + }) + } + + toPublish (props) { + this.push(props, { + component: Publish, + name: 'publish' + }) + } +} + +export default Router diff --git a/src/configs/animations.js b/src/configs/animations.js new file mode 100644 index 00000000..90865acd --- /dev/null +++ b/src/configs/animations.js @@ -0,0 +1,33 @@ +import React from 'react' +import {LayoutAnimation} from 'react-native' + +var animations = {} + +animations.keyboard = { + layout: { + spring: { + duration: 400, + create: { + duration: 300, + type: LayoutAnimation.Types.easeInEaseOut, + property: LayoutAnimation.Properties.opacity + }, + update: { + type: LayoutAnimation.Types.spring, + springDamping: 400 + } + }, + easeInEaseOut: { + duration: 400, + create: { + type: LayoutAnimation.Types.easeInEaseOut, + property: LayoutAnimation.Properties.scaleXY + }, + update: { + type: LayoutAnimation.Types.easeInEaseOut + } + } + } +} + +export default animations diff --git a/src/configs/index.js b/src/configs/index.js new file mode 100644 index 00000000..7b2c0044 --- /dev/null +++ b/src/configs/index.js @@ -0,0 +1,16 @@ +import packageJson from '../../package.json' + +export default { + domain: 'https://cnodejs.org/', + apiPath: '/api/v1', + bgImgUri: 'http://7lrzfj.com1.z0.glb.clouddn.com/soliury213H.png', + replySuffix: '\nFrom [Noder](https://github.com/soliury/noder-react-native)', + sourceInGithub: 'https://github.com/soliury/noder-react-native', + package: packageJson, + author: { + blog: 'http://lingyong.me/about', + cnodeName: 'soliury' + }, + cnodeAbout: 'https://cnodejs.org/about', + RNWebPage: 'http://facebook.github.io/react-native/' +} diff --git a/src/configs/sceneConfig.js b/src/configs/sceneConfig.js new file mode 100644 index 00000000..f09f9ca9 --- /dev/null +++ b/src/configs/sceneConfig.js @@ -0,0 +1,26 @@ +import React from 'react' +import {Dimensions} from 'react-native' +import {Navigator} from 'react-native-deprecated-custom-components' + +const { width } = Dimensions.get('window') + +const baseConfig = Navigator.SceneConfigs.FloatFromRight +const popGestureConfig = Object.assign({}, baseConfig.gestures.pop, { + edgeHitWidth: width / 3 +}) + +const fullPopGestureConfig = Object.assign({}, Navigator.SceneConfigs.FloatFromBottom.gestures.pop, { + edgeHitWidth: width +}) + +export const customFloatFromRight = Object.assign({}, baseConfig, { + gestures: { + pop: popGestureConfig + } +}) + +export const customFloatFromBottom = Object.assign({}, Navigator.SceneConfigs.FloatFromBottom, { + gestures: { + pop: fullPopGestureConfig + } +}) diff --git a/src/constants/ActionTypes.js b/src/constants/ActionTypes.js new file mode 100644 index 00000000..c1859ed5 --- /dev/null +++ b/src/constants/ActionTypes.js @@ -0,0 +1,36 @@ +// Home +export const OPEN_LOGIN_MODAL = 'OPEN_LOGIN_MODAL' +export const CLOSE_LOGIN_MODAL = 'CLOSE_LOGIN_MODAL' +export const UPDATE_TAB = 'UPDATE_TAB' + +// user +export const CHECK_TOKEN = 'CHECK_TOKEN' +export const GET_USER_FROM_STORAGE = 'GET_USER_FROM_STORAGE' +export const UPDATE_CLIENT_USER_INFO = 'UPDATE_CLIENT_USER_INFO' +export const LOGOUT = 'LOGOUT' +export const GET_USER_INFO = 'GET_USER_INFO' +export const CLEAR = 'CLEAR' + +// utils +export const TOAST = 'TOAST' +export const OPEN_TOAST = 'OPEN_TOAST' +export const CLOSE_TOAST = 'CLOSE_TOAST' + +// message +export const GET_UNREAD_MESSAGE_COUNT = 'GET_UNREAD_MESSAGE_COUNT' +export const MARK_AS_READ = 'MARK_AS_READ' +export const GET_MESSAGES_LIST = 'GET_MESSAGES_LIST' + +// topic +export const GET_TOPICS_FROM_STORAGE = 'GET_TOPICS_FROM_STORAGE' +export const GET_TOPICS_BY_TAB = 'GET_TOPICS_BY_TAB' +export const UPDATE_TOPICS_BY_TAB = 'UPDATE_TOPICS_BY_TAB' +export const GET_TOPIC_BY_ID = 'GET_TOPIC_BY_ID' +export const REMOVE_TOPIC_CACHE_BY_ID = 'REMOVE_TOPIC_CACHE_BY_ID' +export const REPLY_TOPIC_BY_ID = 'REPLY_TOPIC_BY_ID' +export const UP_REPLY = 'UP_REPLY' +export const PUBLISH = 'PUBLISH' + +// middleware +export const SYNC_REDUCER_TO_ASYNC_STORAGE = 'SYNC_REDUCER_TO_ASYNC_STORAGE' +export const GET_REDUCER_FROM_ASYNC_STORAGE = 'GET_REDUCER_FROM_ASYNC_STORAGE' diff --git a/src/constants/Tabs.js b/src/constants/Tabs.js new file mode 100644 index 00000000..780b7185 --- /dev/null +++ b/src/constants/Tabs.js @@ -0,0 +1 @@ +export const tabs = ['good', 'ask', 'all', 'share', 'job'] diff --git a/src/constants/index.js b/src/constants/index.js new file mode 100644 index 00000000..51f70a6a --- /dev/null +++ b/src/constants/index.js @@ -0,0 +1,6 @@ +export const refreshControl = { + tintColor: 'rgba(241,196,15, 1)', + title: '正在加载...', + colors: ['rgba(241,196,15, 1)', 'rgba(241,196,15, 0.9)', 'rgba(241,196,15, 0.8)'], + progressBackgroundColor: '#292829' +} diff --git a/iOS/Images.xcassets/blog.imageset/blog@1x.png b/src/images/blog.png similarity index 100% rename from iOS/Images.xcassets/blog.imageset/blog@1x.png rename to src/images/blog.png diff --git a/src/images/noderIcon.png b/src/images/noderIcon.png new file mode 100644 index 00000000..989c3d2f Binary files /dev/null and b/src/images/noderIcon.png differ diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..becedc75 --- /dev/null +++ b/src/index.js @@ -0,0 +1,20 @@ +import React, { + Component +} from 'react' +import { Provider } from 'react-redux' +import configureStore from './store/configureStore' +import Navigation from './layouts/Navigation' + +const store = configureStore() + +class App extends Component { + render () { + return ( + + + + ) + } +} + +export default App diff --git a/src/layouts/About.js b/src/layouts/About.js new file mode 100644 index 00000000..fef3d727 --- /dev/null +++ b/src/layouts/About.js @@ -0,0 +1,127 @@ +import React, {Component} from 'react' +import {View, Text, StyleSheet, Image, TouchableOpacity, Dimensions, ScrollView} from 'react-native' +import Icon from 'react-native-vector-icons/Ionicons' +import config from '../configs' +import * as utils from '../utils' + +const {height, width} = Dimensions.get('window') + +class About extends Component { + _onSourceInGithubPress () { + utils.link(config.sourceInGithub) + } + + render () { + return ( + + + Noder + + {' v' + config.package.version} + + + + utils.link(config.cnodeAbout)}> + For CNodejs.org + + + + + + + + this.props.router.toUser({ + userName: config.author.cnodeName + })}> + @soliury + + + + utils.link(config.author.blog)}> + + + + + utils.link(config.RNWebPage)}> + Power By + React-Native {'v' + config.package.dependencies['react-native']} + + + + ) + } +} + +const styles = StyleSheet.create({ + bgWall: { + height: height, + width: width + }, + noderLogo: { + height: 150, + width: 150 + }, + container: { + width: width, + height: height, + flexDirection: 'column', + alignItems: 'center', + paddingTop: 30, + backgroundColor: '#292829' + }, + title: { + marginTop: 20, + fontSize: 30, + color: 'rgba(255,255,255,0.7)', + borderBottomWidth: 1, + borderBottomColor: 'rgba(255,255,255,0.1)' + + }, + subTitle: { + marginTop: 10, + fontSize: 16, + color: 'rgba(255,255,255,0.5)' + }, + row: { + flexDirection: 'row', + justifyContent: 'center', + height: 40, + alignItems: 'center' + }, + rowIcon: { + height: 40, + width: 40 + }, + footer: { + position: 'absolute', + bottom: 0, + width: width, + flexDirection: 'column', + justifyContent: 'space-around', + alignItems: 'center', + height: 100 + }, + blog: { + height: 20, + width: 100, + opacity: 0.5 + }, + reactNative: { + fontSize: 16, + color: 'rgba(255,255,255,0.3)' + } +}) + +export const LayoutComponent = About +export function mapStateToProps (state) { + return {} +} diff --git a/src/layouts/Comment.js b/src/layouts/Comment.js new file mode 100644 index 00000000..d0236e0f --- /dev/null +++ b/src/layouts/Comment.js @@ -0,0 +1,326 @@ +import React, {Component} from 'react' +import {View, StyleSheet, Text, Image, ListView, TouchableOpacity, TextInput, LayoutAnimation, Dimensions, Keyboard, Platform} from 'react-native' +import Icon from 'react-native-vector-icons/Ionicons' +import Nav from '../components/Nav' +import Spinner from '../components/base/Spinner' +import CommentList from './../components/CommentList' +import animations from '../configs/animations' +import {parseImgUrl} from '../utils' +import config from '../configs' + +const {width, height} = Dimensions.get('window') +const authorImgSize = 35 +const replyFormHeight = 55 +const commentsHeight = height - 40 - 20 - replyFormHeight - 20 +const submitButtonWidth = 55 + +class Comment extends Component { + constructor (props) { + super(props) + this.state = { + didFocus: false + } + if (Platform.OS !== 'web') { + Keyboard.addListener('keyboardWillShow', this.updateKeyboardSpace.bind(this)) + Keyboard.addListener('keyboardWillHide', this.resetKeyboardSpace.bind(this)) + } + + if (Platform.OS === 'android') { + Keyboard.addListener('keyboardDidShow', this.updateKeyboardSpace.bind(this)) + Keyboard.addListener('keyboardDidHide', this.resetKeyboardSpace.bind(this)) + } + } + + updateKeyboardSpace (e) { + LayoutAnimation.configureNext(animations.keyboard.layout.spring) + this.commentsView && this.commentsView.setNativeProps({ + style: { + height: commentsHeight - e.endCoordinates.height + } + }) + } + + resetKeyboardSpace () { + LayoutAnimation.configureNext(animations.keyboard.layout.spring) + this.commentsView && this.commentsView.setNativeProps({ + style: { + height: commentsHeight + } + }) + } + + componentDidMount () { + const {topic, actions} = this.props + actions.getTopicById(topic.id) + } + + componentDidFocus (haveFocus) { + if (!haveFocus) { + setTimeout(() => { + this.setState({ + didFocus: true + }) + }) + } + } + + _resetReplyForm () { + this.replyId = null + this.textInput.setNativeProps({ + text: '' + }) + this.textInputValue = '' + this.textInput.blur() + } + + _doReply () { + var content = this.textInputValue + if (this.props.replyPending || content == '' || content == null) { + return + } + let {topic, user} = this.props + content = content + config.replySuffix + this.props.actions.replyTopicById({ + topicId: topic.id, + content: content, + replyId: this.replyId, + user: { + loginname: user.loginname, + avatar_url: user.avatar_url + } + }, () => { + // resolved + this._resetReplyForm() + }, () => { + // rejected + }) + } + + _onReplyPress (id, authorName) { + if (!this.props.user) { return } + this.textInput.focus() + let text = `@${authorName} ` + this.textInput.setNativeProps({ + text: text + }) + this.replyId = id + this.textInputValue = text + } + + _onAuthorTextPress (authorName) { + if (!this.props.user) { return } + let text = (this.textInputValue || '') + ` @${authorName} ` + + this.textInput.setNativeProps({ + text: text + }) + this.textInputValue = text + } + + _renderReplySubmiteIcon () { + if (this.props.replyPending) { + return ( + + + + ) + } + return ( + + ) + } + + _renderReplyForm () { + const {user} = this.props + if (!user) { return null } + + const userImg = parseImgUrl(user.avatar_url) + let replyFormBorder = {} + if (Platform.OS === 'android') { + replyFormBorder = { + borderTopWidth: 1, + borderTopColor: 'rgba(0,0,0,0.08)' + } + } + + return ( + + + this.props.router.toUser({ + userName: user.loginname + })}> + + + + + + this.textInput = view} + value={this.state.textInput} + multiline + placeholder='嘿,说点啥吧' + style={styles.replyInput} + onChangeText={(text) => { + this.textInput.setNativeProps({ + text: text + }) + this.textInputValue = text + }} + /> + + + + this._doReply()}> + {this._renderReplySubmiteIcon()} + + + + ) + } + + render () { + const {replies, reply = {}, router, user, actions, topic, loadPending, count} = this.props + + let navs = { + Left: { + text: '返回', + onPress: () => { + router.pop() + } + }, + Center: { + text: '评论 ' + count, + onPress: () => { + if (count > 0) { + this.commentList.scrollToTop() + } + } + } + } + + if (this.state.didFocus && this.props.reply && topic) { + navs = { + ...navs, + Right: { + text: '正文', + onPress: () => { + router.toTopic({ + topic: topic, + id: topic.id, + from: 'comment' + }) + } + } + } + } + + return ( + +