diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000000..75a203bde7b --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +ColumnLimit: 100 diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000000..ffa0d8860ea --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +node_modules/ +lib/dist/ +website/ +autolink/ +scripts/ +e2e/ \ No newline at end of file diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 43718552cec..00000000000 --- a/.eslintrc +++ /dev/null @@ -1,523 +0,0 @@ -{ - "parser": "babel-eslint", - "env": { - "es6": true, - "node": true - }, - "parserOptions": { - "ecmaVersion": 7, - "sourceType": "module", - "ecmaFeatures": { - "impliedStrict": true, - "jsx": true, - "experimentalObjectRestSpread": true - } - }, - "plugins": [ - "react", - "react-native", - "babel" - ], - "rules": { - /* - * possible errors - */ - "comma-dangle": "error", - "no-cond-assign": [ - "error", - "except-parens" - ], - "no-console": "warn", - "no-constant-condition": "error", - "no-control-regex": "error", - "no-debugger": "warn", - "no-dupe-args": "error", - "no-dupe-keys": "error", - "no-duplicate-case": "error", - "no-empty": "error", - "no-empty-character-class": "error", - "no-ex-assign": "error", - "no-extra-boolean-cast": "error", - "no-extra-parens": 0, - "no-extra-semi": "error", - "no-func-assign": "error", - "no-inner-declarations": "error", - "no-invalid-regexp": "error", - "no-irregular-whitespace": "error", - "no-negated-in-lhs": "error", - "no-obj-calls": "error", - "no-regex-spaces": "error", - "no-sparse-arrays": "error", - "no-unexpected-multiline": "error", - "no-unreachable": "error", - "use-isnan": "error", - "valid-jsdoc": 0, - "valid-typeof": "error", - /* - * best practices - */ - "accessor-pairs": "warn", - "array-callback-return": 0, - "block-scoped-var": "error", - "complexity": 0, - "consistent-return": "error", - "curly": [ - "error", - "all" - ], - "default-case": "error", - "dot-location": [ - "error", - "property" - ], - "dot-notation": "error", - "eqeqeq": "error", - "guard-for-in": "error", - "no-alert": "error", - "no-caller": "error", - "no-case-declarations": "error", - "no-div-regex": 0, - "no-else-return": 0, - "no-empty-function": "error", - "no-empty-pattern": "error", - "no-eq-null": "error", - "no-eval": "error", - "no-extend-native": "error", - "no-extra-bind": "error", - "no-extra-label": "error", - "no-fallthrough": "error", - "no-floating-decimal": "error", - "no-implicit-coercion": "error", - "no-implicit-globals": 0, - "no-implied-eval": "error", - "no-invalid-this": 0, - "no-iterator": "error", - "no-labels": "error", - "no-lone-blocks": "error", - "no-loop-func": "error", - "no-magic-numbers": 0, - "no-multi-spaces": "error", - "no-multi-str": 0, - "no-native-reassign": "error", - "no-new": "error", - "no-new-func": "error", - "no-new-wrappers": "error", - "no-octal": "error", - "no-octal-escape": "error", - "no-param-reassign": "error", - "no-proto": "error", - "no-redeclare": 0, - "no-return-assign": "error", - "no-script-url": "error", - "no-self-assign": "error", - "no-self-compare": "error", - "no-sequences": "error", - "no-throw-literal": "error", - "no-unmodified-loop-condition": 0, - "no-unused-expressions": "error", - "no-unused-labels": 0, - "no-useless-call": "error", - "no-useless-concat": "error", - "no-void": "error", - "no-warning-comments": 0, - "no-with": "error", - "radix": 0, - "vars-on-top": 0, - "wrap-iife": "error", - "yoda": 0, - "strict": [ - "error", - "never" - ], - /* - * variables - */ - "init-declarations": 0, - "no-catch-shadow": "error", - "no-delete-var": "error", - "no-label-var": "error", - "no-restricted-globals": "error", - "no-shadow": "error", - "no-shadow-restricted-names": "error", - "no-undef": 0, - "no-undef-init": "error", - "no-undefined": 0, - "no-unused-vars": 0, - "no-use-before-define": 0, - /* - * Node.js - */ - "callback-return": 0, - "global-require": 0, - "handle-callback-err": 0, - "no-mixed-requires": "error", - "no-new-require": "error", - "no-path-concat": "error", - "no-process-env": 0, - "no-process-exit": "error", - "no-restricted-modules": 0, - "no-sync": 0, - /* - * style - */ - "array-bracket-spacing": [ - "error", - "never" - ], - "block-spacing": "error", - "brace-style": [ - "error", - "1tbs" - ], - "camelcase": [ - "error", - { - "properties": "never" - } - ], - "comma-spacing": [ - "error", - { - "before": false, - "after": true - } - ], - "comma-style": [ - "error", - "last" - ], - "computed-property-spacing": [ - "error", - "never" - ], - "consistent-this": [ - "error", - "self" - ], - "eol-last": [ - "error", - "unix" - ], - "func-names": 0, - "func-style": 0, - "id-blacklist": 0, - "id-length": 0, - "id-match": 0, - "indent": [ - "error", - 2, - { - "SwitchCase": 1 - } - ], - "jsx-quotes": "error", - "key-spacing": [ - "error", - { - "singleLine": { - "beforeColon": false, - "afterColon": true, - "mode": "strict" - }, - "multiLine": { - "beforeColon": false, - "afterColon": true, - "mode": "strict" - } - } - ], - "keyword-spacing": [ - "error", - { - "before": true, - "after": true - } - ], - "linebreak-style": [ - "error", - "unix" - ], - "lines-around-comment": 0, - "max-depth": [ - "error", - 4 - ], - "max-len": [ - "warn", - 150 - ], - "max-nested-callbacks": [ - "error", - 4 - ], - "max-params": [ - "error", - 6 - ], - "max-statements": [ - "error", - 15, - { - "ignoreTopLevelFunctions": true - } - ], - "new-cap": [ - "error", - { - "capIsNewExceptions": [ - "Immutable" - ] - } - ], - "new-parens": "error", - "newline-after-var": 0, - "newline-before-return": 0, - "newline-per-chained-call": 0, - "no-array-constructor": "error", - "no-bitwise": 0, - "no-continue": 0, - "no-inline-comments": 0, - "no-lonely-if": "error", - "no-mixed-spaces-and-tabs": 0, - "no-multiple-empty-lines": [ - "error", - { - "max": 1 - } - ], - "no-negated-condition": 0, - "no-nested-ternary": "error", - "no-new-object": "error", - "no-plusplus": 0, - "no-restricted-syntax": 0, - "no-spaced-func": "error", - "no-ternary": 0, - "no-trailing-spaces": [ - "error", - { - "skipBlankLines": true - } - ], - "no-underscore-dangle": 0, - "no-unneeded-ternary": "error", - "no-whitespace-before-property": "error", - "object-curly-spacing": [ - "error", - "never" - ], - "one-var": 0, - "one-var-declaration-per-line": 0, - "operator-assignment": 0, - "operator-linebreak": [ - "error", - "before" - ], - "padded-blocks": [ - "error", - "never" - ], - "quote-props": [ - "error", - "consistent-as-needed" - ], - "quotes": 0, - "require-jsdoc": 0, - "semi": [ - "error", - "always" - ], - "semi-spacing": [ - "error", - { - "before": false, - "after": true - } - ], - "sort-imports": 0, - "sort-vars": 0, - "space-before-blocks": [ - "error", - "always" - ], - "space-before-function-paren": [ - "error", - "never" - ], - "space-in-parens": [ - "error", - "never" - ], - "space-infix-ops": "error", - "space-unary-ops": "error", - "spaced-comment": 0, - "wrap-regex": "error", - /* - * ECMAScript 6 - */ - "arrow-body-style": 0, - "arrow-parens": 0, - "arrow-spacing": [ - "error", - { - "before": true, - "after": true - } - ], - "constructor-super": "error", - "generator-star-spacing": 0, - "no-class-assign": "error", - "no-confusing-arrow": "error", - "no-const-assign": "error", - "no-dupe-class-members": "error", - "no-new-symbol": "error", - "no-restricted-imports": 0, - "no-this-before-super": "error", - "no-useless-constructor": 0, - "no-var": "error", - "object-shorthand": 0, - "prefer-arrow-callback": 0, - "prefer-const": "error", - "prefer-reflect": 0, - "prefer-rest-params": "error", - "prefer-spread": "error", - "prefer-template": 0, - "require-yield": 0, - "template-curly-spacing": [ - "error", - "never" - ], - "yield-star-spacing": [ - "error", - "after" - ], - /* - * react plugin - */ - "react/display-name": 0, - "react/forbid-prop-types": [ - "error", - { - "forbid": [ - "any" - ] - } - ], - "react/no-danger": "error", - "react/no-deprecated": "error", - "react/no-did-mount-set-state": "error", - "react/no-did-update-set-state": "error", - "react/no-direct-mutation-state": "error", - "react/no-is-mounted": "error", - "react/no-multi-comp": "error", - "react/no-set-state": 0, - "react/no-string-refs": 0, - "react/no-unknown-property": 0, - "react/prefer-es6-class": [ - "error", - "always" - ], - "react/prefer-stateless-function": 0, - "react/prop-types": "error", - "react/react-in-jsx-scope": "error", - "react/require-extension": 0, - "react/self-closing-comp": "error", - "react/sort-comp": [ - "error", - { - "order": [ - "static-methods", - "lifecycle", - "/^on.+$/", - "/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/", - "everything-else", - "/^render.+$/", - "render" - ] - } - ], - "react/sort-prop-types": 0, - "react/wrap-multilines": "error", - "react/jsx-boolean-value": [ - "error", - "always" - ], - "react/jsx-closing-bracket-location": "error", - "react/jsx-curly-spacing": [ - "error", - "never" - ], - "react/jsx-equals-spacing": [ - "error", - "never" - ], - "react/jsx-handler-names": [ - "error", - { - "eventHandlerPropPrefix": "handle" - } - ], - "react/jsx-indent-props": [ - 0, - 2 - ], - "react/jsx-indent": [ - "error", - 2 - ], - "react/jsx-key": "error", - "react/jsx-max-props-per-line": [ - "error", - { - "maximum": 2 - } - ], - "react/jsx-no-bind": 0, - "react/jsx-no-duplicate-props": [ - "error", - { - "ignoreCase": true - } - ], - "react/jsx-no-literals": "error", - "react/jsx-no-undef": "error", - "react/jsx-pascal-case": "error", - "react/jsx-sort-props": 0, - "react/jsx-space-before-closing": 0, - "react/jsx-uses-react": "error", - "react/jsx-uses-vars": "error", - /* - * react-native plugin - */ - "react-native/no-unused-styles": "error", - "react-native/split-platform-components": "error", - /* - * babel plugin - */ - "babel/generator-star-spacing": [ - "error", - "after" - ], - "babel/new-cap": [ - "error", - { - "capIsNewExceptions": [ - "Immutable" - ] - } - ], - "babel/array-bracket-spacing": [ - "error", - "never" - ], - "babel/object-curly-spacing": [ - "error", - "never" - ], - "babel/object-shorthand": 0, - "babel/arrow-parens": [ - "error", - "always" - ], - "babel/no-await-in-loop": 0 - } -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000000..299a94f60e7 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,10 @@ +module.exports = { + root: true, + extends: ['@react-native', 'prettier', 'prettier/@typescript-eslint', 'prettier/react'], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + env: { + jest: true, + }, +}; + diff --git a/.ghp/wix.json b/.ghp/wix.json deleted file mode 100644 index 7b5cddda7fa..00000000000 --- a/.ghp/wix.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "react-native-navigation", - "description": "App-wide support for 100% native navigation with an easy cross-platform interface.", - "title": "React Native Navigation", - "github": "https://github.com/wix/react-native-navigation", - "AndroidVideoUrl": "https://github.com/wix/react-native/blob/master/src/videos/react-navigation-android.mp4?raw=true", - "IOSVideoUrl": "https://github.com/wix/react-native/blob/master/src/videos/react-navigation-iphone.mp4?raw=true", - "IOSDemoAppLink": "", - "image": "", - "poster": "https://github.com/wix/react-native/blob/master/src/img/react-native-navigation-poster.jpg?raw=true", - "size" : "normal", - "AndroidDemoAppLink": "" -} diff --git a/.github/CONTRIBUTING b/.github/CONTRIBUTING deleted file mode 100644 index 682d0643df1..00000000000 --- a/.github/CONTRIBUTING +++ /dev/null @@ -1 +0,0 @@ -Before contributing... diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE deleted file mode 100644 index cb2b756b4a4..00000000000 --- a/.github/ISSUE_TEMPLATE +++ /dev/null @@ -1,19 +0,0 @@ - - -### Issue Description - -[ENTER DESCRIPTION HERE - Please make sure to use the current [naming conventions](https://github.com/wix/react-native-navigation/issues/197)] - -### Steps to Reproduce / Code Snippets / Screenshots - -[FILL THIS OUT - It will be extremely helpful] - ---- -### Environment -* React Native Navigation version: FILL THIS OUT -* React Native version: FILL THIS OUT -* Platform(s) (iOS, Android, or both?): FILL THIS OUT -* Device info (Simulator/Device? OS version? Debug/Release?): FILL THIS OUT diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT_ANDROID.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT_ANDROID.yml new file mode 100644 index 00000000000..7752000ccdb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT_ANDROID.yml @@ -0,0 +1,46 @@ +name: "🐛 Bug Report - Android" +description: Create a report to help us improve React Native Navigation on Android +labels: ["type: accepted/bug", "platform: Android"] +body: + - type: markdown + attributes: + value: Thanks for taking the time to fill out this bug report! + - type: textarea + id: description + attributes: + label: What happened? + description: A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + id: expected-behaviour + attributes: + label: What was the expected behaviour? + description: A clear and concise description of what was expected to happen. + - type: checkboxes + id: tested-last-rnn + attributes: + label: Was it tested on latest react-native-navigation? + description: Before reporting this issue, please make sure it can be reproduced on the latest released version of react-native-navigation, see our [releases](https://github.com/wix/react-native-navigation/releases). + options: + - label: I have tested this issue on the latest react-native-navigation release and it still reproduces. + required: true + - type: textarea + id: reproduction + attributes: + label: Help us reproduce this issue! + description: "Paste the link to an example repo and exact instructions to reproduce the issue." + - type: textarea + id: environment + attributes: + label: In what environment did this happen? + description: "Include as many relevant details about the environment you experienced the bug in" + value: "React Native Navigation version: + \nReact Native version: + \nHas Fabric (React Native's new rendering system) enabled: (yes/no) + \nNode version: + \nDevice model: + \nAndroid version:" + - type: markdown + attributes: + value: "Remember that first-time contributors are welcome! 🙌 Feel free to reach us out on https://discord.gg/DhkZjq2 \nHave a great day and thank you for the bug report!" diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT_IOS.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT_IOS.yml new file mode 100644 index 00000000000..b7115a8676e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT_IOS.yml @@ -0,0 +1,46 @@ +name: "🐛 Bug Report - iOS" +description: Create a report to help us improve React Native Navigation on iOS +labels: ["type: accepted/bug", "platform: iOS"] +body: + - type: markdown + attributes: + value: Thanks for taking the time to fill out this bug report! + - type: textarea + id: description + attributes: + label: What happened? + description: A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + id: expected-behaviour + attributes: + label: What was the expected behaviour? + description: A clear and concise description of what was expected to happen. + - type: checkboxes + id: tested-last-rnn + attributes: + label: Was it tested on latest react-native-navigation? + description: Before reporting this issue, please make sure it can be reproduced on the latest released version of react-native-navigation, see our [releases](https://github.com/wix/react-native-navigation/releases). + options: + - label: I have tested this issue on the latest react-native-navigation release and it still reproduces. + required: true + - type: textarea + id: reproduction + attributes: + label: Help us reproduce this issue! + description: "Paste the link to an example repo and exact instructions to reproduce the issue." + - type: textarea + id: environment + attributes: + label: In what environment did this happen? + description: "Include as many relevant details about the environment you experienced the bug in" + value: "React Native Navigation version: + \nReact Native version: + \nHas Fabric (React Native's new rendering system) enabled: (yes/no) + \nNode version: + \nDevice model: + \niOS version:" + - type: markdown + attributes: + value: "Remember that first-time contributors are welcome! 🙌 Feel free to reach us out on https://discord.gg/DhkZjq2 \nHave a great day and thank you for the bug report!" diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT_OTHER.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT_OTHER.yml new file mode 100644 index 00000000000..c1bf70ee90d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT_OTHER.yml @@ -0,0 +1,44 @@ +name: "🐛 Bug Report - Other" +description: Report a non-platform-specific bug to help us improve +labels: ["type: accepted/bug", "needs triage"] +body: + - type: markdown + attributes: + value: Thanks for taking the time to fill out this bug report! + - type: textarea + id: description + attributes: + label: What happened? + description: A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + id: expected-behaviour + attributes: + label: What was the expected behaviour? + description: A clear and concise description of what was expected to happen. + - type: checkboxes + id: tested-last-rnn + attributes: + label: Was it tested on latest react-native-navigation? + description: Before reporting this issue, please make sure it can be reproduced on the latest released version of react-native-navigation, see our [releases](https://github.com/wix/react-native-navigation/releases). + options: + - label: I have tested this issue on the latest react-native-navigation release and it still reproduces. + required: true + - type: textarea + id: reproduction + attributes: + label: Help us reproduce this issue! + description: "Paste the link to an example repo and exact instructions to reproduce the issue." + - type: textarea + id: environment + attributes: + label: In what environment did this happen? + description: "Include as many relevant details about the environment you experienced the bug in" + value: "React Native Navigation version: + \nReact Native version: + \nHas Fabric (React Native's new rendering system) enabled: (yes/no) + \nNode version:" + - type: markdown + attributes: + value: "Remember that first-time contributors are welcome! 🙌 Feel free to reach us out on https://discord.gg/DhkZjq2 \nHave a great day and thank you for the bug report!" diff --git a/.github/ISSUE_TEMPLATE/ENHANCEMENT.yml b/.github/ISSUE_TEMPLATE/ENHANCEMENT.yml new file mode 100644 index 00000000000..f3e3c4a25bb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ENHANCEMENT.yml @@ -0,0 +1,30 @@ +name: "🚀 Feature" +description: Submit a proposal/request for a new feature +labels: ["type: enhancement", "needs triage"] +body: + - type: markdown + attributes: + value: Thanks for taking the time to fill out this enhancement suggestion! + - type: textarea + id: idea-description + attributes: + label: Describe your idea + description: "A clear and concise description of what you want to happen.\n + If your feature request is related to a problem, please describe any other alternative solutions or features you’ve considered." + - type: textarea + id: idea-motivation + attributes: + label: Motivation + description: (Please outline the motivation for the proposal.) + - type: checkboxes + id: contribution + attributes: + label: Are you willing to resolve this issue by submitting a Pull Request? + description: Select one. + options: + - label: "Yes, I have the time, and I know how to start." + - label: "Yes, I have the time, but I don't know how to start. I would need guidance." + - label: "No, I don’t have the time and I’m okay to wait for the community / maintainers to resolve this issue." + - type: markdown + attributes: + value: "Remember that first-time contributors are welcome! 🙌 Feel free to reach us out on https://discord.gg/DhkZjq2 \nHave a great day and thank you for the bug report!" diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..3ba13e0cec6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 00000000000..658004be97a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,13 @@ +--- +name: 📚 Documentation +about: Report an issue related to documentation +labels: 'triage: documentation, needs triage' +--- + +## 📚 Documentation + +(A clear and concise description of what the issue is.) + +- [ ] Have you read the [Contributing Guidelines on issues](https://wix.github.io/react-native-navigation/docs/meta-contributing)? + +(Write your answer here.) diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000000..045998e4a1b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,14 @@ +--- +name: ❓ Questions/Help +about: If you have questions, please check Stack Overflow or Discord +labels: 'type: question/stack overflow' +--- + +## ❓ Questions and Help + +### Please note that this issue tracker is not a help form and this issue will be closed. + +Please contact us instead. We have a few channels: + +- [Stack Overflow](https://stackoverflow.com/questions/tagged/wix-react-native-navigation) +- [Discord](https://discord.gg/DhkZjq2) diff --git a/.github/label-actions.yml b/.github/label-actions.yml new file mode 100644 index 00000000000..a242ad7bd88 --- /dev/null +++ b/.github/label-actions.yml @@ -0,0 +1,19 @@ +'type: question/stack overflow': + comment: | + We use the issue tracker exclusively for bug reports and feature requests. + This issue appears to be a general usage or support question. + Instead, please ask a question on Stack Overflow with the `wix-react-native-navigation` tag or on [Discord](https://discord.gg/DhkZjq2). + close: true + lock: false + +invalid: + comment: | + This issue did not follow one of the provided issue templates and was therefor closed. + + Please remember that: + + * Issues without reproducible demos have a very low priority. + * The person fixing the bug would have to do that anyway. Please be respectful of their time. + * You might figure out the issues yourself as you work on extracting it. + close: true + lock: false diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000000..3eec6a82d87 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,55 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 30 + +# Number of days of inactivity before a stale Issue or Pull Request is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 7 + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - "needs triage" + - "type: accepted/enhancement" + - "user: looking for contributors" + - "📌 pinned" + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: true + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Label to use when marking as stale +staleLabel: "🏚 stale" + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. + + If you believe the issue is still relevant, please test on the latest version and report back. + Thank you for your contributions. +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +closeComment: > + The issue has been closed for inactivity. +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +pulls: + daysUntilStale: 45 + markComment: > + This pull request has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# issues: +# exemptLabels: +# - confirmed diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000000..3d3c464b209 --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,57 @@ +name: documentation + +on: + pull_request: + branches: [master] + push: + branches: [master] + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + checks: + if: github.event_name != 'push' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: '16.x' + - name: Test Build + run: | + cd website/ + npm i + npm run build + gh-release: + if: github.event_name != 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: '16.x' + - name: Add key to allow access to repository + env: + SSH_AUTH_SOCK: /tmp/ssh_agent.sock + run: | + mkdir -p ~/.ssh + ssh-keyscan github.com >> ~/.ssh/known_hosts + echo "${{ secrets.GH_PAGES_DEPLOY }}" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + cat <> ~/.ssh/config + Host github.com + HostName github.com + IdentityFile ~/.ssh/id_rsa + EOT + - name: Release to GitHub Pages + env: + USE_SSH: true + GIT_USER: git + run: | + git config --global user.email "yogevbd@wix.com" + git config --global user.name "yogevbd" + cd website/ + npm i + npm run build + npx docusaurus deploy diff --git a/.github/workflows/process-label.yml b/.github/workflows/process-label.yml new file mode 100644 index 00000000000..eeeadf155e4 --- /dev/null +++ b/.github/workflows/process-label.yml @@ -0,0 +1,23 @@ +name: Process Label Action + +on: + issues: + types: labeled + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + processLabelAction: + permissions: + contents: read # to fetch code (actions/checkout) + issues: write # to close, comment, add labels to issues (hramos/label-actions) + + name: Process Label Action + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Process Label Action + uses: hramos/label-actions@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/require-label.yml b/.github/workflows/require-label.yml new file mode 100644 index 00000000000..f3092bfee5e --- /dev/null +++ b/.github/workflows/require-label.yml @@ -0,0 +1,13 @@ +name: Enforce PR label + +on: + pull_request: + types: [labeled, unlabeled, opened, edited, synchronize] + +jobs: + enforce-label: + runs-on: ubuntu-latest + steps: + - uses: yogevbd/enforce-label-action@2.2.2 + with: + REQUIRED_LABELS_ANY: "type: accepted/bug,type: accepted/enhancement,Infrastructure,type: documentation" diff --git a/.gitignore b/.gitignore index 23b427da3a0..c7a276a7644 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +dist +.history/ + +# Docusaurus +.docusaurus +.cache-loader ############ # Node @@ -208,12 +214,34 @@ npm-debug.log # BUCK buck-out/ \.buckd/ + +#IDE files android/app/libs android/keystores/debug.keystore - -# VSCODE -jsconfig.json -.vscode/launchReactNative.js -example/yarn.lock -example/package-lock.json -/package-lock.json +AndroidE2E/.project +AndroidE2E/app/.project +lib/android/.project +playground/android/.project +AndroidE2E/app/.classpath +AndroidE2E/app/.settings/ +AndroidE2E/app/bin/ +lib/android/.settings/ +lib/android/app/.settings/ +playground/android/.settings/ +playground/android/app/.settings/ +AndroidE2E/.settings/ +website/yarn.lock +playground/ios/Podfile.lock +website/package-lock.json + +# detox artifacts +artifacts/ + +# Navigation mocks +lib/Mock/*.js +lib/Mock/*.d.ts +Mock.js +Mock.d.ts + +Gemfile.lock +/playground/ios/.xcode.env.local diff --git a/.grenrc.js b/.grenrc.js new file mode 100644 index 00000000000..aa0ddebdf8a --- /dev/null +++ b/.grenrc.js @@ -0,0 +1,67 @@ +module.exports = { + template: { + commit: ({message, url, author, name}) => + `- [${message}](${url}) - ${author ? `@${author}` : name}`, + issue: ({name, labels, text, url, user_login, user_url}) => `${processLabels(labels)}${name} [${text}](${url}) by [${user_login}](${user_url})`, + label: '[**{{label}}**]', + noLabel: 'closed', + group: '\n## {{heading}}\n', + changelogTitle: '# Changelog\n\n', + release: '## {{release}} ({{date}})\n{{body}}', + releaseSeparator: '\n---\n\n', + }, + groupBy: { + 'Enhancements:': ['type: accepted/enhancement', 'internal'], + 'Fixed:': ['type: accepted/bug'], + Features: ['feature'], + }, + groupPostProcessor: (groupContent) => { + const lines = groupContent.split('\n'); + const iosIssues = []; + const androidIssues = []; + const otherIssues = []; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (line.includes('## ') || line === '') continue; + else if (line.includes('[iOS] ')) iosIssues.push(line.replace('[iOS] ', '')); + else if (line.includes('[Android] ')) androidIssues.push(line.replace('[Android] ', '')); + else otherIssues.push(line); + } + + const groupHeader = groupContent.substr(0, groupContent.indexOf(':\n')); + return `${groupHeader}${generateSection(undefined, otherIssues)}${generateSection('iOS', iosIssues)}${generateSection('Android', androidIssues)}`; + }, + ignoreIssuesWith: ['skip-changelog'], + ignoreTagsWith: ['snapshot', 'v1', 'v2', '0\..\..', '1\..\..', '2\..\..', '3\..\..', '4\..\..', '5\..\..', '6\..\..'], + dataSource: 'prs', + changelogFilename: 'CHANGELOG.gren.md', + override: true, + generate: true, + tags: 'all' +}; + +function generateSection(name, issues) { + if (!issues.length) return ''; + let section = `\n${name ? `### ${name}\n` : ''}`; + + issues.forEach(issue => { + section += `- ${issue}\n`; + }); + + return `${section}\n`; +} + +function processLabels(labels) { + const includesIOS = labels.includes('**platform: iOS**'); + const includesAndroid = labels.includes('**platform: Android**'); + if (includesIOS && includesAndroid) { + return ''; + } else if (includesIOS) { + return '[iOS] ' + } else if (includesAndroid) { + return '[Android] ' + } + + return ''; +} diff --git a/docs/_images/logo.png b/.logo.png similarity index 100% rename from docs/_images/logo.png rename to .logo.png diff --git a/.npmignore b/.npmignore index cb4c7822e12..8c5a69fa9f5 100644 --- a/.npmignore +++ b/.npmignore @@ -1,11 +1,21 @@ -example -old-example-redux - +AndroidE2E/ +coverage/ +e2e/ +integration/ +playground/ +artifacts/ +scripts/ +website/ +.travis.yml +wallaby.js +package-lock.json +.buildkite/ ################# # from .gitignore: ################ + ############ # Node ############ @@ -72,8 +82,6 @@ crashlytics.properties crashlytics-build.properties fabric.properties -./logo.png - ############ # iOS @@ -83,8 +91,8 @@ fabric.properties # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Build generated -ios/build/ -ios/DerivedData/ +lib/ios/build/ +lib/ios/DerivedData/ ## Various settings *.pbxuser @@ -95,11 +103,13 @@ ios/DerivedData/ !default.mode2v3 *.perspectivev3 !default.perspectivev3 -ios/xcuserdata/ +lib/ios/xcuserdata/ ## Other *.moved-aside *.xcuserstate +.github/ +docs/ ## Obj-C/Swift specific *.hmap @@ -113,7 +123,7 @@ ios/xcuserdata/ # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # -ios/Pods/ +lib/ios/Pods/ # Carthage # @@ -147,29 +157,30 @@ fastlane/screenshots *.class # Generated files -android/bin/ -android/gen/ -android/out/ -android/app/build/ +lib/android/bin/ +lib/android/gen/ +lib/android/out/ # Gradle files -android/.gradle/ -android/build/ +lib/android/.gradle/ +lib/android/build/ +lib/android/app/build/ +lib/android/app/src/test # Local configuration file (sdk path, etc) local.properties # Proguard folder generated by Eclipse -android/proguard/ +lib/android/proguard/ # Log Files *.log # Android Studio Navigation editor temp files -android/.navigation/ +lib/android/.navigation/ # Android Studio captures folder -android/captures/ +lib/android/captures/ # Intellij *.iml @@ -218,6 +229,37 @@ npm-debug.log # BUCK buck-out/ \.buckd/ -android/app/libs -android/keystores/debug.keystore - +lib/android/app/libs +lib/android/keystores/debug.keystore + +# Tests +**/*.test.js +**/*.test.jsx +**/*.test.ts +**/*.test.d.ts +**/*.test.tsx + +# TS configs +tsconfig.build.json +tsconfig.json +tsconfig-strict.json +tslint.json + +# Eslint +.eslintignore +.eslintrc.js + +# Docs +CONTRIBUTING.md + +# Editor +.vscode +jsconfig.json + +# Other +babel.config.js +.watchmanconfig +.logo.png +.grenrc.js +.clang-format +.prettierrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..abaf5ae7b53 --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +legacy-peer-deps=true +registry=https://registry.npmjs.org +strict-ssl=true diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000000..209e3ef4b62 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000000..cbd1fe375e6 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": true, + "singleQuote": true, + "trailingComma": "es5", + "printWidth": 100 +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e1742bb3678..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,47 +0,0 @@ -language: java - -jdk: - - oraclejdk8 - -env: - global: - - NODE_VERSION=stable - - PATH=$PATH:$HOME/.yarn/bin - - ANDROID_HOME=$HOME/android-sdk-linux - - PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools - -git: - depth: 3 - -branches: - only: - - master - -cache: - yarn: true - directories: - - $HOME/.gradle/ - - $HOME/.m2 - - $ANDROID_HOME/licenses/ - -before_cache: - - rm -rf $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -rf $HOME/.gradle/caches/*/plugin-resolution/ - -install: - - set -e - - nvm install $NODE_VERSION - - curl -o- -L https://yarnpkg.com/install.sh | bash - - ./scripts/clean.sh - - yarn install - -script: - - yarn run lint - - yarn run test:js - - ./scripts/installAndroidSDK.sh - - yarn run test:android - - yarn run release - - set +e - -after_script: - - echo "BUILD FINISHED" diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..e6273c1ba74 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "editor.formatOnSave": true, + "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"], + "eslint.enable": true, + "typescript.tsdk": "node_modules/typescript/lib", +} diff --git a/.watchmanconfig b/.watchmanconfig index 48802ff2ea4..0967ef424bc 100644 --- a/.watchmanconfig +++ b/.watchmanconfig @@ -1,15 +1 @@ -{ - "ignore_dirs": [ - ".git", - "node_modules", - ".gradle", - ".idea", - "gradle", - "build", - "example", - "example-redux", - "android/.gradle", - "android/gradle", - "android/app/build" - ] -} +{} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000000..2542add76f3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1854 @@ +>⚠️ This changelog is no longer maintained. Release notes can be found [here](https://github.com/wix/react-native-navigation/releases). +___ +# Changelog + +# 7.0.0 + +This release mainly focuses on adding support for TurboModules (Integrating Reanimated2 is now possible!) and aligning the Navigation commands API once and for all. + +## Key Features + +- Support TurboModules (and Reanimated v2) +- New layout system on iOS. Layout insets are now handled via constraints and safeAreaLayoutGuide instead of margins and edgesForExtendedLayout as per Apple's recommendations. This is not a breaking change and is done in preparation to deprecate the `bottomTabs.drawBehind` option on iOS. +- Deprecate registerComponentWithRedux. [registerComponent with providers](https://wix.github.io/react-native-navigation/api/component#registering-a-component-wrapped-with-providers) should be used instead. +- Align promise results of all Navigation commands on both iOS and Android + +## Upgrading from v6 + +### iOS + +Add `extraModulesForBridge` in `AppDelegate.m` + +```objc +- (NSArray> *)extraModulesForBridge:(RCTBridge *)bridge { + return [ReactNativeNavigation extraModulesForBridge:bridge]; +} +``` + +In case your'e bootstraping ReactNativeNavigation like that: +```objc +[ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions]; +``` + +Replace it with +```objc +[ReactNativeNavigation bootstrapWithDelegate:self launchOptions:launchOptions]; +``` + +> **If on upgrading you experience the error:** +> +>Specs satisfying the ReactNativeNavigation (from ../node_modules/react-native-navigation) dependency were found, but they required a higher minimum deployment target. +> +>Please update your Podfile deployment target to at least 11.0: +>``` +>platform :ios, '11.0' +>``` + +### Android + +No Changes needed 🥳 + +## Breaking changes + +- Starting from this version, both `modalDismissed` and `modalAttemptedToDismiss` events can no longer be handled in components. Handling them is only supported via the `Navigation.events()` api. +- `dismissModal` promise is resolved with the id of the root layout. For example, if a modal which contains a stack and a few children was dismissed, the `Navigation.dismissModal()` promise will be resolved with the stack's id. +- Change Navigation commands promise resolve type from any to string + +### iOS + +- The default value of `sideMenu.openGestureMode` is now `bezel`. Up until now `entireScreen` was the default value which made it difficult for users to interact with scrollable components, Carousel for instance, as the SideMenu intercepted the scroll events. The `bezel` option solves this issue as the SideMenu will respond only to touch events from the edge of the screen. +- Resolve all Navigation commands with id of root layout instead of actual layout. +- Resolve push command promise with id of pushed layout instead of current layout. + +### Android + +- `fab.id` is mandatory. We plan to rework some of the native components on Android, mainly Fab and BottomTabs. This change is mostly a cosmetic change needed for future work on Fab. + +## Changes + +### Added + +- allow assigning OpaqueColorValue as a color [#8f67d9f](https://github.com/wix/react-native-navigation/commit/8f67d9f2dced62b441bcce4ab6e9e21ee62eb177) by [danilobuerger](https://github.com/danilobuerger) + +#### Android + +- Support PlatformColor [#d7ba3ff](https://github.com/wix/react-native-navigation/commit/d7ba3ffc19c88b313729757d158b4495f9f97d29) by [danilobuerger](https://github.com/danilobuerger) + +### Fixes + +- Recreate wrapped component on re-register component [#12a615b](https://github.com/wix/react-native-navigation/commit/12a615bd70112571a43f73463376c7a9cfc683ec) by [danilobuerger](https://github.com/danilobuerger) +- Calling UpdateProps multiple times does not discard previous props [#fff6d23](https://github.com/wix/react-native-navigation/commit/fff6d23c8b6d380ac50f9b1c1af03d254ba3dd65) by [jinshin1013](https://github.com/jinshin1013) +- Fix props type passed to options function in `NavigationFunctionalComponent` interface [#a3a796a](https://github.com/wix/react-native-navigation/commit/a3a796ae0c7c6a5341cdf3f7db06acc01377e0c2) by [mrousavy](https://github.com/mrousavy) + +#### iOS + +- Fix options not being applied on large title [#e845afe](https://github.com/wix/react-native-navigation/commit/e845afecaeea16dc92ef2461038079eab1e09a6f) by [yogevbd](https://github.com/yogevbd) +- Fix crash after calling setStackRoot and pressing the back button [#8a7d34b](https://github.com/wix/react-native-navigation/commit/8a7d34b22a1226cab7ad03e58a858d2ab4ea43fb) by [yogevbd](https://github.com/yogevbd) +- Initialize UIWindow only if needed [#e5cc0c3](https://github.com/wix/react-native-navigation/commit/e5cc0c3594b495f89b4912f2019be8fec2499fcd) by [danilobuerger](https://github.com/danilobuerger) +- Change default modalPresentationStyle from overFullScreen to fullScreen on iOS 12 and below [#0869fd0](https://github.com/wix/react-native-navigation/commit/0869fd0197a621123ae16e183965dd05fdf4521d) by [danilobuerger](https://github.com/danilobuerger) +- Don't crash if specified Shared Element ID could not be found/invalid nativeID has been set [#fcf23d2](https://github.com/wix/react-native-navigation/commit/fcf23d2e283e4031767864f6360051d9326c2475) by [mrousavy](https://github.com/mrousavy) +- Fix edge case where title wasn't visible if subtitle was also declared [#1878393](https://github.com/wix/react-native-navigation/commit/1878393eb05d42bbb2099567a55cc35d6fc61595) by [yogevbd](https://github.com/yogevbd) +- Fix Bicolor status bar disappears on setRoot [#83a5afa](https://github.com/wix/react-native-navigation/commit/83a5afa84b3ed79284a1c28c4634506d0641df02) by [yogevbd](https://github.com/yogevbd) +- Remove obsolete bootstrap methods [#5c5ec9e](https://github.com/wix/react-native-navigation/commit/5c5ec9e04901b5825953e6c9e3bcb587a45984cd), [#8d9e358](https://github.com/wix/react-native-navigation/commit/8d9e35895712d8c5f6685a6f92c93429246ebb96) by [danilobuerger](https://github.com/danilobuerger) +- Support fade animation in setRoot [#acc7f12](https://github.com/wix/react-native-navigation/commit/acc7f1276803d6bdb7fa5e1affc9f958d9923466) by [yogevbd](https://github.com/yogevbd) +- Properly resolve fontFamily and fontWeight [#a3e8189](https://github.com/wix/react-native-navigation/commit/a3e8189d3725a292277c138a3da234b7864fc131) by [yogevbd](https://github.com/yogevbd) +- Fix crash when navigating to a screen without a TopBar title text from a screen with LargeTitle [#0c9c996](https://github.com/wix/react-native-navigation/commit/0c9c99691909c292f69aca16738a0aba97630e5c) by [mateioprea](https://github.com/mateioprea) +- Fix border being visible when LargeTitle is used even though `noBorder:true` was specified [#29365dc](https://github.com/wix/react-native-navigation/commit/29365dc86d92f7de2bf94231b0d59d3e2bf6c073) by [mateioprea](https://github.com/mateioprea) + +#### Android + +- Fixed animating images with different `scaleType` in Shared Element Trnaisiton [#382e69a](https://github.com/wix/react-native-navigation/commit/382e69abddf5eae95969e12e648f04197a7b2a89) by [guyca](https://github.com/guyca) + +# 6.12.0 + +## Added + +### iOS + +- Enable PlatformColor / DynamicColorIOS for iOS [#57519ca](https://github.com/wix/react-native-navigation/commit/57519cab1cac1a4c6ebe9165db3bd4a4449d3720) by [danilobuerger](https://github.com/danilobuerger) + +## Fixed + +- Fix option processors path resolving [#f37d465](https://github.com/wix/react-native-navigation/commit/f37d465dd7339f4e9eca4e6c27be883e711b7ff2) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Fix white screen when back was pressed during show modal animation [#58f72f8](https://github.com/wix/react-native-navigation/commit/58f72f8033f703b1f83c935fce7c70e67dd9b5c2) by [guyca](https://github.com/guyca) +- Fix issue where right buttons which were added with mergeOptions were not unmounted [#3c5e8e4](https://github.com/wix/react-native-navigation/commit/3c5e8e4454edef3220fa9f40025b6703446d76fa) by [guyca](https://github.com/guyca) +- Resole popToRoot promise successfully even when it's called while there's nothing to pop [#ec2b0a0](https://github.com/wix/react-native-navigation/commit/ec2b0a0e367f99807c0c67068cbcff40e6cb23a7) by [guyca](https://github.com/guyca) +- Resize title component when buttons are added to TopBar [#a66e8e9](https://github.com/wix/react-native-navigation/commit/a66e8e93b456ec911aed7a5a49c14ea0a689c0b9) by [guyca](https://github.com/guyca) + +### iOS + +- Fix bug where screen became unresponsive if user tried to interact with elements during momentum scroll [#cb74af5](https://github.com/wix/react-native-navigation/commit/cb74af57f0bea7f2a4517e1f7b14959af8a79f20) by [yogevbd](https://github.com/yogevbd) +- Fix category warnings for RNNInterpolationOptions [#a13698b](https://github.com/wix/react-native-navigation/commit/a13698b0863c46fc2f708e7e6eae3f37d5f55237) by [danilobuerger](https://github.com/danilobuerger) + +# 6.11.0 + +## Added + +- Update NavigationComponent typings - include passProps in static options generate [#813c1a2](https://github.com/wix/react-native-navigation/commit/813c1a271225a802c9f828aae798a22c47e9752d) by [guyca](https://github.com/guyca) +- Include componentId in props passed to static options generator [#c4f8eb2](https://github.com/wix/react-native-navigation/commit/c4f8eb2932a9cdb85686339282ca6cc97c6918ce) by [guyca](https://github.com/guyca) + +### iOS + +- Add primaryBackgroundStyle option to splitView [#9ba863a](https://github.com/wix/react-native-navigation/commit/9ba863a5090c636c47939a709c5b8e4e81767421) by [frane](https://github.com/frane) + +## Fixed + +### iOS + +- Fixed case where options were not merged correctly under certain conditions [#c9e5309](https://github.com/wix/react-native-navigation/commit/c9e5309f87bdae31cd2d90a51ead201b297bbf94) by [yogevbd](https://github.com/yogevbd) +- Fix toggling StatusBar visibility with mergeOptions [#36e0e81](https://github.com/wix/react-native-navigation/commit/36e0e81dfb796406f7a0be3861178eaa2b1c2cd5) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Fix button fontSize being applied in pixels instead of dp [#8d1309f](https://github.com/wix/react-native-navigation/commit/8d1309f4be88215d6c2e67a19475c88a39d3ff98) by [guyca](https://github.com/guyca) + +# 6.10.0 + +## Added + +- New Options Processor API [#1d4d054](https://github.com/wix/react-native-navigation/commit/1d4d05460f323e31ccc87f614560f82876baa50c) by [yogevbd](https://github.com/yogevbd) + +- New Layout Processor API [#4f4a04e](https://github.com/wix/react-native-navigation/commit/4f4a04e25c2d64052810b75cda1e51aafc0f1a08) by [yogevbd](https://github.com/yogevbd) + +- Type component options in NavgationComponent and NavigationFunctionalComponent [#b23ab25](https://github.com/wix/react-native-navigation/commit/b23ab2598225466e1e49d7f7dd73c696060fed98) + +### Android + +- Support Shared Element Transition in pop [#80a52a2](https://github.com/wix/react-native-navigation/commit/80a52a23f6d3143de10421c036c2ed9deb152589) by [guyca](https://github.com/guyca) + +- Add allCaps option to TopBar buttons [#a561a80](https://github.com/wix/react-native-navigation/commit/a561a80e9dd36d5cf40b9952cab022583ed9bee5) by [guyca](https://github.com/guyca) + +### iOS + +- Deprecate toggling BottomTabs on iOS [#aaef66b](https://github.com/wix/react-native-navigation/commit/aaef66b56ced621c48252d6d11a59fb3f4a1d776) by [yogevbd](https://github.com/yogevbd) + +- Fabric support [#6ecdb51](https://github.com/wix/react-native-navigation/commit/6ecdb515bd1c06a923987eefcad99d02f66c3bbc) by [ericlewis](https://github.com/ericlewis) + +## Fixed + +### Android + +- Fix overlay touch detection [#5e03718](https://github.com/wix/react-native-navigation/commit/5e0371885db750844989981db53c0929e98d9baf) by [guyca](https://github.com/guyca) + +- Fix flickering BottomTabs when pushing a screen with waitForRender [#7add403](https://github.com/wix/react-native-navigation/commit/7add403d39a3d6eceef7c3c28443be425ecec9ef) by [guyca](https://github.com/guyca) + +### iOS + +- Support calling setDefaultOptions before appLaunch event is emitted [#87e7b1a](https://github.com/wix/react-native-navigation/commit/87e7b1afa280e6788385f3fcbd29350f9149a839) by [yogevbd](https://github.com/yogevbd) + +# 6.9.1 + +## Fixed + +### Android + +- Fix changing disabled button color [#1b291c6](https://github.com/wix/react-native-navigation/commit/1b291c63458052e44ef6b03ff7daf7e4d3dd84a4) by [guyca](https://github.com/guyca) + +# 6.9.0 + +## Added + +- Introduced a new API to lazily register components [#81c0f87](https://github.com/wix/react-native-navigation/commit/81c0f8715f194670865e239ab6539c595b441924) by [yedidyak](https://github.com/yedidyak) + +## Fixed + +### Android + +- Emit componentDidAppear after appear animation completes [#b9310bf](https://github.com/wix/react-native-navigation/commit/b9310bf7545d1c15b2f716a98aaab3eb34b4b504) by [guyca](https://github.com/guyca) +- Fix overflow menu item text color affected by `button.color` option [#2f0095f](https://github.com/wix/react-native-navigation/commit/2f0095fa238cb3f7109fa1756da1593be0ec2d3d) by [guyca](https://github.com/guyca) + +### iOS + +- Fix incorrect SideMenu dimensions after orientation change [#22444b1](https://github.com/wix/react-native-navigation/commit/22444b1fc27f0dcf1a59885ec5f5656b241790c6) by [yogevbd](https://github.com/yogevbd) +- Fix back button testID option not being applied [#9676e9c](https://github.com/wix/react-native-navigation/commit/9676e9cd7895fa76c6c30254068038f1de720109) by [yogevbd](https://github.com/yogevbd) + +# 6.8.0 + +## Added + +- Proper error handling in link script [#daa48ca](https://github.com/wix/react-native-navigation/commit/daa48caa44831efdb60a6b394eb56cf6a94b4f9f) by [eduardopelitti](https://github.com/eduardopelitti) +- Replace deprecated link process [#4c3ed45](https://github.com/wix/react-native-navigation/commit/4c3ed4511a3a7f81586705b24b36e84e21436980) by [eduardopelitti](https://github.com/eduardopelitti) +- Add NavigationFunctionComponent interface [#c56630e](https://github.com/wix/react-native-navigation/commit/c56630e1ca7ed6575ac49c0c0c53a32b7ac3ff05) by [elizabeth-dev](https://github.com/elizabeth-dev) +- Export EventsRegistry [#057f11b](https://github.com/wix/react-native-navigation/commit/057f11b8eb6180066d719e83b9a8f39fe567d1b0) by [yedidyak](https://github.com/yedidyak) + +### Android + +- Implement bottomTabs.hideOnScroll [#9544f41](https://github.com/wix/react-native-navigation/commit/9544f412e88505dec5aee4472b736689a0fe249a) by [guyca](https://github.com/guyca) + +## Fixed + +- Fix updateProps creating new props object [#b1a1e0d](https://github.com/wix/react-native-navigation/commit/b1a1e0d9ee5e00cd6c71ec3df2c8cc0c2c18fb7f) by [jinshin1013](https://github.com/jinshin1013) + +### iOS + +- Fixes badgeColor not being applied on ios 13+ [#28928e5](https://github.com/wix/react-native-navigation/commit/28928e567edac38a99c9aa71e3749e2e32364ec5) by [DaveAdams88](https://github.com/DaveAdams88) +- Fix black/white flickering when dismissing modals [#fd38fff](https://github.com/wix/react-native-navigation/commit/fd38fffeebbfca8edd8ddebccb4002c3349e5e9f) by [simonmitchell](https://github.com/simonmitchell) +- Fix registerBottomTabSelectedListener unselected value [#fbb72f2](https://github.com/wix/react-native-navigation/commit/fbb72f25df7097f5345d4e769b8cb736e2145785) by [yogevbd](https://github.com/yogevbd) +- Fix bottomTabs long press event [#814de45](https://github.com/wix/react-native-navigation/commit/814de45558a2bc250acc9c496e3974b54888592a) by [yogevbd](https://github.com/yogevbd) +- Fix hiding the SearchBar on iOS 11+ [#58674e8](https://github.com/wix/react-native-navigation/commit/58674e8baf06b09187039897a6ba27aff99ec8cb) by [jinshin1013](https://github.com/jinshin1013) + +### Android + +- Don't create Navigator if the Activity is finishing [#5c6ccd1](https://github.com/wix/react-native-navigation/commit/5c6ccd12c62190edbef4a614b24374b2402ac90c) by [JK0N](https://github.com/JK0N) +- Fix crash when disabledButtonColor is undefined and attempting to show a disabled button [#3fae8ed](https://github.com/wix/react-native-navigation/commit/3fae8ededc31e4d10e9e4153a614e9f3d159d650) by [guyca](https://github.com/guyca) +- TopBar title and subtitle font size is measured in dp instead of sp [#88e65de](https://github.com/wix/react-native-navigation/commit/88e65defb91e30292e73d228f602b126e1064b59) by [guyca](https://github.com/guyca) +- Fix crash when currentTabIndex is defined [#fbe81d0](https://github.com/wix/react-native-navigation/commit/fbe81d05b5074e82e32c08456b9688cf8c9f4a25) by [guyca](https://github.com/guyca) + +# 6.7.5 + +## Fixed + +- Fix TypeScript compilation errors [#2225e97](https://github.com/wix/react-native-navigation/commit/2225e971265a58fec7715630d782d8a8845f48fa) by [ItsNoHax](https://github.com/ItsNoHax) + +# 6.7.4 + +## Fixed + +### iOS + +- Fix wrong options being applied when selected tab changes [#bd710bc](https://github.com/wix/react-native-navigation/commit/bd710bc0bd91ebdc41c3ebca6cf79ad84b91738e) by [yogevbd](https://github.com/yogevbd) + +# 6.7.3 + +## Fixed + +### iOS + +- Restore bottomTabs visibility when needed [#80eb489](https://github.com/wix/react-native-navigation/commit/80eb4893ef2c86c2e20480c61c03fc2dc99979f1) by [yogevbd](https://github.com/yogevbd) + +# 6.7.2 + +## Fixed + +### iOS + +- Fix BottomTabs visibility not working for pushed screens and mergeOptions [#ab63850](https://github.com/wix/react-native-navigation/commit/ab63850a405d01d40689478b3f408fc30ab1d382) by [yogevbd](https://github.com/yogevbd) + +# 6.7.0 - 6.7.1 + +## Added + +- Export TypeScript interfaces to streamline work with NavigationComponent + introduce `Navigation.events().registerComponentListener()` api [#ec7f324](https://github.com/wix/react-native-navigation/commit/ec7f32404d1a8cba79517f12c36eccaa4b13d3e2) by [yogevbd](https://github.com/yogevbd) + +## Fixed + +- Unmount previous root before resolving setRoot promise [#86b344c](https://github.com/wix/react-native-navigation/commit/86b344c7a287815a79891d7a9491c893c8081339) by [guyca](https://github.com/guyca) and [yogevbd](https://github.com/yogevbd) +- Ensure component generator passed to Navigation.registerComponent is invoked only once [#8ec7bcd](https://github.com/wix/react-native-navigation/commit/8ec7bcd83ae7fc721ce026cd11fb62df136edeac) by [guyca](https://github.com/guyca) + +### Android + +- Fix updating button options with mergeOptions [#b2df65a](https://github.com/wix/react-native-navigation/commit/b2df65a5fb245f123ea96cd2785ebc065cb065ea) by [guyca](https://github.com/guyca) +- Fix react-native-youtube support [#4d8d2ae](https://github.com/wix/react-native-navigation/commit/4d8d2ae40a0455fb5187cb965213fe350052bc50) by [guyca](https://github.com/guyca) +- Fix sideMenu.enabled option getting cleared when set on one drawer and the other drawer is opened [#67191e9](https://github.com/wix/react-native-navigation/commit/67191e9e7c915d612f83136e47000ed6311591e1) by [guyca](https://github.com/guyca) +- Mount all stack children after initial child is mounted [#a1beebe](https://github.com/wix/react-native-navigation/commit/a1beebe74beb265ed196e9e322a85aa40b84aa98) by [guyca](https://github.com/guyca) +- Fix flickering FAB when changing bottom tabs [#9a8bc54](https://github.com/wix/react-native-navigation/commit/9a8bc54dd41f91fbc90c3d8e44f02884dcdaa02c) by [guyca](https://github.com/guyca) +- Fix touch handling in nested Touchables in an Overlay [#851703c](https://github.com/wix/react-native-navigation/commit/851703c0caa75e4b6d8ad66f672ad0dc855842c4) by [guyca](https://github.com/guyca) + +### iOS + +- Send screen popped event only for rnn components [#0b7507d](https://github.com/wix/react-native-navigation/commit/0b7507d75f05590af7c933d5949b01aa7db04993) by [yogevbd](https://github.com/yogevbd) +- Fix bottomTabs visibility issues [#4e1ac71](https://github.com/wix/react-native-navigation/commit/4e1ac713944373d8d2c5b251912e1a872b2d00a7) by [yogevbd](https://github.com/yogevbd) + +# 6.6.0 + +## Fixed + +### Android + +- Fix showing Modal from TopBar components in RN 62 [94862ed](https://github.com/wix/react-native-navigation/commit/94862ed66883646d636be95aeaaccd40394b8082) by [guyca](https://github.com/guyca) + +# 6.5.0 + +## Added + +### Android + +- Added `width` and `height` options to button component which can be used to set exact measurements to button components [#42a6917](https://github.com/wix/react-native-navigation/commit/42a6917eeee149f7348a4eaf524ba76bac1240cf) by [guyca](https://github.com/guyca) +- Reuse button component if a component with the same id already exists [#42a6917](https://github.com/wix/react-native-navigation/commit/42a6917eeee149f7348a4eaf524ba76bac1240cf) by [guyca](https://github.com/guyca) +- Allow hiding the NavigationBar [#7f6353b](https://github.com/wix/react-native-navigation/commit/7f6353bcead9c6d6e87d72574e0fec29ad9f2d19) by [M-i-k-e-l](https://github.com/M-i-k-e-l) +- Support `rotation` animation in shared element transition [#03dd211](https://github.com/wix/react-native-navigation/commit/03dd211a5425cf14586ef49814c1d3716aeb8441) by [guyca](https://github.com/guyca) +- Implement shared element transition `interpolation` option [#e80eb92](https://github.com/wix/react-native-navigation/commit/e80eb9275a04921976127f8c2775f37088f133c1) by [guyca](https://github.com/guyca) +- Implement shared element transition `startDelay` option [#334ab71](https://github.com/wix/react-native-navigation/commit/334ab7174a599f18af66eca6cee7409bee7537e7) by [guyca](https://github.com/guyca) + +### iOS + +- Implement rotate animation for shared element transition [#5d9e910](https://github.com/wix/react-native-navigation/commit/5d9e9100b771ca76ac20b916f945406460084b9b) by [yogevbd](https://github.com/yogevbd) + +## Fixed + +### iOS + +- Fixed invalid modalPresentationStyle.popover enum value [#951a07b](https://github.com/wix/react-native-navigation/commit/951a07bb5571dbda2a0c9b665969bc25fc5ae784) by [rfnd](https://github.com/rfnd) +- Fix incorrect layout after changing BottomTabs visibility [#21cafcd](https://github.com/wix/react-native-navigation/commit/21cafcdecca8264dd2157d172dab24d8d4b5b4e6) by [yogevbd](https://github.com/yogevbd) +- Fix SafeAreaView measurement in SideMenu [#0da097e](https://github.com/wix/react-native-navigation/commit/0da097ef8471670e6550152fa5ebbdf4a02b3478) by [rfnd](https://github.com/rfnd) +- Fix backButton.color change on mergeOptions [#da0fd19](https://github.com/wix/react-native-navigation/commit/da0fd194f88b8f1042a0fe74bbf91e75ffac95b3) by [yogevbd](https://github.com/yogevbd) +- Fix bottomTab colors in landscape orientation [#89402dc](https://github.com/wix/react-native-navigation/commit/89402dc31a3769b4fb1326b95170961497011caf) by [yogevbd](https://github.com/yogevbd) +- FIx screenPopped event not emitted if screen is popped with pop command [#2f31a2f](https://github.com/wix/react-native-navigation/commit/2f31a2fa703659f153162274c846a8f137ee94d1) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Set textual TopBar button style options by spans instead of applying them on the view [#42a6917](https://github.com/wix/react-native-navigation/commit/42a6917eeee149f7348a4eaf524ba76bac1240cf) by [guyca](https://github.com/guyca) +- Ensure Component layout is not created prematurely by mergeOptions [#111df5a](https://github.com/wix/react-native-navigation/commit/111df5a3ba51ba6762cffd7119071bb4f71d18f7) by [guyca](https://github.com/guyca) +- Resolve tabsAttachMode from default options [#a4b2c76](https://github.com/wix/react-native-navigation/commit/a4b2c76a9d9b934192a4deee496c3ecef4c184ff) by [guyca](https://github.com/guyca) +- Support declaring currentTabIndex and currentTabId in default options [#3e5be29](https://github.com/wix/react-native-navigation/commit/3e5be29af8b1b78be1eec9ebf970b9204354a052) by [guyca](https://github.com/guyca) +- Fix BottomTabs size not adjusted after orientation change [#aa7908c](https://github.com/wix/react-native-navigation/commit/aa7908c57d141c7bb49de64a8e071330a8f7af31) by [guyca](https://github.com/guyca) + +# 6.4.0 + +## Fixed + +### iOS + +- Fix styling options on iOS 13.4 [#950ac64](https://github.com/wix/react-native-navigation/commit/950ac6404fe1a43021426803d4fdad4ed4711476) by [yogevbd](https://github.com/yogevbd) +- Fix white flicker when pushing a screen [#a2bdfac](https://github.com/wix/react-native-navigation/commit/a2bdfacb27065f2101c3228df98484ba4ec68e03) by [RobertPaul01](https://github.com/RobertPaul01) +- Fix white topBar on pop with swipe gesture [#6227321](https://github.com/wix/react-native-navigation/commit/62273214f0590007ce81be2aef6da1f05e035c4a) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Fix title component not being replaced via mergeOptions [#b0e8a82](https://github.com/wix/react-native-navigation/commit/b0e8a824f5e1ec141c9d3030dc21f242902ec29f) by [guyca](https://github.com/guyca) + +# 6.3.3 + +## Fixed + +### iOS + +- Fix status bar visibility on iOS 13 [#f487134](https://github.com/wix/react-native-navigation/commit/f487134d8e4c302f69453c093c49fde17dba46fe) by [yogevbd](https://github.com/yogevbd) + +# 6.3.1 - 6.3.2 + +## Added + +- Custom component reference id OptionsTopBarButton typing [#6046372](https://github.com/wix/react-native-navigation/commit/60463729e5e4ace5c4c81ddc854ee2421b431c86) by [jarnove](https://github.com/jarnove) + +## Fixed + +### Android + +- Always resolve dismissAllModals promise [#ec03383](https://github.com/wix/react-native-navigation/commit/ec03383b0de4fe092ddbef807850d131a42a1e7f) [#52bcd5b](https://github.com/wix/react-native-navigation/commit/52bcd5ba5090622db37055d0a18cb673673affa0) by [guyca](https://github.com/guyca) + +# 6.3.0 + +## Fixed + +### iOS + +- Fix symbol collision with react-native-keyboard-input [#8ad40e1](https://github.com/wix/react-native-navigation/commit/8ad40e1ab23116d432e888801c07b57c6c09ad37) by [yogevbd](https://github.com/yogevbd) +- Fix overlays touch interception on new iPads [#2ed434c](https://github.com/wix/react-native-navigation/commit/2ed434c952b7c9326d9547005caa8c0601e58cb4) +- Removes unable to find UIManager module warning [#ba12604](https://github.com/wix/react-native-navigation/commit/ba1260402cc15409ddfef46fd5cad180d5e1a60f) +- Reject pop command when viewController not found in the hierarchy [#4413aa4](https://github.com/wix/react-native-navigation/commit/4413aa4a76628449116cf9bc7294696a490d6a65) +- Fix mergeOptions merging options with wrong child [#3c38c50](https://github.com/wix/react-native-navigation/commit/3c38c50a8b53e958a21e6fb7453622463e9870ff) +- Fix build warnings and possible retain cycles issues [#3f8577d](https://github.com/wix/react-native-navigation/commit/3f8577da7d23a2e4698d27d12bf9de55be39e7ef) +- Fix bottomTab icon hidden after setting badge [#124f975](https://github.com/wix/react-native-navigation/commit/124f975f42ebaf124d9e7c58296eaafd0f617ad9) by [yogevbd](https://github.com/yogevbd) + +# 6.2.0 + +## Added + +- Add windows support to build scripts vai `npm run start-windows` command [#afb5bff](https://github.com/wix/react-native-navigation/commit/afb5bffb49b9e8c670419aaacedf10f65cf82fd2) by [mayconmesquita](https://github.com/mayconmesquita) + +## Fixed + +### iOS + +- Fix largeTitle background color on iOS 13 no being applied [#979cb6e](https://github.com/wix/react-native-navigation/commit/979cb6e08f80bd0b6b8e9286eb21d3c255c88312) by [yogevbd](https://github.com/yogevbd) +- Fix bottomTabs attach mode not working when BottomTabs are inside SideMenu [#7d6029f](https://github.com/wix/react-native-navigation/commit/7d6029f06bd3b4f4336d0d50a1621a5291e43fa7) by [yogevbd](https://github.com/yogevbd) +- Fix crash on iOS 10 when displaying stack layouts [#e923b8c](https://github.com/wix/react-native-navigation/commit/e923b8c02204e31d1ce6781dab11ebeabc2af218) [RomualdPercereau](https://github.com/RomualdPercereau) + +# 6.1.2 + +## Fixed + +### iOS + +- Fix modal presentation style not being applied on some layouts [#931167e](https://github.com/wix/react-native-navigation/commit/931167e039000502d4198244c450dacce3c39809) by [yogevbd](https://github.com/yogevbd) +- Fix truncated bottomTab.text with semibold fontWeight [#b01629c](https://github.com/wix/react-native-navigation/commit/b01629c41da9197ee0737c937c02684c73dd9042) by [yogevbd](https://github.com/yogevbd) +- Always drawBehind bottomTabs and topBar when translucent: true [#6edbbf5](https://github.com/wix/react-native-navigation/commit/6edbbf512f2230ee0bceaf73c7895bca90475700) by [yogevbd](https://github.com/yogevbd) +- drawBehind when largeTitle is visible - fixes black large title [#6edbbf5](https://github.com/wix/react-native-navigation/commit/6edbbf512f2230ee0bceaf73c7895bca90475700) by [yogevbd](https://github.com/yogevbd) + +# 6.1.1 + +## Fixed + +### iOS + +- Create new UITabBarItem instance on each bottomTab update [#3757ff7](https://github.com/wix/react-native-navigation/commit/3757ff7aa64cc9b6b8054af3e27b3865e27b2f9f) by [yogevbd](https://github.com/yogevbd) +- Delete duplicate misplaced files in root directory [#6d61ec0](https://github.com/wix/react-native-navigation/commit/6d61ec0e6cabeddc41b5860b4cb5b24f3de92dc2) by [ItsNoHax](https://github.com/ItsNoHax) + +# 6.1.0 + +## Added + +- Add componentName to modalDismiss event [#1c2558d](https://github.com/wix/react-native-navigation/commit/1c2558d77e489e2a35adc3a60eebed97ebf52add) by [jinshin1013](https://github.com/jinshin1013) + +## Fixed + +### iOS + +- Support changing backButton fontFamily and fontSize [#b438588](https://github.com/wix/react-native-navigation/commit/b4385883de9ff07ed8915cdcd6f78ddc26bb6691) by [yogevbd](https://github.com/yogevbd) +- Fixed bottomTab text color not working correctly on iOS13 [#211a46e](https://github.com/wix/react-native-navigation/commit/211a46e087213bc72c166a4332cd1d3d0fa01be2) by [yogevbd](https://github.com/yogevbd) +- Support backButton.testID [#e1b76c1](https://github.com/wix/react-native-navigation/commit/e1b76c1fe222a4153eddedf43caba5dd457aadb9) by [yogevbd](https://github.com/yogevbd) +- Handle statusBar.visible in all layout types and not only in components [#a2f5dbd](https://github.com/wix/react-native-navigation/commit/a2f5dbd3131f2cc158a650a01a1b9e271c2952f2) by [yogevbd](https://github.com/yogevbd) +- Fix a lot of large title issues [#54b2855](https://github.com/wix/react-native-navigation/commit/54b285531ea43e0dae76ae08af7de923ccf5917c) +- Fix title and subtitle color animations when popping screens [#5210848](https://github.com/wix/react-native-navigation/commit/52108484cc59ad8aaec9ef51b3c370c7ac80128f) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Stop rejecting dismissAllModals promise if no modals are displayed [#30b0b47](https://github.com/wix/react-native-navigation/commit/30b0b47b712cd1882b9c944a125c9d06ca5e0dd8) by [guyca](https://github.com/guyca) +- Support tabs without icons on Android [#ef58a6c](https://github.com/wix/react-native-navigation/commit/ef58a6cdeb1c4ea90ff528af50d6d2dc572f9f28) by [guyca](https://github.com/guyca) +- Fix autolink script - set minSdk to 19 [#4ce0e89](https://github.com/wix/react-native-navigation/commit/4ce0e89b06b9ab29d4be5d2eb0d11419deaade7a) by [jinshin1013](https://github.com/jinshin1013) +- ExternalComponentController extends ViewController [#c33ff12](https://github.com/wix/react-native-navigation/commit/c33ff1291ded4b171ef7b3f0736c5bc5b169d850) by [guyca](https://github.com/guyca) +- Support [react-native-youtube](https://github.com/davidohayon669/react-native-youtube) [#2793a02](https://github.com/wix/react-native-navigation/commit/2793a022729043d271fa6ffd80df62297c5f76fa) + +# 6.0.1 + +## Fixed + +### iOS + +- Fix applying drawBehind through mergeOptions [#e002a68](https://github.com/wix/react-native-navigation/commit/e002a68110cb75877982aed9c693ece8382c7942) by [yogevbd](https://github.com/yogevbd) + +# 6.0.0 + +This release changes how layout.backgroundColor work on iOS to add parity with Android. + +- layout.backgroundColor - applies background color to parent layouts (Stack, BottomTabs, SideMenu etc) +- layout.componentBackgroundColor - applies background color only to components + +## Fixed + +### Android + +- Fix custom push animations not working [#c9232cb](https://github.com/wix/react-native-navigation/commit/c9232cb9e49e02cd1975d16de01fa2a6186032b0) by [guyca](https://github.com/guyca) + +### iOS + +- Remove draw behind deprecation [#950642d](https://github.com/wix/react-native-navigation/commit/950642d48b2ec67f510ae6b3eefaaeb1ebfcf43d) by [yogevbd](https://github.com/yogevbd) +- Fix layout.backgroundColor being applied to components, it's now applied to parent layouts [#950642d](https://github.com/wix/react-native-navigation/commit/950642d48b2ec67f510ae6b3eefaaeb1ebfcf43d) by [yogevbd](https://github.com/yogevbd) +- Implement layout.componentBackgroundColor which is applied only to component ViewControllers [#950642d](https://github.com/wix/react-native-navigation/commit/950642d48b2ec67f510ae6b3eefaaeb1ebfcf43d) by [yogevbd](https://github.com/yogevbd) + +# 5.1.1 + +## Fixed + +### iOS + +- Apply extendedLayoutIncludesOpaqueBars true on all viewControllers (this commit was originally added to v4 and was left out of v5 my mistake) [#9fefeca](https://github.com/wix/react-native-navigation/commit/9fefeca9be9844fc80f839a532c97f5c4fa1d299) + +### Android + +- Fix crash when mergeOptions were called before stack view was created [#defc2aa](https://github.com/wix/react-native-navigation/commit/defc2aaa6e7c845c05cabe8c5753cc6a68ab5830) by [guyca](https://github.com/guyca) + +# 5.1.0 + +## Added + +### iOS + +- Add window.backgroundColor option [#c99ecf9](https://github.com/wix/react-native-navigation/commit/c99ecf9b145f453a9674c965d1634bcdece973b6) by [yogevbd](https://github.com/yogevbd) + +# 5.0.0 + +This release is focuses on shared element transition and on improving the installation process of the library. + +## Upgrading from V4 + +### Remove missingDimensionStrategy from app/build.gradle + +Since RNN supports multiple react-native versions, the library has multiple flavors, each targeting a different RN version. We now chose the appropriate flavor based on the react-native version installed in node_modules. + +```diff +-missingDimensionStrategy "RNN.reactNativeVersion", "reactNativeXX" // Where XX is the minor number of the react-native version you're using +``` + +### Declare Kotlin version in build.gradle + +We're starting to migrate RNN to Kotlin. All new code is written in Kotlin and existing code will be gradually converted to Kotlin. This requires you to declare the Kotlin version you're using in your project. + +```diff +buildscript { + ext { ++ kotlinVersion = "1.3.61" // Or any other kotlin version following 1.3.x ++ RNNKotlinVersion = kotlinVersion ++ RNNKotlinStdlib = "kotlin-stdlib-jdk8" + } + dependencies { ++ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + } +} +``` + +### Update MainApplication.java + +In an effort to simplify RNN's integrations process as much as possible, we're minimizing the changes required to both MainApplication and MainActivity. + +```diff ++import com.facebook.react.PackageList; + +public class MainApplication extends NavigationApplication { +- @Override +- protected ReactNativeHost createReactNativeHost() { +- return new NavigationReactNativeHost(this) { ++ private final ReactNativeHost mReactNativeHost = + new NavigationReactNativeHost(this) { + @Override + protected String getJSMainModuleName() { + return "index"; + } + ++ @Override ++ public boolean getUseDeveloperSupport() { ++ return BuildConfig.DEBUG; ++ } + ++ @Override ++ public List getPackages() { ++ ArrayList packages = new PackageList(this).getPackages(); ++ return packages; ++ } ++ } +- } + ++ @Override ++ public ReactNativeHost getReactNativeHost() { ++ return mReactNativeHost; ++ } + +- @Override +- public boolean isDebug() { +- return BuildConfig.DEBUG; +- } + +- @Nullable +- @Override +- public List createAdditionalReactPackages() { +- List packages = new ArrayList<>(); +- return packages; +- } +} +``` + +### Update settings.gradle + +Since RNN now supports auto linking, declaring the dependency manually is no longer needed. + +```diff +-include ':react-native-navigation' +-project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../../lib/android/app/') +``` + +### Make sure your app supports auto linking + +#### Update `app/build.gradle` + +Add these lines to the bottom of your `app/build.gradle` file. + +```diff ++apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle") ++applyNativeModulesAppBuildGradle(project) +``` + +#### Update `settings.gradle` + +```diff ++apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle") ++applyNativeModulesSettingsGradle(settings) +include ':app' +``` + +### Remove RNN pod from podspec + +As RNN is now autolinked, remove its pod from your podspec file. This will ensure the correct version is linked when running `pod install` + +```diff +- pod 'ReactNativeNavigation', :podspec => '../node_modules/react-native-navigation/ReactNativeNavigation.podspec' +``` + +## Breaking Changes + +### Modal animation parity + +show and dismiss animation api have been fixed and are now in parity with Android api. +If you've defined a custom modal animation, you can now consolidate the animation declarations. + + + + + + + + + + +
New Android + iOS APIUnsupported iOS API
+ +```js +options: { + animations: { + showModal: { + alpha: { + from: 0, + to: 1, + duration: 250, + } + } + } +} +``` + + + +```js +options: { + animations: { + showModal: { + content: { + alpha: { + from: 0, + to: 1, + duration: 250 + } + } + } + } +} +``` + +
+ +### drawBehind is deprecated on iOS + +> ❗️topBar and bottomTabs drawBehind option will be removed in the next major version. + +The drawBehind option has been an anti pattern on iOS from the start and was introduced only for parity with Android api. +On iOS, when a ScrollView or a SafeAreaView are used as screen root; the system handles insets automatically. +As adoption of notch devices increases, developers use these views regularly, rendering the drawBehind option useless. + +> **During the migration phase, leave Android options unchanged and set `drawBehind: true` to both TopBar and BottomTabs in default options.** + +### Android: Animation values are now declared in dp + +If you're animating `translationY` or `translationX` pass these values in dp instead of pixels. +This is especially relevant to values returned by `await Navigation.constants()` api as these values are returned in dp. Now, if you'd like to use them in animations, you can do so without converting to pixels. + +# 4.8.1 + +## Fixed + +### Android + +- Fix NPE when showing Overlay [#bfde34a](https://github.com/wix/react-native-navigation/commit/bfde34a5862c971587583aa52cb450cf526d5c66) by [guyca](https://github.com/guyca) + +### iOS + +- Fix overlays touch interception on new iPads [#433f48b](https://github.com/wix/react-native-navigation/commit/433f48b59d9be5aa328361654341afa8414c2e21) by [yogevbd](https://github.com/yogevbd) + +# 4.8.0 + +## Fixed + +### Android + +- Support react-native-youtube [#ffbd288](https://github.com/wix/react-native-navigation/commit/ffbd2882b24109ff8f2b51ca3c8c88822cc9afb7) by [guyca](https://github.com/guyca) + +### iOS + +- Fix wrong SafeAreaView margins when using bottomTabs.drawBehind: true [#527fd49](https://github.com/wix/react-native-navigation/commit/527fd49f2f1517143032a8b14f6ab17d2f74c032) by [yogevbd](https://github.com/yogevbd) + +# 4.7.1 + +## Fixed + +- Move selectTabOnPress prop to correct interface [#d6ead65](https://github.com/wix/react-native-navigation/commit/d6ead65c9331f12d3f79fc3b5bb7e0a0de80816e) by [phanghos](https://github.com/phanghos) + +### iOS + +- Fix external components layout measurement [#1961181](https://github.com/wix/react-native-navigation/commit/196118186fb788200dafcc1e11cd9f7d6e3f6dda) by [yogevbd](https://github.com/yogevbd) + +# 4.7.0 + +## Added + +- On tab press event - handle tab selection in Js [#b153142](https://github.com/wix/react-native-navigation/commit/b1531428a0a9608b5d1c84547f228d5de0c1aca2) by [pontusab](https://github.com/pontusab) +- RN 0.62 support on Android [#4bfa7c5](https://github.com/wix/react-native-navigation/commit/4bfa7c5092ac0ca6708b4bd61bd63e59601e8f3e) by [safaiyeh](https://github.com/safaiyeh) + +## Fixed + +### Android + +- Fix dotIndicator not respecting initial visibility option [#d9bd03f](https://github.com/wix/react-native-navigation/commit/d9bd03fea7465acadb6ef17613f8fe98e8be4eb1) by [itsam](https://github.com/itsam) + +### iOS + +- Set default fontsize value for title and subtitle [#0741799](https://github.com/wix/react-native-navigation/commit/0741799281a43380bc419886a19a8e72fc32d042) by [maryjenel](https://github.com/maryjenel) +- Respect default options when updating bottomTab options [#513138e](https://github.com/wix/react-native-navigation/commit/513138ebd9c620ba9e8d2b8a4a154ced790de1b2) by [yogevbd](https://github.com/yogevbd) + +# 4.6.0 + +## Added + +### Android + +- Adapt NavigationBar buttons color according to NavigationBar background color [#6521177](https://github.com/wix/react-native-navigation/commit/65211775f6b354945a9dc5a3f7791ddfdd20ebab) by [rverbytskyi](https://github.com/rverbytskyi) + +## Fixed + +### Android + +- Disable TopBar scroll when nestedScrollEnabled is enabled [#9a361a4](https://github.com/wix/react-native-navigation/commit/9a361a4fe340f5af18e1fa87b02f5e7e1f41646d) by [guyca](https://github.com/guyca) +- Reject promise when trying to push two children with same id [#27ceea8](https://github.com/wix/react-native-navigation/commit/27ceea8fb92506fdd756e45768e7235e3e7babc6) by [guyca](https://github.com/guyca) +- Fix drawBehind in default options not working [#0e93366](https://github.com/wix/react-native-navigation/commit/0e933661aed9cb4a6cad6e1e1fa5a352f371f754) by [guyca](https://github.com/guyca) + +### iOS + +- Fix merge options leaks to next screen in stack [#386bf65](https://github.com/wix/react-native-navigation/commit/386bf65d251f0c6582de2cf529487dfafc69bc9d) by [yogevbd](https://github.com/yogevbd) +- Invoke all commands on the main thread [#8843224](https://github.com/wix/react-native-navigation/commit/8843224a9aed33a9fd92323db48ab80f50cae72f) by [yogevbd](https://github.com/yogevbd) +- Resolve navigationItem from external component [#d81b0bf](https://github.com/wix/react-native-navigation/commit/d81b0bf3cf929136218a71dbc74dcbf0cc668886) by [yogevbd](https://github.com/yogevbd) +- Fix popGesture freezes the app [#37473f8](https://github.com/wix/react-native-navigation/commit/37473f88e9bfdc847f25cd21e5ca521e31157268) by [yogevbd](https://github.com/yogevbd) + +# 4.5.4 + +- Fix title.component fill parent [#7e6b2be](https://github.com/wix/react-native-navigation/commit/7e6b2be676382db74bd393940ddfdea3a3847e2c) by [yogevbd](https://github.com/yogevbd) + +# 4.5.2 - 4.5.3 + +## Fixed + +### Android + +- Fix NPE when updating tabs before tab views are created [#fccfb4d](https://github.com/wix/react-native-navigation/commit/fccfb4d8c289c10b6424e38690fa4469fa65b7ea) by [guyca](https://github.com/guyca) + +# 4.5.1 + +## Fixed + +### iOS + +- Fix crash when check UIBarButtonItem are not added by RNN [#233820e](https://github.com/wix/react-native-navigation/commit/233820ef372042d4fae463b0a63f75bfeab160da) by [wixiosalex](https://github.com/wixiosalex) + +# 4.5.0 + +## Added + +- Improve accessibility support [#07c558c](https://github.com/wix/react-native-navigation/commit/07c558c76f7bf3acd56a2af4e0e901c81ae0e49d), [#f635b5e](https://github.com/wix/react-native-navigation/commit/f635b5e8be81ee99aaf2726c989624b1dafcbf41) by [yogevbd](https://github.com/yogevbd) and [guyca](https://github.com/guyca) + +### iOS + +- Add modalAttemptedToDismiss event [#87af42a](https://github.com/wix/react-native-navigation/commit/87af42a56be7deaa32678afb72846c92e293f524) by [manicantic](https://github.com/manicantic) +- Add bottomTabLongPressed event on iOS [#c425f83](https://github.com/wix/react-native-navigation/commit/c425f837b1d99a8b27525d52b6eba37fb77cbded) by [N3TC4T](https://github.com/N3TC4T) + +## Fixed + +### Android + +- Emit modalDismissed event before ViewController is destroyed [#cf591d9](https://github.com/wix/react-native-navigation/commit/cf591d9a9c48ed89c7e7fed4594b8dbcb9732bc9) by [guyca](https://github.com/guyca) + +# 4.4.0 + +## Added + +### Android + +- Added TitleState showWhenActiveForce option for bottomTabs [#cf18e2d](https://github.com/wix/react-native-navigation/commit/cf18e2d3c98785c28d42b486b70e05b75404ca54) by [BenJeau](https://github.com/BenJeau) + +## Fixed + +### Android + +- Apply BottomTabs visibility only if child is visible [#6ffb301](https://github.com/wix/react-native-navigation/commit/6ffb3011f7e3db11c9dac9d4c9d01b8345079c2e) by [guyca](https://github.com/guyca) + +## Fixed + +# 4.3.0 + +## Fixed + +### iOS + +- Fixed pushing external ViewControllers to stack inside a modal [#4b14c87](https://github.com/wix/react-native-navigation/commit/4b14c8798b4f9bf99ce36dd29b2df8e8ff5bf109) by [yogevbd](https://github.com/yogevbd) + +# 4.2.0 + +## Fixed + +### Android + +- Support hiding back button with mergeOptions [#3f17dc4](https://github.com/wix/react-native-navigation/commit/3f17dc4a82657c6cfdbdd82c95cbba6f2bf63f55) by [guyca](https://github.com/guyca) + +# 4.1.0 + +## Added + +- Send componentType field in componentDidAppear and componentDidDisappear events [#3878b68](https://github.com/wix/react-native-navigation/commit/3878b683ccc045f6c732850833be0633a8ac1b0e) by [guyca](https://github.com/guyca) and [yogevbd](https://github.com/yogevbd) + +## Fixed + +- Add typing for children on TopTabs [#1f611c6](https://github.com/wix/react-native-navigation/commit/1f611c657ff946493aced56758399f7c240bf002) by [aalises](https://github.com/aalises) + +### Android + +- Apply translucent StatusBAr flag only if needed [#6782362](https://github.com/wix/react-native-navigation/commit/6782362035228463701003cc7fbbbc0af27d88d0) by [guyca](https://github.com/guyca) + +### iOS + +- Fix topBar.title.component measurement on iOS 10 [#82e4807](https://github.com/wix/react-native-navigation/commit/82e48079dc4ef24639b215af83d1344aa021c281) by [yogevbd](https://github.com/yogevbd) +- Remove yellow boxes from title and button components [#b82d87f](https://github.com/wix/react-native-navigation/commit/b82d87f0c88d1dcd803af0f8507935a1d818bae3) by [yogevbd](https://github.com/yogevbd) + +# 4.0.9 + +## Fixed + +### iOS + +- Force translucent on iOS 12 when background is transparent [#2ad41f3](https://github.com/wix/react-native-navigation/commit/2ad41f3adb9883fa20f1d52fcbbc6fd0750976f9) by [yogevbd](https://github.com/yogevbd) + +# 4.0.8 + +## Fixed + +### iOS + +- Fix TopBar background color on iOS12 [#f202c7e](https://github.com/wix/react-native-navigation/commit/f202c7ec03bcc6cf9d2bc1c587064b78e111432a) by [yogevbd](https://github.com/yogevbd) + +# 4.0.7 + +## Added + +- Add screenPopped event [#71af559](https://github.com/wix/react-native-navigation/commit/71af55968db11315cd10aac2e64cb1e24f37c0e0) by [yogevbd](https://github.com/yogevbd) and [guyca](https://github.com/guyca) + +## Fixed + +### Android + +- Fix incorrect bottom inset when hiding BottomTabs in default options [#d0c21e4](https://github.com/wix/react-native-navigation/commit/d0c21e4f6573189e634838a53c518f6bb8587080) by [guyca](https://github.com/guyca) + +### iOS + +- Fix topBar transparent background on iOS 12 [#cd3d347](https://github.com/wix/react-native-navigation/commit/cd3d3472fcb8e5588507bc16c438d53c581d7d2b) by [yogevbd](https://github.com/yogevbd) + +# 4.0.6 + +## Fixed + +- Fix native bottomTab.icon resource not working [#aa1870a](https://github.com/wix/react-native-navigation/commit/aa1870a743ff9e1611c643a5462ca84f81710fcd) by [guyca](https://github.com/guyca) + +### iOS + +- Fix default font size regression [#8f9e719](https://github.com/wix/react-native-navigation/commit/8f9e719747ef9c0861122f5c5a75b0ec852574fc) by [yogevbd](https://github.com/yogevbd) +- Fix crash when reloading while an overlay is displayed [#2fa17aa](https://github.com/wix/react-native-navigation/commit/2fa17aaaca56a1faef751e1d946eb3cc16ee7284) by [yogevbd](https://github.com/yogevbd) + +# 4.0.5 + +## Fixed + +- Fix conflict with React Native's getConstants [#5e6d6fc](https://github.com/wix/react-native-navigation/commit/5e6d6fce132fc37722867c3e43a0036f4fe085b8) by [guyca](https://github.com/guyca) +- Use lodash submodules instead of lodash to reduce bundle size [#e53a9fe](https://github.com/wix/react-native-navigation/commit/e53a9feb20e5851d29f0913fc6c2704dbe00af2e) by (pontusab)[https://github.com/pontusab] +- Replace lodash chain with flow to reduce bundle size [#bf354d7](https://github.com/wix/react-native-navigation/commit/bf354d7c77c889c7e2dc0be0fc29b6a54011ce9b) by [jinshin1013](https://github.com/jinshin1013) + +### iOS + +- Send ModalDismissed event [#4cb0e98](https://github.com/wix/react-native-navigation/commit/4cb0e98a6756317f8f61f5ee2b3d7530cd180f61) by [yogevbd](https://github.com/yogevbd) +- Fix incorrect `constants.topBarHeight` value when pageSheet modal is displayed [#9ef61a9](https://github.com/wix/react-native-navigation/commit/9ef61a9a1357312208463ef149a7951931043d1e) by [yogevbd](https://github.com/yogevbd) +- Add BottomTabs.attachMode support [#60c4dfc](https://github.com/wix/react-native-navigation/commit/60c4dfcd72245de02836bd4858f311822cdf866d) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Merge child options with SideMenu parent [#afbaa9a](https://github.com/wix/react-native-navigation/commit/afbaa9a4f53e05e6b00e1b8044a4a8a484ac3ea0) by [guyca](https://github.com/guyca) +- Temporary fix to FAB position on screen [#4714983](https://github.com/wix/react-native-navigation/commit/47149835dcf707806bb211230e63a61d8cf9a1d5) by [guyca](https://github.com/guyca) + +# 4.0.4 + +## Fixed + +### iOS + +- Fix large title issues [#65118b1](https://github.com/wix/react-native-navigation/commit/65118b1ed28dd5a4636dabd5952c515d18a0b802) by [yogevbd](https://github.com/yogevbd) + +# 4.0.3 + +## Added + +### iOS + +- Introduce `modal.swipeToDismiss` option [#659a42c](https://github.com/wix/react-native-navigation/commit/ + +## Fixed + +### iOS + +- Fix setting TopBar component in default options [#4a1b8b4](https://github.com/wix/react-native-navigation/commit/4a1b8b4a64546050f515f8dd00539f14e18e5f70) by [yogevbd](https://github.com/yogevbd) +- Fix blinking react view button [#d502c69](https://github.com/wix/react-native-navigation/commit/d502c694438903ffb612fec16a0b72444b3bc3ed) by [yogevbd](https://github.com/yogevbd) +- Let the system control modal presentation style [#659a42c](https://github.com/wix/react-native-navigation/commit/659a42cde14a3fb7653ebc40c906ec042761cd7c) by [yogevbd](https://github.com/yogevbd) +- Fix black TopBar on iOS < 13 [#7cf2083](https://github.com/wix/react-native-navigation/commit/7cf208353f22a4f07760f166ba0afd5af24f2e91) by [yogevbd](https://github.com/yogevbd) + +# 4.0.2 + +## Fixed + +### iOS + +- Fix glitchy pop animation [#0c6e2f0](https://github.com/wix/react-native-navigation/commit/0c6e2f00b1ee8122499df08f060d5f016868355e) by [yogevbd](https://github.com/yogevbd) + +# 4.0.1 + +## Fixed + +### iOS + +- Fix double back button [#ed7c579](https://github.com/wix/react-native-navigation/commit/ed7c5795e1e7770c1eeb692b1fa300f3163d7503) by [yogevbd](https://github.com/yogevbd) +- Fix transparent TopBar on iOS 13 [#b560265](https://github.com/wix/react-native-navigation/commit/b56026553dfcc5bf9ffe91e848fd3b7723561656) by [yogevbd](https://github.com/yogevbd) +- Fix TopBar.noBorder on iOS 13 [#919fa12](https://github.com/wix/react-native-navigation/commit/919fa12780e1ace13d2b8ce7680795fd26b68f76), [#5b7ddec](https://github.com/wix/react-native-navigation/commit/5b7ddec1dad927e71dc31115111dec5d7e165449) by [yogevbd](https://github.com/yogevbd) +- Fix crash when calling Navigation.constants() when BottomTabs don't exist [#2cd4752](https://github.com/wix/react-native-navigation/commit/2cd4752fa0a43a7c704846b3e3c8833a4c9eff36) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Create react host after SoLoader.init [#ab2fa63](https://github.com/wix/react-native-navigation/commit/ab2fa632c23fcfbfbb1fbb04e91f7394289e95cb) by [guyca](https://github.com/guyca) + +# 4.0.0 + +## Added + +### iOS + +- **Support Xcode 11 - Xcode 10 is no longer supported** +- Support centering bottomTab icons using bottomTabs.titleDisplayMode [#26d3d82](https://github.com/wix/react-native-navigation/commit/26d3d8219097fe1b22a9585526ab8a712af6a508) by [yogevbd](https://github.com/yogevbd) +- Prevent creation of button react view with the same componentId [#1807c5b](https://github.com/wix/react-native-navigation/commit/1807c5b48d7b72e4f171dc105db6eff6291614e5) by [yogevbd](https://github.com/yogevbd) + +## Fixed + +- Change BottomTab.icon back to optional [#d8c34c3](https://github.com/wix/react-native-navigation/commit/d8c34c391097189819972ffd7f5454231ec9b2f3) by [guyca](https://github.com/guyca) + +### iOS + +- Remeasure title component after orientation change [#619af3e](https://github.com/wix/react-native-navigation/commit/619af3efe081f7069acfbe1149c7b0775f40faeb) by [yogevbd](https://github.com/yogevbd) +- Fix memory leak when reloading the app [#9970853](https://github.com/wix/react-native-navigation/commit/9970853820bf303cb75fb4238050e46c9c65c49d) by [yogevbd](https://github.com/yogevbd) +- Support UINavigationBarBehavior [#6f13d69](https://github.com/wix/react-native-navigation/commit/6f13d6963c6af655506a820b8bbddea4849152d4), [#9f43bca](https://github.com/wix/react-native-navigation/commit/9f43bca3573e8833eb8219c6e7a829d8d92faac0) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Automatically apply DrawBehind when tabs are hidden [#002b7d8](https://github.com/wix/react-native-navigation/commit/002b7d8f331019f79421e7cd28bab9bf411d73e4) by [guyca](https://github.com/guyca) +- Fix button disabled color has no effect [#b66ff1d](https://github.com/wix/react-native-navigation/commit/b66ff1d4b63196113ee0ba0129d33da39c2e134a) by [guyca](https://github.com/guyca) +- Fix BottomTabs background color changing to white background sometimes [#57eb0db](https://github.com/wix/react-native-navigation/commit/57eb0db7da6d69c784a9b0cd5672a563901738a9) by [guyca](https://github.com/guyca) + +# 3.7.0 + +## Added + +### Android + +- Add bottomTabs.preferLargeIcons option [#fd93167](https://github.com/wix/react-native-navigation/commit/fd93167dbe70975161c20832f43a499453f76804) by [guyca](https://github.com/guyca) + +# 3.6.0 + +### Added + +- Start script for Windows [#764863f](https://github.com/wix/react-native-navigation/commit/764863f46be72f7b29499994e5349ea90084d450) by [Damar95](https://github.com/Damar95) + +## Fixed + +### Android + +- Include commandName in commandCompleted event [#b904608](https://github.com/wix/react-native-navigation/commit/b9046081ace89a2d3d0795c15920b6b2692c7702) by [jpgarcia](https://github.com/jpgarcia) +- Fix crash when title component is destroyed right after being attached [#39ee170](https://github.com/wix/react-native-navigation/commit/39ee1701fd0e626961158d9c342b4c6b0bd3c05b) by [guyca](https://github.com/guyca) +- Fix NPE when component appears under certain conditions [#35851fc](https://github.com/wix/react-native-navigation/commit/35851fc9893917338022f5eb06c25bfb21625d81) by [heroic](https://github.com/heroic) +- Apply layout direction directly on TopBar buttons container [#14b5221](https://github.com/wix/react-native-navigation/commit/14b5221caa2529c0396134c5f7981f093a14b58b) by [guyca](https://github.com/guyca) + +# 3.5.1 + +## Fixed + +### iOS + +- Fix title component disappearing after mergeOptions [#6d446a8](https://github.com/wix/react-native-navigation/commit/6d446a8882f92b82cd01b78992331d66c31b5abf) by [guyca](https://github.com/guyca) + +# 3.5.0 + +## Fixed + +### Android + +- Allow navigationBarColor change within mergeOptions [#8720628](https://github.com/wix/react-native-navigation/commit/87206286bfb8fd235e5356da9542c62dfc44f356) by [danielang](https://github.com/danielang) +- Fix crash when null was used as bottomTab.color [#c48ed74](https://github.com/wix/react-native-navigation/commit/c48ed747a163a2917820e62ab40d5047389f5fcb) by [guyca](https://github.com/guyca) + +# 3.4.0 + +## Added + +- [stable] Introduce Navigation.updateProps command [#0eb0570](https://github.com/wix/react-native-navigation/commit/0eb0570840a26d4b848d7c763060a2b8faf1dc80) by [guyca](https://github.com/guyca) + +### Android + +- add support for navigationBarColor [#8af95da](https://github.com/wix/react-native-navigation/commit/8af95da24a0622829d514c8ed61507438491bc27) by [mcuelenaere](https://github.com/mcuelenaere) + +## Fixed + +- Added setStackRoot animation property to interface [#fcdbe79](https://github.com/wix/react-native-navigation/commit/fcdbe79dc3305cbf12396aa6283a1bf4a5f02889) by [nielsdB97](https://github.com/nielsdB97) + +# 3.3.0 + +## Added + +- **[experimental]** Support updating component props with Navigation.mergeOptions [#291f161](https://github.com/wix/react-native-navigation/commit/291f16177d2f67a474d3a980a503a85d0acf2b2a) by [justtal](https://github.com/justtal) + +### Android + +- Add support for getLaunchArgs [#16646e7](https://github.com/wix/react-native-navigation/commit/16646e7c88d78f1ddd7fb6ae434ef968ac051f06) by [swabbass](https://github.com/swabbass) +- Support bottomTab.selectedIcon [#45e8389](https://github.com/wix/react-native-navigation/commit/45e8389b2b7d282878a80c49b146ddeb4ec2cd89) by [guyca](https://github.com/guyca) + +### iOS + +- Added fontWeight option for iOS 13 [#6ab2345](https://github.com/wix/react-native-navigation/commit/6ab2345ad6e9ddd26ac1275537ec2791fa50c7c2) by [yogevbd](https://github.com/yogevbd) + +## Fixed + +### Android + +- Merge options with ParentViewControllers [#0dd3315](https://github.com/wix/react-native-navigation/commit/0dd331590770c33d067bfeae596aae7d4ff992ea) by [guyca](https://github.com/guyca) + +### iOS + +- Prefer new imageWithTintColor API when tinting an UIImage [#5d751f6](https://github.com/wix/react-native-navigation/commit/5d751f643ad80a67abccc51d75f1127e2b65824a) by [danilobuerger](https://github.com/danilobuerger) +- Fixed disappearing StatusBar when displaying native ViewControllers [#58c76e1](https://github.com/wix/react-native-navigation/commit/58c76e1ec218741b461bca30e8126e952b87a180) by [yogevbd](https://github.com/yogevbd) +- Fixed title layout issues on iOS 13 [#898e187](https://github.com/wix/react-native-navigation/commit/898e187d4cbea76b93709c95ad89e984e660b904), [#a3f176d](https://github.com/wix/react-native-navigation/commit/a3f176d56e94e5a5de0be079de9f63b180dc6f5a), [#094b9a7](https://github.com/wix/react-native-navigation/commit/094b9a7ef153d62ea9c195e342cafca4892c1428) by [yogevbd](https://github.com/yogevbd) +- Fixed leaking pageSheet modals on iOS 13 [#2b4d897](https://github.com/wix/react-native-navigation/commit/2b4d897f19684e2c04c3050c3882f1558cb1efed) by [yogevbd](https://github.com/yogevbd) + +# 3.2.0 + +## Added + +### Android + +- Add animation support for setStackRoot [#d0a17fa](https://github.com/wix/react-native-navigation/commit/d0a17fabf4f5360b0f54797867a7a49960a1937d) by [Jazqa](https://github.com/Jazqa) + +## Fixed + +- Don't cache values for constants() call [#a99e138](https://github.com/wix/react-native-navigation/commit/a99e138839abc8ab84b67489ef9a83a6874778da) by [ItsNoHax](https://github.com/ItsNoHax) + +### iOS + +- Fix applying merged backButton options [#aef5b2e](https://github.com/wix/react-native-navigation/commit/aef5b2e3bd60acb33847c0ab3b66b8fc51fef703) by [guyca](https://github.com/guyca) +- Remove duplicate setDefaultOptions in UIViewController categories [#0d31e30](https://github.com/wix/react-native-navigation/commit/0d31e30800dc3e7314cfbf1dcf6b645614b781f4) by [danilobuerger](https://github.com/danilobuerger) +- Don't consume SideMenu enabled option after applying it in mergeOptions [#9faf458](https://github.com/wix/react-native-navigation/commit/9faf458cb451829e86809d9162728eed17a7f56c) by [guyca](https://github.com/guyca) +- supportedInterfaceOrientations didn't take default orientation value into account [#9faf458](https://github.com/wix/react-native-navigation/commit/9faf458cb451829e86809d9162728eed17a7f56c) by [guyca](https://github.com/guyca) +- SideMenu always returned the centre ViewController as the current child and didn't take open SideMenu into account [#9faf458](https://github.com/wix/react-native-navigation/commit/9faf458cb451829e86809d9162728eed17a7f56c) by [guyca](https://github.com/guyca) +- Stop recursive double setting of default options [#d5c92b1](https://github.com/wix/react-native-navigation/commit/d5c92b1609d5fc1a75c51065791e5aad2a80b654) by [danilobuerger](https://github.com/danilobuerger) +- Immediately unmount buttons removed by mergeOptions, instead of unmounting them when screen is unmounted [#65dde34](https://github.com/wix/react-native-navigation/commit/65dde342fb087bd122bc19de308cbf283485aac7) by [yogevbd](https://github.com/yogevbd) + +## Android + +- Catch rare RuntimeException in setRoot when waitForRender = true [#b048581](https://github.com/wix/react-native-navigation/commit/b04858190e1fc2a1fe22f67879a6c7ca3769c297) by [rawrmaan](https://github.com/rawrmaan) +- Fix SideMenu enabled property issues [#92fcf70](https://github.com/wix/react-native-navigation/commit/92fcf70773a3614c48e3ac844e81cb16d1ff8d2a) by [Royce](https://github.com/Royce) + +# 3.1.2 + +## Fixed + +- Add @babel/core to devDependencies [#fdec91d](https://github.com/wix/react-native-navigation/commit/fdec91dc39364aaa23a48dfc4d1d44e73a6f2e21) by [ItsNoHax](https://github.com/ItsNoHax) + +### iOS + +- Fix replacing react title with text title not working [#b434b4f](https://github.com/wix/react-native-navigation/commit/b434b4f82a6f0642af9d11ad8dda6ec8e9c5603a) by [FRizzonelli](https://github.com/FRizzonelli) +- Fix merging TopBar title, buttons and status bar options, broke in 3.1.1 [#5409a62](https://github.com/wix/react-native-navigation/commit/5409a625d9d272c5c0a7d9b10ed0df5ff51c6155) by [guyca](https://github.com/guyca) + +# 3.1.1 + +## Fixed + +### Android + +- Fix defaultOptions not being applied if called after setRoot [#338b096](https://github.com/wix/react-native-navigation/commit/338b0961f9bee9fa20583efe0f165e3cefa14c92) by [guyca](https://github.com/guyca) + +# 3.1.0 + +## Added + +- Support passing null color to StatusBar backgroundColor and bottom tab icon color [#3519837](https://github.com/wix/react-native-navigation/commit/3519837cc2a82cb14ec1849bfc358865e407f556) by [guyca](https://github.com/guyca) + +## Fixed + +### Android + +- Removed the legacy support lib [#8663669](https://github.com/wix/react-native-navigation/commit/8663669ed92f34bedf7bdbdb8a9b1a64be5b8cdf) by [SudoPlz](https://github.com/SudoPlz) +- Apply layout direction directly on views [#fffd2d2](https://github.com/wix/react-native-navigation/commit/fffd2d23f169d11ddb7c9348e2070c3385844e34) by [guyca](https://github.com/guyca) + +# 3.0.0 + +## Android + +- Support RN 0.60 +- Migrate to AndroidX +- Improve draw behind StatusBar
+ Added `statusBar.translucent` boolean property +- BottomTabs are not pushed upwards when keyboard opens +- Removed SyncUiImplementation + [SyncUiImplementation](https://github.com/wix/react-native-navigation/blob/master/lib/android/app/src/reactNative57WixFork/java/com/reactnativenavigation/react/SyncUiImplementation.java) was used to overcome a bug in RN's UiImplementation. This workaround was added to RN's `UiImplementation` in RN 0.60 and can be removed from RNN. + + If you're using `SyncUiImplementation` your app will fail to compile after upgrading to v3. Simply remove the following code from your `MainApplication.java` + + ```diff + - import com.facebook.react.uimanager.UIImplementationProvider; + - import com.reactnativenavigation.react.SyncUiImplementation; + ``` + +* @override +* protected UIImplementationProvider getUIImplementationProvider() { +* return new SyncUiImplementation.Provider(); +* } + +```` +* BottomTab badge and dot indicator are not animated by default. +* The following option will show a badge with animation + ```js + bottomTab: { + badge: 'new, + animateBadge: true + } + ``` + +* The following option will show a dot indicator with animation + ```js + bottomTab: { + dotIndicator: { + visible: true, + animate: true + } + } + ``` +* Stack, BottomTabs and SideMenu are drawn behind StatusBar.
+While parent controllers are drawn behind the StatusBar, their background isn't. +This means that when transitioning from a destinations drawn under the StatusBar to a destination drawn behind it, the application's default background color will be visible behind the StatusBar. +If you application's theme is dark, you might want to change the `windowBackground` property to mitigate this: +Add the following to your application's `style.xml` +```xml + + + + + + #f00 + +```` + +# 2.29.0 + +## Added + +- Introduce `Navigation.updateProps` command [#0eb0570](https://github.com/wix/react-native-navigation/commit/0eb0570840a26d4b848d7c763060a2b8faf1dc80) by [guyca](https://github.com/guyca) + +## Fixed + +### iOS + +- Fix compilation error on Xcode 10.x [#99ddcd8](https://github.com/wix/react-native-navigation/commit/99ddcd864005ce768ca7c0b34d2ecfa8246dc568) and [#83f03cd](https://github.com/wix/react-native-navigation/commit/83f03cd8f945152cda93c664d69bf36047989571) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Don't merge null bottomTab.selectedIconColor and bottomTab.iconColor [#c48ed74](https://github.com/wix/react-native-navigation/commit/c48ed747a163a2917820e62ab40d5047389f5fcb) by [guyca](https://github.com/guyca) + +# 2.28.0 + +## Added + +- Support updating component props with Navigation.mergeOptions [#291f161](https://github.com/wix/react-native-navigation/commit/291f16177d2f67a474d3a980a503a85d0acf2b2a) by [justtal](https://github.com/justtal) + +### Android + +- Support bottomTab.selectedIcon [#45e8389](https://github.com/wix/react-native-navigation/commit/45e8389b2b7d282878a80c49b146ddeb4ec2cd89) by [guyca](https://github.com/guyca) + +# 2.27.7 + +## Added + +### iOS + +- Font weight option support on iOS [#f283e15](https://github.com/wix/react-native-navigation/commit/f283e155948c0ae190c1dde0fb3d78d5ac129af0) by [yogevbd](https://github.com/yogevbd) + +# 2.27.6 + +## Fixed + +### iOS + +- Fix status bar disappear when presenting native camera screen on iOS [#6cfde5e](https://github.com/wix/react-native-navigation/commit/6cfde5e24c95506b6d31b2f40164fa3f196b72a6) by [yogevbd](https://github.com/yogevbd) + +# 2.27.5 + +## Fixed + +### iOS + +- Stop recursive double setting of default options [#3da2ca8](https://github.com/wix/react-native-navigation/commit/3da2ca8afc7597b46cad500828dffc0102c034a6) by [danilobuerger](https://github.com/danilobuerger) +- Fix infinite loop while trying to remove react buttons [#88fd1f1](https://github.com/wix/react-native-navigation/commit/88fd1f15d0bc22d8c53c7e518eb0bb178e15ea6c) by [guyca](https://github.com/guyca) + +# 2.27.4 + +## Fixed + +### iOS + +- Immediately unmount buttons removed by mergeOptions, instead of unmounting them when screen is unmounted [#65dde34](https://github.com/wix/react-native-navigation/commit/65dde342fb087bd122bc19de308cbf283485aac7) by [yogevbd](https://github.com/yogevbd) +- Don't consume SideMenu enabled option after applying it in mergeOptions [#9faf458](https://github.com/wix/react-native-navigation/commit/9faf458cb451829e86809d9162728eed17a7f56c) by [guyca](https://github.com/guyca) +- supportedInterfaceOrientations didn't take default orientation value into account [#9faf458](https://github.com/wix/react-native-navigation/commit/9faf458cb451829e86809d9162728eed17a7f56c) by [guyca](https://github.com/guyca) +- SideMenu always returned the centre ViewController as the current child and didn't take open SideMenu into account [#9faf458](https://github.com/wix/react-native-navigation/commit/9faf458cb451829e86809d9162728eed17a7f56c) by [guyca](https://github.com/guyca) +- Remove duplicate setDefaultOptions in UIViewController categories [#452c4e6](https://github.com/wix/react-native-navigation/commit/452c4e692fe700600447f19282bd42b07dcc9bb4) by [danilobuerger](https://github.com/danilobuerger) + +# 2.27.3 + +## Fixed + +### iOS + +- Fix merging back button [#1800e70](https://github.com/wix/react-native-navigation/commit/1800e708a8483bc4e56873e826f2d72f02d659b9) by [guyca](https://github.com/guyca) + +# 2.27.2 + +## Fixed + +### iOS + +- Fix TopBar, title, buttons and StatusBar which broke in the previous release [#8044b2d](https://github.com/wix/react-native-navigation/commit/8044b2d12cfd2b937bfbe846d98f9034a88aa254) by [guyca](https://github.com/guyca) + +# 2.27.1 + +## Fixed + +### iOS + +- Fix defaultOptions not being applied if called after setRoot [#338b096](https://github.com/wix/react-native-navigation/commit/338b0961f9bee9fa20583efe0f165e3cefa14c92) by [guyca](https://github.com/guyca) + +# 2.27.0 + +## Added + +- Support passing null color to StatusBar backgroundColor and bottom tab icon color [#3519837](https://github.com/wix/react-native-navigation/commit/3519837cc2a82cb14ec1849bfc358865e407f556) by [guyca](https://github.com/guyca) + +## Fixed + +### Android + +- Apply layout direction directly on views [#fffd2d2](https://github.com/wix/react-native-navigation/commit/fffd2d23f169d11ddb7c9348e2070c3385844e34) by [guyca](https://github.com/guyca) + +# 2.26.1 + +## Fixed + +### iOS + +- Fix transparent topBar background color transition [#147cf4c](https://github.com/wix/react-native-navigation/commit/147cf4cafca83f0903b68a47d3812009a11d3018) by [yogevbd](https://github.com/yogevbd) + +# 2.26.0 + +## Fixed + +### Android + +- Apply TopBar buttons only if they are different than current buttons [#f15e9b3](https://github.com/wix/react-native-navigation/commit/f15e9b3a2a8c661d10c93d9c2f9a7155de979240) by [guyca](https://github.com/guyca) + +# 2.25.0 + +## Fixed + +### Android + +- Ensure appLaunched event is emitted only when app is resumed [#21584fd](https://github.com/wix/react-native-navigation/commit/21584fd4a525d7a8085caf18d624668cc5865d93) by [guyca](https://github.com/guyca) + +# 2.24.0 + +## Added + +- Add return type to Navigation.constants() [#66ab3cd](https://github.com/wix/react-native-navigation/commit/66ab3cd695be68e7d7536fde4c61bad4e7067281) by [danilobuerger](https://github.com/danilobuerger) + +## Fixed + +### Android + +- Destroy modals on setRoot [#f06787d](https://github.com/wix/react-native-navigation/commit/f06787dec9997cd51c52bef4d319ef32bca64f48) by [guyca](https://github.com/guyca) + +### iOS + +- Fixed react component button flicker [#77ee4df](https://github.com/wix/react-native-navigation/commit/77ee4df6c9e3824c418fbba6ed9fe82711b5d520) by [yogevbd](https://github.com/yogevbd) +- Fix bug that reverts navbar title size to 17 [#e677f97](https://github.com/wix/react-native-navigation/commit/e677f97cb775e43af1352caf38c03dd352851b47) by [dcvz](https://github.com/dcvz) + +# 2.23.0 + +## Added + +- BottomTab dot indicator [#f425155](https://github.com/wix/react-native-navigation/commit/f42515524d88a5f4f12a35684ab288dad6af1b1d) by [guyca](https://github.com/guyca) + +## Fixed + +### Android + +- Fix margin top topbar when statusbar drawBehind [#234c59c](https://github.com/wix/react-native-navigation/commit/234c59ce7b35acc6ba53bc7a43f4c688bfb6e11e) by [isuhar](https://github.com/isuhar) + +### iOS + +- Fix SideMenu size after screen rotation [#a591fe4](https://github.com/wix/react-native-navigation/commit/a591fe4476ca152a336022e2570431b677f60225) by [lionerez1](https://github.com/lionerez1) +- Set nil as default UITabBarItem.title value [#76d832b](https://github.com/wix/react-native-navigation/commit/76d832b683b3daca530340acdcfbc30acf36b568) by [danilobuerger](https://github.com/danilobuerger) + +# 2.22.3 + +## Fixed + +### iOS + +- Fix Constants.topBarHeight being zero if root ViewController isn't a NavigationViewController [#f19e523](https://github.com/wix/react-native-navigation/commit/f19e523afcc013681a601d2c9d4b0340f5459b59) by [guyca](https://github.com/guyca) + +# 2.22.2 + +## Added + +### iOS + +- Support changing javascript bundle location in runtime [#8959d68](https://github.com/wix/react-native-navigation/commit/8959d680d8efc8ca9f11d5ae7d78134c2f9a7959) by [yogevbd](https://github.com/yogevbd) + +## Fixed + +### iOS + +- Fix back button initialization on setStackRoot [#c0ad194](https://github.com/wix/react-native-navigation/commit/c0ad1945a3dbbc29192abdcc1c598516b391a10f) by [yogevbd](https://github.com/yogevbd) + +# 2.22.1 + +## Fixed + +- Add width and height attributes to SideMenuSide type [#73d621d](https://github.com/wix/react-native-navigation/commit/73d621d48d24ba270dec42f82789bfbc911262cd) by [ball-hayden](https://github.com/ball-hayden) + +### iOS + +- Fixed crash when calling Navigation.constants() when root view isn't BottomTabs [#663b1c3](https://github.com/wix/react-native-navigation/commit/663b1c3f60cb474ebd9cdbda824121add1c34801) by [daveyjones](https://github.com/daveyjones) +- Fixed crash when setting react component as left button [#29829ae](https://github.com/wix/react-native-navigation/commit/29829ae2aa972fa7df20cd50e0d43efa8991fbf2) by [MarianPalkus](https://github.com/MarianPalkus) + +### Android + +- Remove android \* imports for support [#35a19b5](https://github.com/wix/react-native-navigation/commit/35a19b5f687b89dc414e65184995ebc69f847704) by [heroic](https://github.com/heroic) +- Add back button to last child in setStackRoot [#898cf7a](https://github.com/wix/react-native-navigation/commit/898cf7ae2703656459f28e21123f3b0f8a40b22e) by [guyca](https://github.com/guyca) + +# 2.21.1 + +## Fixed + +### iOS + +- Fix `setStackRoot` options resolving [#8ced964](https://github.com/wix/react-native-navigation/commit/8ced96443f8c279821719e842f7580a988aeb47c) by [yogevbd](https://github.com/yogevbd) + +# 2.21.0 + +## Added + +- Title topMargin option [#069cb85](https://github.com/wix/react-native-navigation/commit/069cb85132dcc441c27c56e0f25e475c1d44eef2) by [guyca](https://github.com/guyca) + +## Fixed + +- Safer check around component listener trigger [#51d1b66](https://github.com/wix/react-native-navigation/commit/51d1b6676027c38d439dff03d23660ac8d617a5a) by [dozoisch](https://github.com/dozoisch) + +### Android + +- Emit SideMenu visibility events [#7ee9c12](https://github.com/wix/react-native-navigation/commit/7ee9c12d53dffe3461a3c4f6721619f9ceb5eb91) by [guyca](https://github.com/guyca) +- Fix setStackRoot crash when called with the same id [#3c08b1c](https://github.com/wix/react-native-navigation/commit/3c08b1c99559a3485fb8661ca98ce256db59adb8) by [guyca](https://github.com/guyca) +- Fix crashes related to race conditions around ViewController.destroy [#f2e46ea](https://github.com/wix/react-native-navigation/commit/f2e46ea4e7f6a32164ce0a0b1e1b697544177f33) by [guyca](https://github.com/guyca) + +# 2.20.2 + +## Fixed + +### iOS + +- Fixed missing TopBar React component background [#d2d5d0f](https://github.com/wix/react-native-navigation/commit/d2d5d0fe7951e2c0c1e8d9fba247de392793a73b) by [yogevbd](https://github.com/yogevbd) + +# 2.20.1 + +## Fixed + +- Include PassProps in ComponentDidAppearListener [#c226a7d](https://github.com/wix/react-native-navigation/commit/c226a7d55193c9c630e102dce35bc02243222921) by [yogevbd](https://github.com/yogevbd) + +# 2.20.0 + +## Fixed + +- Include PassProps in layout parameter of CommandListener [#d3d01c2](https://github.com/wix/react-native-navigation/commit/d3d01c221f6c63ac36d8ef13a66e03fab980cf9f) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Fix TopBar background React component flicker when pushing screens [#99032e0](https://github.com/wix/react-native-navigation/commit/99032e060d2e0a429d3da2775884f624e8cd5fd5) by [FRizzonelli](https://github.com/FRizzonelli) + +# 2.19.1 + +## Fixed + +### Android + +- Fix missing absolute positioned views [#ecadcb0](https://github.com/wix/react-native-navigation/commit/ecadcb0f352d5c96944966deb09a7c2d570ccb2d) by [guyca](https://github.com/guyca) + +# 2.19.0 + +## Added + +- Add passProps to component typings file [#42fd86d](https://github.com/wix/react-native-navigation/commit/42fd86d654feac83177c272b19276e71c08ef75a) by [Andarius](https://github.com/Andarius) +- Add missing topBar options [#5566ffd](https://github.com/wix/react-native-navigation/commit/5566ffd47c65f7bfc608f3a0f0b19814039b541e) by [retyui](https://github.com/retyui) + +## Fixed + +### iOS + +- Fixes broken modals animations [#42e26d7](https://github.com/wix/react-native-navigation/commit/42e26d77b8d231debe0489dbe874fc06d9a97589) by [yogevbd](https://github.com/yogevbd) + +### Android + +- Fixed buggy currentTabIndex when calling setRoot multiple times [#cd182f4](https://github.com/wix/react-native-navigation/commit/cd182f4693a6a4bd943eddf9a15706d943c88d4e) by [guyca](https://github.com/guyca) + +# 2.18.5 + +## Fixed + +### iOS + +- Handle simultaneous recognizers, Fixes a crash when tapping on the screen with other gesture recognizers active [#a5b9f58](https://github.com/wix/react-native-navigation/commit/a5b9f58affd132bba03f961a255d05e41272bae9) by [jordoh](https://github.com/jordoh) + +# 2.18.4 + +## Fixed + +### iOS + +- Fix topBar.title.component fill alignment [#9f439da](https://github.com/wix/react-native-navigation/commit/9f439dabd8fabc151bb96fbb04fa34bfe2b469d8) by [yogevbd](https://github.com/yogevbd) + +# 2.18.3 + +## Fixed + +### iOS + +- Fix topBar.titleView calculation on props change [#f3b1d34](https://github.com/wix/react-native-navigation/commit/f3b1d34ea61341f08ab864b2134933ec9764b127) by [yogevbd](https://github.com/yogevbd) + +# 2.18.2 + +## Fixed + +### iOS + +- Fix TopBar react view measurement issue [#1993b93](https://github.com/wix/react-native-navigation/commit/1993b93c2ec388bce8923b6d70edf11fc5499976) by [yogevbd](https://github.com/yogevbd) + +# 2.18.1 + +## Fixed + +### iOS + +- Fix bottomTabs’s initial currentTabIndex [#0e888fb](https://github.com/wix/react-native-navigation/commit/0e888fb65a70343949386f0d6f9f59b03e7b93b7) by [yogevbd](https://github.com/yogevbd) + +# 2.18.0 + +## Fixed + +- Add missing topMargin type to OptionsTopBar [#9d7d7f4](https://github.com/wix/react-native-navigation/commit/9d7d7f4600ce4994ed680c123f59eb198130a32c) by [ceyhuno](https://github.com/ceyhuno) + +### iOS + +- Fix bottomTabs’s animate option [#9836730](https://github.com/wix/react-native-navigation/commit/9836730570f8a84c389ddf59728176fa6c828222) by [wsliaw](https://github.com/wsliaw) +- Stop keeping hard reference to ViewControllers, remove RNNStore [#275304c](https://github.com/wix/react-native-navigation/commit/275304c88e8f35bc053aec2328a94a38a6fce088) by [yogevbd](https://github.com/yogevbd) +- Return componentId on showModal [#81dc07d](https://github.com/wix/react-native-navigation/commit/81dc07d5b899ed2df1751562afc5a9703fbe0ab9) by [yogevbd](https://github.com/yogevbd) +- Apply bottomTabs options after children added [#2bddff3](https://github.com/wix/react-native-navigation/commit/2bddff390d939f21d1387645077f57cb81399970) by [yogevbd](https://github.com/yogevbd) +- Fix sideMenu orientation options [#0e1a35d](https://github.com/wix/react-native-navigation/commit/0e1a35d467fc22eab3742fd92cbf6062a645b535) by [yogevbd](https://github.com/yogevbd) +- Fix broken TextInput focus in Overlay [#e9ca247](https://github.com/wix/react-native-navigation/commit/e9ca247a524e474daf3ccf56989289ce679fc063) by [yogevbd](https://github.com/yogevbd) +- Fix TopBar react view measurement issue [#be00c4c](https://github.com/wix/react-native-navigation/commit/be00c4c36d9eee1da39f18a37240c1980cd22951) by [yogevbd](https://github.com/yogevbd) + +## 2.17.0 + +- Migrate to Detox 12 [#9428233](https://github.com/wix/react-native-navigation/commit/942823390a8d628b0e94a8d1c35301ece0bb0971) by [guyca](https://github.com/guyca) + +### Fixed + +#### iOS + +- Fix Height of SideMenu when device orientation changes [#68c62f3](https://github.com/wix/react-native-navigation/commit/68c62f33b586d1d9dfd7839ea66342861dacf534) by [mohammadalijf](https://github.com/mohammadalijf) +- adding and removing components from registry manually by presenter [#ac60d2f](https://github.com/wix/react-native-navigation/commit/ac60d2fe6ad036528c31954a2997109b06f0c947) by [yogevbd](https://github.com/yogevbd) +- Attach and detach viewControllers explicitly in store [#2830059](https://github.com/wix/react-native-navigation/commit/28300597ede5de1f08d7b32ba4a9313ffdf4aac1) by [yogevbd](https://github.com/yogevbd) +- Fix StatusBarOptions duplication in xcodeproj [#ab9fd65](https://github.com/wix/react-native-navigation/commit/ab9fd658c2abde508a42374baad983ba2a3c143d) by [tyronet-sportsbet](https://github.com/tyronet-sportsbet) + +#### Android + +- Match android dependencies to app configuration [#e954a41](https://github.com/wix/react-native-navigation/commit/e954a41e64f203b17c70a54224bcac2190c689be) by [alpha0010](https://github.com/alpha0010) +- Do not setTag to bottomTabs if testId is null [#9126ced](https://github.com/wix/react-native-navigation/commit/9126ced3bd1e0d82d966f6b45f529ac876ecc9d8) by [EliSadaka](https://github.com/EliSadaka) +- Clear sideMenu's visible options after applying [#283f226](https://github.com/wix/react-native-navigation/commit/283f226f55be633da5022692c76d90a391ec3fd8) by [ItsNoHax](https://github.com/ItsNoHax) + +## 2.16.0 + +### Fixed + +- Update app lifecycle docs [#1c740b7](https://github.com/wix/react-native-navigation/commit/1c740b74f25157bcd0b58f88c7da7716deea763b) by [ericketts](https://github.com/ericketts) + +#### iOS + +- Fix command completion event commandId [#0e29a03](https://github.com/wix/react-native-navigation/commit/0e29a03a40df26755d71c3578ca5ca554096b14c) by [yogevbd](https://github.com/yogevbd) +- Fix topBar buttons iconsInsets [#e2dcef9](https://github.com/wix/react-native-navigation/commit/e2dcef9d4a4a5efb6021e00a80f3898cc0254343) by [yogevbd](https://github.com/yogevbd) + +## 2.15.0 + +### Added + +- Add `externalComponent` prop to Layout TS declaration [#5ba7ccb](https://github.com/wix/react-native-navigation/commit/5ba7ccb75fd9e3e9ecf0b954d78704930f50d8f6) by [yedidyak](https://github.com/yedidyak) + +### Fixed + +#### iOS + +- Fix prevent retaining button component in componentRegistry [#0186b1a](https://github.com/wix/react-native-navigation/commit/0186b1ac36e919fb6b2a796677db1905b48aec7e) by [yogevbd](https://github.com/yogevbd) +- Fix and refactor animations options [#a98f187](https://github.com/wix/react-native-navigation/commit/a98f18704cc49094cd91859e75089328b4fd7cbc) by [yogevbd](https://github.com/yogevbd) +- Fix display empty custom topBar background over valid custom background [#6cb1e18](https://github.com/wix/react-native-navigation/commit/6cb1e18a883db803a5b193ca86f077d4e281a8e4) + by [RoTTex](https://github.com/RoTTex) + +## 2.14.0 + +### Fixed + +- Add direction property to Layout TS declaration [#025c5e8](https://github.com/wix/react-native-navigation/commit/025c5e8dd6a0eec75f3a27a49e52af1d252b5351) by [mohammadalijf](https://github.com/mohammadalijf) +- Add enabled property to StackAnimation TS declaration [#996f2b1](https://github.com/wix/react-native-navigation/commit/996f2b11ff4dc98d579a7c7a0ff7ab6fa8577916) by [larryranches](https://github.com/larryranches) +- [BREAKING] Rename animation options class name [#4517d22](https://github.com/wix/react-native-navigation/commit/4517d22b38a1450b8e426f8de03c4b9fdc1213e8) by [guyca](https://github.com/guyca) + +#### Android + +- Fixed title centering issues [#1899601](https://github.com/wix/react-native-navigation/commit/1899601fb99093f804f8b97773a6470a7587017c) by [hadimostafapour](https://github.com/hadimostafapour) +- Cancel in-flight push animation on pop [#47b7d2c](https://github.com/wix/react-native-navigation/commit/47b7d2c7c54af861e99b922aa258489d86c9c0b2) by [guyca](https://github.com/guyca) +- Fix crash when calling setStackRoot multiple times in quick succession [#fdee254](https://github.com/wix/react-native-navigation/commit/fdee25422f6568be4ba5507b26f470b511decc95) by [guyca](https://github.com/guyca) +- External component lifecycle events [#602c669](https://github.com/wix/react-native-navigation/commit/602c669b02b31c45b040965e27c327c2bd0fde61) by [guyca](https://github.com/guyca) + +#### iOS + +- Fix iOS pop gesture when topBar is hidden [#81d8b69](https://github.com/wix/react-native-navigation/commit/81d8b69d61934e4702d59d531ce84294c9b92c55) by [rawrmaan](https://github.com/rawrmaan) + +## 2.13.1 + +### Fixed + +- Moved `react-native-uilib` to dev dependencies [#2c514d9](https://github.com/wix/react-native-navigation/commit/2c514d931f74cf97807cb565672ddce50644349f) by [guyca](https://github.com/guyca) + +## 2.13.0 + +### Added + +- Add `enabled?` property to interface OptionsAnimationProperties [#6065bd1](https://github.com/wix/react-native-navigation/commit/6065bd1345ef5087d9dea92c9c332ba42619411f) by [taichi-jp](https://github.com/taichi-jp) + +### Fixed + +#### iOS + +- Fixes initial screen size [#e036743](https://github.com/wix/react-native-navigation/commit/e03674381315f92292add444055aeaba791076d3) by [yogevbd](https://github.com/yogevbd) +- Fix top bar buttons size on iOS 10 [#8282d93](https://github.com/wix/react-native-navigation/commit/8282d934f70d512548d6d4ceae25e9798d591141) by [yogevbd](https://github.com/yogevbd) +- Prevent keyboard from hiding when overlay is shown [#aba58b6](https://github.com/wix/react-native-navigation/commit/aba58b6c5aa4b39a0fb76fa2f8ebbd28dc80952e) by [tomhicks](https://github.com/tomhicks) + +#### Android + +- Fix loading local images [#c82bc57](https://github.com/wix/react-native-navigation/commit/c82bc57d58227f8ecb54e7cf351da46b38b4f8f9) by [guyca](https://github.com/guyca) +- Update side menu options on open / close callback [#43f05ee](https://github.com/wix/react-native-navigation/commit/43f05ee01574c18d216acfb510be4b5e38165e4d) by [gosuperninja](https://github.com/gosuperninja) +- Fix overflow visible for react button components in TopBar [#54ff1cd](https://github.com/wix/react-native-navigation/commit/54ff1cd049b7a418f7fd2658f569d06853bcea6c) by [guyca](https://github.com/guyca) + +## 2.12.0 + +### Added + +- Add waitForRender to root animation options [#298ec43](https://github.com/wix/react-native-navigation/commit/298ec43f27eb9a031c7168675c40ab5be47396ec) by [guyca](https://github.com/guyca) + +#### Android + +- RTL support [#d09d010](https://github.com/wix/react-native-navigation/commit/d09d0108d1530cf10e24c46efb6c9d9962807ead) by [hadimostafapour](https://github.com/hadimostafapour) + +### Fixed + +- Stop using lodash in store.js [#8ba9796](https://github.com/wix/react-native-navigation/commit/8ba9796d2d94c5dd58266841c2563bbcd563f635) by [guyca](https://github.com/guyca) + +#### iOS + +- Use autolayout constraints to set size of custom bar button item [#362606b](https://github.com/wix/react-native-navigation/commit/362606b82ed4de37e05ebf8603739b16adf0e0d2) by [eliperkins](https://github.com/eliperkins) +- Ignore pan gesture when no drawer is enabled [#664ef34](https://github.com/wix/react-native-navigation/commit/664ef343090051049213eb5d56285e0432b4e2d7) by [StasDoskalenko](https://github.com/StasDoskalenko) +- Fix peek and pop preview on iOS [#e7c0d16](https://github.com/wix/react-native-navigation/commit/e7c0d166cb70fa27edf68eae8a00f23257eddf9a) by [yogevbd](https://github.com/yogevbd) +- Fix launch image matching for iPhone XR/XS Max portrait [#dfd894a](https://github.com/wix/react-native-navigation/commit/dfd894ab2f4ab434548a4ef57f0eb176ee17627f) by [oblador](https://github.com/oblador) + +## 2.11.0 + +### Fixed + +#### iOS + +- Support updating bottomTab options [#2362655](https://github.com/wix/react-native-navigation/commit/23626556cf9ae4c161993b39776098855117d928) by [rsispal](https://github.com/rsispal) + +#### Android + +- Fix android build for RN 0.58.x [#600a1d1](https://github.com/wix/react-native-navigation/commit/600a1d188b634b7834c1720620336dd5d02bfd80) by [alpha0010](https://github.com/alpha0010) + +## 2.10.0 + +### Added + +#### iOS + +- Add Icon insets support for topBar buttons [#545e5fe](https://github.com/wix/react-native-navigation/commit/545e5fef5fa570aaa20d95bbb40ed9aed72fc480) by [yogevbd](https://github.com/yogevbd) +- SetRoot wait for render [#5abea28](https://github.com/wix/react-native-navigation/commit/5abea28c53ed34dc822641f30abe2190c08f8185) by [yogevbd](https://github.com/yogevbd) + +### Fixed + +#### iOS + +- Improved RNNSplashScreen status bar styling [#b3b88d1](https://github.com/wix/react-native-navigation/commit/b3b88d15bbb730b96de1fa2c0378d0f3c59b53ab) by [danielgindi](https://github.com/danielgindi) + +#### Android + +- Null check when parsing strings [#eda4b9c](https://github.com/wix/react-native-navigation/commit/eda4b9ce0a6a9b732241f662012a1e7e5750e193) by [guyca](https://github.com/guyca) +- Fixed modalDismissed event being emitted with wrong id [#aef7745](https://github.com/wix/react-native-navigation/commit/aef7745cd3a8d9cfce69f9553c8c01b9bdf1cc06) by [guyca](https://github.com/guyca) + +## 2.9.0 + +### Fixed + +#### iOS + +- Improve SplitView and BottomTabs interactions [#954e734](https://github.com/wix/react-native-navigation/commit/954e7348d78d97477927beb0f1ad3f1e37fedf65) by [zzorba](https://github.com/zzorba) +- SplitView options are handled by presenter [#00d5e31](https://github.com/wix/react-native-navigation/commit/00d5e313f8992cac5b7fb2301515d8e35e20c2f8) by [zzorba](https://github.com/zzorba) +- Fixes Large title and noBorder issue which caused color to change to default [#9c48a78](https://github.com/wix/react-native-navigation/commit/9c48a78bc2c01e68e3d9d184f5df637f6b331c53) by [mohammadalijf](https://github.com/mohammadalijf) +- Pull BottomTabs height from correct controller [#8cee745](https://github.com/wix/react-native-navigation/commit/8cee74533489e1877ffea95c1622bd4ab6fb33ff) by [paubins](https://github.com/paubins) + +#### Android + +- Fix custom back button missing id [#578f6a8](https://github.com/wix/react-native-navigation/commit/578f6a8eeac543b64dce5637d6e6e856c5fdda1b) by [guyca](https://github.com/guyca) +- Fix Android title centering [#4aa5cd1](https://github.com/wix/react-native-navigation/commit/4aa5cd17bfb8a2acad884e2614eef137698b0f5a) by [StasDoskalenko](https://github.com/StasDoskalenko) + +## 2.8.0 + +### Added + +- passProps passed to setStackRoot and showOverlay can specify type with generics [#bc23fba](https://github.com/wix/react-native-navigation/commit/bc23fbad608dc9e38a7f09ff76868867310a4d62) by [henrikra](https://github.com/henrikra) +- passProps passed to showModal can specify type with generics [#34f37aa](https://github.com/wix/react-native-navigation/commit/34f37aa7c5790e10b3f7db8c5a2af23c6848c6c8) by [ruscoder](https://github.com/ruscoder) + +#### Android + +- Bottom tabs attach mode [#740ad3c](https://github.com/wix/react-native-navigation/commit/740ad3c326f29f51205b8f0fb046ff0658076925) by [guyca](https://github.com/guyca) + +### Fixed + +#### iOS + +- Fix system & back button color [#57d8ff7](https://github.com/wix/react-native-navigation/commit/57d8ff7858f550ade133422e4a02505ed6378968) by [maryjenel](https://github.com/maryjenel) + +## 2.7.1 + +### Fixed + +#### Android + +- Fix broken static options provided as objects [#4d82292](https://github.com/wix/react-native-navigation/commit/4d82292950471979cfb6c4016e82665fa29fe9da) by [guyca](https://github.com/guyca) + +## 2.7.0 + +### Added + +- Adding hideNavBarOnFocusSearchBar option [#83f69d4](https://github.com/wix/react-native-navigation/commit/83f69d4effecfbaaf17af3cebdf8a03b38bfa589) by [sganti564](https://github.com/sganti564) + +### Fixed + +- Add missing type interface "waitForRender" [#f1ef49e](https://github.com/wix/react-native-navigation/commit/f1ef49e7aeb63ec17b4165cac9d7e9d0cfe6d48e) by [minhtc](https://github.com/minhtc) + +### Android + +- Fix title height not being set on Android [#09c8c37](https://github.com/wix/react-native-navigation/commit/09c8c37e644fa0af2f00a7ec0536d814cddc36fd) by [davrosull](https://github.com/davrosull) +- Support calling mergeOptions on ExternalComponents [#b1e1ec8](https://github.com/wix/react-native-navigation/commit/b1e1ec84ae5f41693e69da17f7427b59e336fc6a) by [guyca](https://github.com/guyca) + +## 2.6.0 + +### Added + +#### iOS + +- Support iOS system item icons for top bar [#7a26ea9](https://github.com/wix/react-native-navigation/commit/7a26ea956cfce65035ec902ef3f403f178b69317) by [BerndSchrooten](https://github.com/BerndSchrooten) + +### Fixed + +- Road to noImplicitAny part 6 (FINAL part) [#08f8581](https://github.com/wix/react-native-navigation/commit/08f8581b3fbf95967a9cc95de2809316065ee275) by [henrikra](https://github.com/henrikra) + +#### Android + +- Fix ScrollView not scrollable in Overlay [#d3ab1ac](https://github.com/wix/react-native-navigation/commit/d3ab1ac526f5829fe74989144130a13d83795ad8) by [guyca](https://github.com/guyca) + +#### iOS + +- Fixed settings backButton color dynamically [#8434938](https://github.com/wix/react-native-navigation/commit/84349384958ee9f0d03d24c6ef087cc5b7661d4b) by [masarusanjp](https://github.com/masarusanjp) + +## 2.5.2 + +### Fixed + +#### Android + +- Revert "Set elevation 0 when creating TopBar" [#135c6eb](https://github.com/wix/react-native-navigation/commit/135c6eb7b240d81e3781e564f021883191736504) by [guyca](https://github.com/guyca) +- Only set elevation values from Options [#487c1da](https://github.com/wix/react-native-navigation/commit/487c1da9dc5277d1ad0e7ca0e410b1c4b5dbc61e) by [guyca](https://github.com/guyca) + +## 2.5.1 + +### Fixed + +#### Android + +- Set elevation 0 when creating TopBar [#05dacbd](https://github.com/wix/react-native-navigation/commit/05dacbd0729f4ebf0074bd21c50f3bf813ad7fab) by [guyca](https://github.com/guyca) + +## 2.5.0 + +### Fixed + +- Road to implicit any part 5 [#ee6dc78](https://github.com/wix/react-native-navigation/commit/ee6dc788023ca78a51834206f9823ca85abd273e) by [henrikra](https://github.com/henrikra) +- Road to implicitAny part 4 [#02985c5](https://github.com/wix/react-native-navigation/commit/02985c507a61c5534f63f134c3f5fecbf6218908) by [henrikra](https://github.com/henrikra) +- Fixed the type mismatch for modalPresentationStyle [#9ef60e9](https://github.com/wix/react-native-navigation/commit/9ef60e9bd9f940c47b7efd05ca104b5404a66d3b) by [masarusanjp](https://github.com/masarusanjp) + +#### Android + +- Render first tab first [#e5a2efb](https://github.com/wix/react-native-navigation/commit/e5a2efb0d9237cae82fbadb92c3a86d0f01c3b5f) by [guyca](https://github.com/guyca) +- Retrieve BuildConfig.DEBUG from Application in ImageLoader [#b422dd0](https://github.com/wix/react-native-navigation/commit/b422dd0761183edc5f6e5006ba5d5e9b06b9561b) by [guyca](https://github.com/guyca) + +#### iOS + +- Fix sideMenu intuitive side width [#07cc9d3](https://github.com/wix/react-native-navigation/commit/07cc9d3f6212c9bad59767e0a12ae9243de126f7) by [yogevbd](https://github.com/yogevbd) + +## 2.4.0 + +### Added + +#### Android + +- Add fab.iconColor option to tint fab icon [#13de5ca](https://github.com/wix/react-native-navigation/commit/13de5cab70834ca5d38f02c512346753dec6c5ed) by [guyca](https://github.com/guyca) + +### Fixed + +- Refactor options processor [#ee04610](https://github.com/wix/react-native-navigation/commit/ee04610f6a9c9117f9ae8c17ae6d9ce9ca132883) by [henrikra](https://github.com/henrikra) + +#### Android + +- Fix closing sideMenu when pushing a screen [#dc739de](https://github.com/wix/react-native-navigation/commit/dc739dee337b91c825992e3a77cdcf0262fee162) by [guyca](https://github.com/guyca) +- Orientation.hasValue returns false for default orientation [#43ae659](https://github.com/wix/react-native-navigation/commit/43ae659097f8b6d2cf8897703034829172573fb7) by [guyca](https://github.com/guyca) +- Measure TopBar buttons using using MeasureSpec.UNSPECIFIED [#dd93c51](https://github.com/wix/react-native-navigation/commit/dd93c5147aaac16c852e4795f39abc455f77c90b) by [guyca](https://github.com/guyca) + +## v2.3.0 + +### Added + +#### Android + +- Add `layout.componentBackgroundColor` option - This option is used to set background color only for component layouts. [#cb48065](https://github.com/wix/react-native-navigation/commit/cb48065aaffa0449f1cd57b27bd3de6bb5a0eac8) by [guyca](https://github.com/guyca) + +### Fixed + +- SetStackRoot now accepts an array of children which will replace the current children. [#2365e02](https://github.com/wix/react-native-navigation/commit/2365e0211b51a2353949c22a836340eb32cd8cc0) by [guyca](https://github.com/guyca) + +#### Android + +- Avoid unnecessary BottomTabs view creation. [#b84a3e5](https://github.com/wix/react-native-navigation/commit/b84a3e5fadcbef93a8ef683550743dc84ac8a2fa) by [guyca](https://github.com/guyca) + +## v2.2.5 + +### Added + +- Add typed interface to constants [#a71e731](https://github.com/wix/react-native-navigation/commit/a71e7311e270d2feb793c7c61b8e637afe98591e) by [pie6k](https://github.com/pie6k) +- Remove some implicit anys and refactor tests [#c27fa5c](https://github.com/wix/react-native-navigation/commit/c27fa5c97a163b6578058fb3edad8753934b0ada) by [henrikra](https://github.com/henrikra) +- Improve support for Context API and other Provider based apis [#9d36521](https://github.com/wix/react-native-navigation/commit/9d365216d968cb441d02ede36cc21608e091dfed) by [guyca](https://github.com/guyca) + +### Fixed + +#### iOS + +- Fix setting bottomTabs.currentTabIndex on bottomTabs init [#631e7db](https://github.com/wix/react-native-navigation/commit/631e7dbd555ab171679b021207091ae5d9f2f882) by [yogevbd](https://github.com/yogevbd) + +## v2.2.2 - v2.2.4 + +Skipped versions due to CI maintenance + +## v2.2.1 + +### Fixed + +#### iOS + +- Fix title.font when subtitle supplied - Font wasn't applied on title, when subtitel was provided. [#14a5b74](https://github.com/wix/react-native-navigation/commit/14a5b748fa461a9c4bd50ca0148a0e13a8ae6fba) by [yogevbd](https://github.com/yogevbd) +- Fix invisible modals edge case. When an Overlay was displayed before setRoot was called, Consecutive Modals and Overlays were attached to the wrong window. [#b40f8ed](https://github.com/wix/react-native-navigation/commit/b40f8eda6eea09c465b9cf0e29269fef6238dae0) by [yogevbd](https://github.com/yogevbd) + +## v2.2.0 + +### Added + +- Component name can be a number as well to support enum component names [#e32d8d2](https://github.com/wix/react-native-navigation/commit/e32d8d2c1a30e4a50b6b1f6ed8eeb99b81b58cde) by [henrikra](https://github.com/henrikra) +- Update lodash to v4.17.x [#77e2faa](https://github.com/wix/react-native-navigation/commit/77e2faa5988c1e7905bc138030422291413213e0) by [guyca](https://github.com/guyca) + +#### iOS + +- Add sideMenu.openGestureMode option [#0a4bf2a](https://github.com/wix/react-native-navigation/commit/0a4bf2ade3b8b98041c8a6057d26a254e193d84d) by [yogevbd](https://github.com/yogevbd) + +### Fixed + +- Add props to TopBarButton type [#4373](https://github.com/wix/react-native-navigation/pull/4373) by [gsdatta](https://github.com/gsdatta) +- Add title alignment to OptionsTopBarTitle [#bd00422](https://github.com/wix/react-native-navigation/commit/bd004225b64c6e4a0bca45103ca0c1ebdbd80ad3) by [minhloi](https://github.com/minhloi) + +#### iOS + +- popGesture on stack root freezes the app [#4388](https://github.com/wix/react-native-navigation/issues/4388) by [yogevbd](https://github.com/yogevbd) +- setRoot on main application window - fix setRoot on iPad [a3922f8](https://github.com/wix/react-native-navigation/commit/a3922f84815a80b094416b4ce2bee342f21890a6) by [yogevbd](https://github.com/yogevbd) +- Fix "Multiple commands produce..." build error on Xcode 10 [#b5d300f](https://github.com/wix/react-native-navigation/commit/b5d300f0506e3e8098de5be0390b58eea32eb085) by [yogevbd](https://github.com/yogevbd) + +#### Android + +- Use proper key for bottom tab height [#3b98553](https://github.com/wix/react-native-navigation/commit/3b9855327363149613f371e6eb47727fc8430aab) by [Krizzu](https://github.com/Krizzu) + +## 2.1.3 + +### Added + +#### iOS + +- Add optional componentId param to bindComponent [#0a6e34f](https://github.com/wix/react-native-navigation/commit/0a6e34f2dd16bbec43edd37c93c0f609b6c589f2) by [luigiinred](https://github.com/luigiinred) + +### Fixed + +- Avoid calling component generators on registerComponent [#708d594](https://github.com/wix/react-native-navigation/commit/708d594877f223e684df749faff2a3e8abdbe9a8) by [yogevbd](https://github.com/yogevbd) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000000..bf4bd4be9d8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1 @@ +See https://wix.github.io/react-native-navigation/docs/meta-contributing/ diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000000..1142b1b209a --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version +ruby '>= 2.6.10' + +gem 'cocoapods', '>= 1.11.3' diff --git a/LICENSE b/LICENSE index 1fc000867f6..869314b4099 100644 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,21 @@ -The MIT License (MIT) +MIT License -Copyright (c) Wix.com +Copyright (c) 2016 Wix.com -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Mock.ts b/Mock.ts new file mode 100644 index 00000000000..96a78fad355 --- /dev/null +++ b/Mock.ts @@ -0,0 +1 @@ +export * from './lib/Mock'; diff --git a/README.md b/README.md index eab2b6b98ad..04fbb42b1c6 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,37 @@ +[![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine)

-
+
React Native Navigation

-[![NPM Version](https://img.shields.io/npm/v/react-native-navigation.svg?style=flat)](https://www.npmjs.com/package/react-native-navigation) -[![NPM Downloads](https://img.shields.io/npm/dm/react-native-navigation.svg?style=flat)](https://www.npmjs.com/package/react-native-navigation) -[![Build Status](https://travis-ci.org/wix/react-native-navigation.svg?branch=master)](https://travis-ci.org/wix/react-native-navigation) -[![Join us on Discord](https://img.shields.io/badge/discord-react--native--navigation-738bd7.svg?style=flat)](https://discord.gg/DhkZjq2) +

+ NPM downloads + NPM latest version + NPM snapshot version + NPM snapshot version -## Important -Latest stable version is `1.1.x` and is published to npm under tag `latest`. It supports react-native >= 0.43. -

We are currently redesigning and rewriting this project under branch `v2`. -
As a result, new features and pull requests on the current stable version will take more time to process. +

+

+ Follow on Twitter + Chat on Discord + StackExchange +

-### tl;dr +React Native Navigation provides 100% native platform navigation on both iOS and Android for React Native apps. The JavaScript API is simple and cross-platform - just install it in your app and give your users the native feel they deserve. Ready to get started? Check out the [docs](https://wix.github.io/react-native-navigation/). -React Native Navigation provides 100% native platform navigation on both iOS and Android for React Native apps. The JavaScript API is simple and cross-platform - just install it in your app and give your users the native feel they deserve. Using redux? No problem: React Native Navigation comes with optional redux support out of the box. Ready to get started? Check out the [docs](https://wix.github.io/react-native-navigation/). +# Quick Links -### Real world examples +- [Documentation](https://wix.github.io/react-native-navigation/) +- [Changelog](https://github.com/wix/react-native-navigation/blob/master/CHANGELOG.md) +- [Stack Overflow](http://stackoverflow.com/questions/tagged/wix-react-native-navigation) +- [Chat with us](https://discord.gg/DhkZjq2) +- [Contributing](https://wix.github.io/react-native-navigation/docs/meta-contributing) -     - +# Requirements -On the left - The Wix app. +Apps using React Native Navigation may target iOS 11 and Android 5.0 (API 21). You may use Windows, macOS or Linux as your development operating system. -On the right - The example app. +# Installation - -## Quick Links -* [Documentation](https://wix.github.io/react-native-navigation/#/) -* [Stack Overflow](http://stackoverflow.com/questions/tagged/react-native-navigation) -* [Chat with us](https://discord.gg/DhkZjq2) -* Bootstrap - If you prefer to learn more about the library and the APIs through code, head over to [the bootstrap example app](https://github.com/wix/react-native-navigation-bootstrap) or the more feature rich [JuneDomingo/movieapp](https://github.com/JuneDomingo/movieapp) -* [v2 - Under Development](https://github.com/wix/react-native-navigation/tree/v2#react-native-navigation-v2-wip) - ----- - -One of the major things missing from React Native core is fully featured native navigation. Navigation includes the entire skeleton of your app with critical components like nav bars, tab bars and side menu drawers. - -If you're trying to deliver a user experience that's on par with the best native apps out there, you simply can't compromise on JS-based components trying to fake the real thing. - -For example, this package replaces the native [NavigatorIOS](https://facebook.github.io/react-native/docs/navigatorios.html) that has been [abandoned](https://facebook.github.io/react-native/docs/navigator-comparison.html) in favor of JS-based solutions that are easier to maintain. For more details see in-depth discussion [here](https://github.com/wix/react-native-controllers#why-do-we-need-this-package). - - -## License - -The MIT License. - -See [LICENSE](LICENSE) +As `react-native-navigation` is a native navigation library - integrating it into your app will require editing native files. Follow the installation guides in the [documentation](https://wix.github.io/react-native-navigation/). diff --git a/ReactNativeNavigation.podspec b/ReactNativeNavigation.podspec new file mode 100644 index 00000000000..1777dc62b01 --- /dev/null +++ b/ReactNativeNavigation.podspec @@ -0,0 +1,96 @@ +require 'json' +require 'find' + +package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) + +fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' + +# Detect if this is a Swift project by looking for user AppDelegate.swift files +start_dir = File.expand_path('../../', __dir__) +swift_delegate_path = nil +Find.find(start_dir) do |path| + if path =~ /AppDelegate\.swift$/ + swift_delegate_path = path + break + end +end + +swift_project = swift_delegate_path && File.exist?(swift_delegate_path) + +# Debug output +if swift_project + puts "ReactNativeNavigation: Swift AppDelegate detected - enabling Swift-compatible configuration" +else + puts "ReactNativeNavigation: Objective-C AppDelegate detected - using standard configuration" +end + +Pod::Spec.new do |s| + s.name = "ReactNativeNavigation" + s.version = package['version'] + s.summary = package['description'] + + s.authors = "Wix.com" + s.homepage = package['homepage'] + s.license = package['license'] + s.platform = :ios, "11.0" + + s.module_name = 'ReactNativeNavigation' + s.default_subspec = 'Core' + + s.subspec 'Core' do |ss| + s.source = { :git => "https://github.com/wix/react-native-navigation.git", :tag => "#{s.version}" } + s.source_files = 'lib/ios/**/*.{h,m,mm,cpp}' + s.exclude_files = "lib/ios/ReactNativeNavigationTests/**/*.*", "lib/ios/OCMock/**/*.*" + # Only expose headers for Swift projects + if swift_project + s.public_header_files = [ + 'lib/ios/RNNAppDelegate.h' + ] + end + end + + folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32 -DFOLLY_CFG_NO_COROUTINES=1' + + # Base xcconfig settings + xcconfig_settings = { + 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/boost" "$(PODS_ROOT)/boost-for-react-native" "$(PODS_ROOT)/RCT-Folly" "$(PODS_ROOT)/Headers/Private/React-Core" "$(PODS_ROOT)/Headers/Private/Yoga"', + "CLANG_CXX_LANGUAGE_STANDARD" => "c++20", + "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", + } + + # Only add DEFINES_MODULE for Swift projects + if swift_project + xcconfig_settings["DEFINES_MODULE"] = "YES" + end + + s.pod_target_xcconfig = xcconfig_settings + + if fabric_enabled + install_modules_dependencies(s) + + s.compiler_flags = folly_compiler_flags + ' ' + '-DRCT_NEW_ARCH_ENABLED' + ' ' + '-DUSE_HERMES=1' + s.requires_arc = true + + s.dependency "React" + s.dependency "React-RCTFabric" + s.dependency "React-cxxreact" + s.dependency "React-Fabric" + s.dependency "React-Codegen" + s.dependency "RCT-Folly" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon" + s.dependency "React-runtimeexecutor" + s.dependency "React-rncore" + s.dependency "React-RuntimeCore" + else + s.compiler_flags = folly_compiler_flags + end + + s.dependency 'React-Core' + s.dependency 'React-CoreModules' + s.dependency 'React-RCTImage' + s.dependency 'React-RCTText' + s.dependency 'HMSegmentedControl' + s.frameworks = 'UIKit' +end diff --git a/android/app/build.gradle b/android/app/build.gradle deleted file mode 100644 index 51f8df937cb..00000000000 --- a/android/app/build.gradle +++ /dev/null @@ -1,64 +0,0 @@ -apply plugin: 'com.android.library' -apply from: '../prepare-robolectric.gradle' - -android { - compileSdkVersion 25 - buildToolsVersion "25.0.1" - - defaultConfig { - minSdkVersion 16 - targetSdkVersion 23 - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false - } - debug { - minifyEnabled false - } - } - lintOptions { - abortOnError false - } - - testOptions { - unitTests.all { t -> - reports { - html.enabled true - } - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - } - afterSuite { desc, result -> - if (!desc.parent) { // will match the outermost suite - def output = " ${result.resultType} (${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped) " - def repeatLength = output.length() - println '\n' + ('-' * repeatLength) + '\n' + output + '\n' + ('-' * repeatLength) + '\n' - - println "see report at file://${t.reports.html.destination}/index.html" - } - } - } - } -} - -dependencies { - compile fileTree(dir: "libs", include: ["*.jar"]) - - compile 'com.android.support:design:25.3.1' - compile "com.android.support:appcompat-v7:25.3.1" - - // node_modules - compile "com.facebook.react:react-native:+" - - // third party - compile "com.aurelhubert:ahbottomnavigation:2.0.6" - compile 'com.balysv.materialmenu:material-menu-toolbar:1.5.4' - - // tests - testCompile "junit:junit:4.12" - testCompile "org.robolectric:robolectric:3.1.4" - testCompile 'org.assertj:assertj-core:2.5.0' -} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 7cb0951b45b..00000000000 --- a/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - diff --git a/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java b/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java deleted file mode 100644 index d1c3b12f4bd..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/NavigationApplication.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.reactnativenavigation; - -import android.app.Application; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.support.annotation.Nullable; -import android.support.v4.app.ActivityOptionsCompat; - -import com.facebook.react.ReactApplication; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.uimanager.UIManagerModule; -import com.reactnativenavigation.bridge.EventEmitter; -import com.reactnativenavigation.controllers.ActivityCallbacks; -import com.reactnativenavigation.react.NavigationReactGateway; -import com.reactnativenavigation.react.ReactGateway; - -import java.util.List; - -public abstract class NavigationApplication extends Application implements ReactApplication { - - public static NavigationApplication instance; - - private NavigationReactGateway reactGateway; - private EventEmitter eventEmitter; - private Handler handler; - private ActivityCallbacks activityCallbacks; - - @Override - public void onCreate() { - super.onCreate(); - instance = this; - handler = new Handler(getMainLooper()); - reactGateway = new NavigationReactGateway(); - eventEmitter = new EventEmitter(reactGateway); - activityCallbacks = new ActivityCallbacks(); - } - - @Override - public void startActivity(Intent intent) { - String animationType = intent.getStringExtra("animationType"); - if (animationType != null && animationType.equals("fade")) { - Bundle bundle = ActivityOptionsCompat.makeCustomAnimation(getApplicationContext(), - android.R.anim.fade_in, - android.R.anim.fade_out - ).toBundle(); - super.startActivity(intent, bundle); - } else { - super.startActivity(intent); - } - } - - public void startReactContextOnceInBackgroundAndExecuteJS() { - reactGateway.startReactContextOnceInBackgroundAndExecuteJS(); - } - - public void runOnMainThread(Runnable runnable) { - handler.post(runnable); - } - - public void runOnMainThread(Runnable runnable, long delay) { - handler.postDelayed(runnable, delay); - } - - public ReactGateway getReactGateway() { - return reactGateway; - } - - public ActivityCallbacks getActivityCallbacks() { - return activityCallbacks; - } - - protected void setActivityCallbacks(ActivityCallbacks activityLifecycleCallbacks) { - this.activityCallbacks = activityLifecycleCallbacks; - } - - public boolean isReactContextInitialized() { - return reactGateway.isInitialized(); - } - - public void onReactInitialized(ReactContext reactContext) { - // nothing - } - - @Override - public ReactNativeHost getReactNativeHost() { - return reactGateway.getReactNativeHost(); - } - - public EventEmitter getEventEmitter() { - return eventEmitter; - } - - public UIManagerModule getUiManagerModule() { - return getReactGateway() - .getReactInstanceManager() - .getCurrentReactContext() - .getNativeModule(UIManagerModule.class); - } - - /** - * @see ReactNativeHost#getJSMainModuleName() - */ - @Nullable - public String getJSMainModuleName() { - return null; - } - - /** - * @see ReactNativeHost#getJSBundleFile() - */ - @Nullable - public String getJSBundleFile() { - return null; - } - - /** - * @see ReactNativeHost#getBundleAssetName() - */ - @Nullable - public String getBundleAssetName() { - return null; - } - - public abstract boolean isDebug(); - - public boolean clearHostOnActivityDestroy() { - return true; - } - - @Nullable - public abstract List createAdditionalReactPackages(); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/animation/PeekingAnimator.java b/android/app/src/main/java/com/reactnativenavigation/animation/PeekingAnimator.java deleted file mode 100644 index f0905586b32..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/animation/PeekingAnimator.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.reactnativenavigation.animation; - -import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.view.View; -import android.view.animation.OvershootInterpolator; - -import com.reactnativenavigation.params.SlidingOverlayParams.Position; - -import static android.view.View.TRANSLATION_Y; - -public class PeekingAnimator { - - private static final int SLIDE_OUT_DURATION = 300; - private static final int SLIDE_IN_DURATION = 600; - - private final Animator animator; - - public PeekingAnimator(View view, Position position, final boolean show) { - final int offsetPixels = view.getHeight() * (position == Position.Top ? -1 : 1); - - this.animator = show ? - createSlideInAnimator(view, offsetPixels) : - createSlideOutAnimator(view, offsetPixels); - } - - public void addListener(Animator.AnimatorListener listener) { - this.animator.addListener(listener); - } - - public void animate() { - animator.start(); - } - - private ObjectAnimator createSlideInAnimator(View view, int offset) { - - view.setTranslationY(offset); - - ObjectAnimator slideIn = ObjectAnimator.ofFloat(view, TRANSLATION_Y, 0); - slideIn.setDuration(SLIDE_IN_DURATION); - slideIn.setInterpolator(new OvershootInterpolator(0.8f)); - return slideIn; - } - - private ObjectAnimator createSlideOutAnimator(View view, int offset) { - ObjectAnimator slideOut = ObjectAnimator.ofFloat(view, TRANSLATION_Y, offset); - slideOut.setDuration(SLIDE_OUT_DURATION); - return slideOut; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/animation/VisibilityAnimator.java b/android/app/src/main/java/com/reactnativenavigation/animation/VisibilityAnimator.java deleted file mode 100644 index dec6bd150ef..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/animation/VisibilityAnimator.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.reactnativenavigation.animation; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.support.annotation.Nullable; -import android.support.v4.view.animation.LinearOutSlowInInterpolator; -import android.view.View; - -public class VisibilityAnimator { - - private final LinearOutSlowInInterpolator interpolator = new LinearOutSlowInInterpolator(); - private ObjectAnimator animator; - - public enum HideDirection { - Up, Down - } - - private static final int SHOW_END_VALUE = 0; - private static final int DURATION = 300; - - private final View view; - private final int hiddenEndValue; - - public VisibilityAnimator(View view, HideDirection hideDirection, int height) { - this.view = view; - this.hiddenEndValue = hideDirection == HideDirection.Up ? -height : height; - } - - public void setVisible(boolean visible, boolean animate, @Nullable Runnable onAnimationEnd) { - cancelAnimator(); - if (visible) { - show(animate, onAnimationEnd); - } else { - hide(animate, onAnimationEnd); - } - } - - private void cancelAnimator() { - if (animator != null && animator.isRunning()) { - view.clearAnimation(); - animator.cancel(); - } - } - - private void show(boolean animate, @Nullable Runnable onAnimationEnd) { - if (animate) { - animator = createAnimator(true, onAnimationEnd); - animator.start(); - } else { - view.setTranslationY(SHOW_END_VALUE); - view.setVisibility(View.VISIBLE); - if (onAnimationEnd != null) onAnimationEnd.run(); - } - } - - private void hide(boolean animate, @Nullable Runnable onAnimationEnd) { - if (animate) { - animator = createAnimator(false, onAnimationEnd); - animator.start(); - } else { - view.setTranslationY(hiddenEndValue); - view.setVisibility(View.GONE); - if (onAnimationEnd != null) onAnimationEnd.run(); - } - } - - private ObjectAnimator createAnimator(final boolean show, @Nullable final Runnable onAnimationEnd) { - view.setVisibility(View.VISIBLE); - final ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, show ? SHOW_END_VALUE : hiddenEndValue); - animator.setDuration(DURATION); - animator.setInterpolator(interpolator); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onAnimationEnd != null) onAnimationEnd.run(); - } - }); - return animator; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/bridge/BundleConverter.java b/android/app/src/main/java/com/reactnativenavigation/bridge/BundleConverter.java deleted file mode 100644 index 0ab6f4c27a2..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/bridge/BundleConverter.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.reactnativenavigation.bridge; - -import android.os.Bundle; - -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableMapKeySetIterator; - -public class BundleConverter { - public static Bundle toBundle(ReadableMap map) { - Bundle bundle = new Bundle(); - ReadableMapKeySetIterator it = map.keySetIterator(); - while (it.hasNextKey()) { - String key = it.nextKey(); - switch (map.getType(key)) { - case Null: - break; - case Boolean: - bundle.putBoolean(key, map.getBoolean(key)); - break; - case Number: - putNumber(bundle, map, key); - break; - case String: - bundle.putString(key, map.getString(key)); - break; - case Map: - bundle.putBundle(key, toBundle(map.getMap(key))); - break; - case Array: - bundle.putBundle(key, toBundle(map.getArray(key))); - break; - default: - break; - } - } - return bundle; - } - - private static void putNumber(Bundle bundle, ReadableMap map, String key) { - try { - bundle.putInt(key, map.getInt(key)); - } catch (Exception e) { - bundle.putDouble(key, map.getDouble(key)); - } - } - - public static Bundle toBundle(ReadableArray array) { - Bundle bundle = new Bundle(); - for (int i = 0; i < array.size(); i++) { - String key = String.valueOf(i); - switch (array.getType(i)) { - case Null: - break; - case Boolean: - bundle.putBoolean(key, array.getBoolean(i)); - break; - case Number: - bundle.putDouble(key, array.getDouble(i)); - break; - case String: - bundle.putString(key, array.getString(i)); - break; - case Map: - bundle.putBundle(key, toBundle(array.getMap(i))); - break; - case Array: - bundle.putBundle(key, toBundle(array.getArray(i))); - break; - default: - break; - } - } - return bundle; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/bridge/EventEmitter.java b/android/app/src/main/java/com/reactnativenavigation/bridge/EventEmitter.java deleted file mode 100644 index a271d6da6e8..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/bridge/EventEmitter.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.reactnativenavigation.bridge; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.BaseScreenParams; -import com.reactnativenavigation.react.ReactGateway; -import com.reactnativenavigation.screens.NavigationType; - -public class EventEmitter { - private ReactGateway reactGateway; - - public EventEmitter(ReactGateway reactGateway) { - this.reactGateway = reactGateway; - } - - public void sendWillAppearEvent(BaseScreenParams params, NavigationType type) { - sendScreenChangedEventToJsScreen("willAppear", params.getNavigatorEventId()); - sendGlobalScreenChangedEvent("willAppear", params.timestamp, params.screenId, type); - } - - public void sendDidAppearEvent(BaseScreenParams params, NavigationType type) { - sendScreenChangedEventToJsScreen("didAppear", params.getNavigatorEventId()); - sendGlobalScreenChangedEvent("didAppear", params.timestamp, params.screenId, type); - } - - public void sendWillDisappearEvent(BaseScreenParams params, NavigationType type) { - sendScreenChangedEventToJsScreen("willDisappear", params.getNavigatorEventId()); - sendGlobalScreenChangedEvent("willDisappear", params.timestamp, params.screenId, type); - } - - public void sendDidDisappearEvent(BaseScreenParams params, NavigationType type) { - sendScreenChangedEventToJsScreen("didDisappear", params.getNavigatorEventId()); - sendGlobalScreenChangedEvent("didDisappear", params.timestamp, params.screenId, type); - } - - public void sendActivityResumed(String id) { - sendScreenChangedEventToJsScreen("onActivityResumed", id); - } - - private void sendScreenChangedEventToJsScreen(String eventId, String navigatorEventId) { - WritableMap map = Arguments.createMap(); - map.putString("type", "ScreenChangedEvent"); - sendNavigatorEvent(eventId, navigatorEventId, map); - } - - private void sendGlobalScreenChangedEvent(String eventId, double timestamp, String screenId, NavigationType type) { - WritableMap map = Arguments.createMap(); - map.putDouble("startTime", timestamp); - map.putDouble("endTime", System.currentTimeMillis()); - map.putString("screen", screenId); - map.putString("commandType", String.valueOf(type)); - sendNavigatorEvent(eventId, map); - } - - public void sendNavigatorEvent(String eventId, String navigatorEventId) { - if (!NavigationApplication.instance.isReactContextInitialized()) { - return; - } - reactGateway.getReactEventEmitter().sendNavigatorEvent(eventId, navigatorEventId); - } - - public void sendNavigatorEvent(String eventId, String navigatorEventId, WritableMap data) { - if (!NavigationApplication.instance.isReactContextInitialized()) { - return; - } - reactGateway.getReactEventEmitter().sendNavigatorEvent(eventId, navigatorEventId, data); - } - - public void sendEvent(String eventId, String navigatorEventId) { - if (!NavigationApplication.instance.isReactContextInitialized()) { - return; - } - reactGateway.getReactEventEmitter().sendEvent(eventId, navigatorEventId); - } - - public void sendNavigatorEvent(String eventId, WritableMap arguments) { - if (!NavigationApplication.instance.isReactContextInitialized()) { - return; - } - reactGateway.getReactEventEmitter().sendEvent(eventId, arguments); - } - - public void sendEvent(String eventId) { - if (!NavigationApplication.instance.isReactContextInitialized()) { - return; - } - reactGateway.getReactEventEmitter().sendEvent(eventId, Arguments.createMap()); - } - - public void sendAppLaunchedEvent() { - if (!NavigationApplication.instance.isReactContextInitialized()) { - return; - } - reactGateway.getReactEventEmitter().sendEvent("RNN.appLaunched", Arguments.createMap()); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactEventEmitter.java b/android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactEventEmitter.java deleted file mode 100644 index 2f730ed6859..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactEventEmitter.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.reactnativenavigation.bridge; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; - -public class NavigationReactEventEmitter { - - private static final String KEY_EVENT_ID = "id"; - private static final String KEY_EVENT_TYPE = "type"; - private static final String KEY_NAVIGATOR_EVENT_ID = "navigatorEventID"; - private static final String EVENT_TYPE = "NavBarButtonPress"; - private RCTDeviceEventEmitter eventEmitter; - - public NavigationReactEventEmitter(ReactContext reactContext) { - this.eventEmitter = reactContext.getJSModule(RCTDeviceEventEmitter.class); - } - - public void sendNavigatorEvent(String eventId, String navigatorEventId) { - WritableMap data = Arguments.createMap(); - data.putString(KEY_EVENT_TYPE, EVENT_TYPE); - data.putString(KEY_EVENT_ID, eventId); - data.putString(KEY_NAVIGATOR_EVENT_ID, navigatorEventId); - eventEmitter.emit(navigatorEventId, data); - } - - public void sendNavigatorEvent(String eventId, String navigatorEventId, WritableMap data) { - data.putString(KEY_NAVIGATOR_EVENT_ID, navigatorEventId); - data.putString(KEY_EVENT_ID, eventId); - eventEmitter.emit(navigatorEventId, data); - } - - public void sendEvent(String eventId, String data) { - eventEmitter.emit(eventId, data); - } - - public void sendEvent(String eventId, WritableMap data) { - eventEmitter.emit(eventId, data); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java b/android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java deleted file mode 100644 index a0ad9922397..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactModule.java +++ /dev/null @@ -1,284 +0,0 @@ -package com.reactnativenavigation.bridge; - -import android.support.annotation.Nullable; - -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.reactnativenavigation.controllers.NavigationCommandsHandler; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.LightBoxParams; -import com.reactnativenavigation.params.SlidingOverlayParams; -import com.reactnativenavigation.params.SnackbarParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.params.parsers.ContextualMenuParamsParser; -import com.reactnativenavigation.params.parsers.FabParamsParser; -import com.reactnativenavigation.params.parsers.LightBoxParamsParser; -import com.reactnativenavigation.params.parsers.ScreenParamsParser; -import com.reactnativenavigation.params.parsers.SlidingOverlayParamsParser; -import com.reactnativenavigation.params.parsers.SnackbarParamsParser; -import com.reactnativenavigation.params.parsers.TitleBarButtonParamsParser; -import com.reactnativenavigation.params.parsers.TitleBarLeftButtonParamsParser; -import com.reactnativenavigation.views.SideMenu.Side; - -import java.util.List; - -/** - * The basic abstract components we will expose: - * BottomTabs (app) - boolean - * TopBar (per screen) - * - TitleBar - * - - RightButtons - * - - LeftButton - * - TopTabs (segmented control / view pager tabs) - * DeviceStatusBar (app) (colors are per screen) - * AndroidNavigationBar (app) (colors are per screen) - * SideMenu (app) - boolean, (menu icon is screen-based) - */ -public class NavigationReactModule extends ReactContextBaseJavaModule { - public static final String NAME = "NavigationReactModule"; - - public NavigationReactModule(ReactApplicationContext reactContext) { - super(reactContext); - } - - @Override - public String getName() { - return NAME; - } - - @ReactMethod - public void startApp(final ReadableMap params, final @Nullable Promise promise) { - NavigationCommandsHandler.startApp(BundleConverter.toBundle(params), promise); - } - - @ReactMethod - public void setScreenTitleBarTitle(String screenInstanceId, String title) { - NavigationCommandsHandler.setScreenTitleBarTitle(screenInstanceId, title); - } - - @ReactMethod - public void setScreenTitleBarSubtitle(String screenInstanceId, String subtitle) { - NavigationCommandsHandler.setScreenTitleBarSubtitle(screenInstanceId, subtitle); - } - - @ReactMethod - public void setScreenButtons(String screenInstanceId, String navigatorEventId, - ReadableArray rightButtonsParams, ReadableMap leftButtonParams, ReadableMap fab) { - if (rightButtonsParams != null) { - setScreenTitleBarRightButtons(screenInstanceId, navigatorEventId, rightButtonsParams); - } - if (leftButtonParams != null) { - setScreenTitleBarLeftButton(screenInstanceId, navigatorEventId, leftButtonParams); - } - if (fab != null) { - setScreenFab(screenInstanceId, navigatorEventId, fab); - } - } - - private void setScreenTitleBarRightButtons(String screenInstanceId, String navigatorEventId, ReadableArray rightButtonsParams) { - List rightButtons = new TitleBarButtonParamsParser() - .parseButtons(BundleConverter.toBundle(rightButtonsParams)); - NavigationCommandsHandler.setScreenTitleBarRightButtons(screenInstanceId, navigatorEventId, rightButtons); - } - - private void setScreenTitleBarLeftButton(String screenInstanceId, String navigatorEventId, ReadableMap leftButtonParams) { - TitleBarLeftButtonParams leftButton = new TitleBarLeftButtonParamsParser() - .parseSingleButton(BundleConverter.toBundle(leftButtonParams)); - NavigationCommandsHandler.setScreenTitleBarLeftButtons(screenInstanceId, navigatorEventId, leftButton); - } - - private void setScreenFab(String screenInstanceId, String navigatorEventId, ReadableMap fab) { - FabParams fabParams = new FabParamsParser().parse(BundleConverter.toBundle(fab), navigatorEventId, screenInstanceId); - NavigationCommandsHandler.setScreenFab(screenInstanceId, navigatorEventId, fabParams); - } - - @ReactMethod - public void setScreenStyle(String screenInstanceId, ReadableMap style) { - NavigationCommandsHandler.setScreenStyle(screenInstanceId, BundleConverter.toBundle(style)); - } - - @ReactMethod - public void setBottomTabBadgeByIndex(Integer index, String badge) { - NavigationCommandsHandler.setBottomTabBadgeByIndex(index, badge); - } - - @ReactMethod - public void setBottomTabBadgeByNavigatorId(String navigatorId, String badge) { - NavigationCommandsHandler.setBottomTabBadgeByNavigatorId(navigatorId, badge); - } - - @ReactMethod - public void setBottomTabButtonByIndex(Integer index, final ReadableMap params) { - NavigationCommandsHandler.setBottomTabButtonByIndex(index, BundleConverter.toBundle(params)); - } - - @ReactMethod - public void setBottomTabButtonByNavigatorId(String navigatorId, final ReadableMap params) { - NavigationCommandsHandler.setBottomTabButtonByNavigatorId(navigatorId, BundleConverter.toBundle(params)); - } - - @ReactMethod - public void selectBottomTabByTabIndex(Integer index) { - NavigationCommandsHandler.selectBottomTabByTabIndex(index); - } - - @ReactMethod - public void selectBottomTabByNavigatorId(String navigatorId) { - NavigationCommandsHandler.selectBottomTabByNavigatorId(navigatorId); - } - - @ReactMethod - public void selectTopTabByTabIndex(String screenInstanceId, int index) { - NavigationCommandsHandler.selectTopTabByTabIndex(screenInstanceId, index); - } - - @ReactMethod - public void selectTopTabByScreen(String screenInstanceId) { - NavigationCommandsHandler.selectTopTabByScreen(screenInstanceId); - } - - @ReactMethod - public void toggleSideMenuVisible(boolean animated, String side) { - NavigationCommandsHandler.toggleSideMenuVisible(animated, Side.fromString(side)); - } - - @ReactMethod - public void setSideMenuVisible(boolean animated, boolean visible, String side) { - NavigationCommandsHandler.setSideMenuVisible(animated, visible, Side.fromString(side)); - } - - @ReactMethod - public void setSideMenuEnabled(boolean enabled, String side) { - NavigationCommandsHandler.setSideMenuEnabled(enabled, Side.fromString(side)); - } - - @ReactMethod - public void toggleTopBarVisible(final ReadableMap params) { - } - - @ReactMethod - public void setTopBarVisible(String screenInstanceId, boolean hidden, boolean animated) { - NavigationCommandsHandler.setTopBarVisible(screenInstanceId, hidden, animated); - } - - @ReactMethod - public void toggleBottomTabsVisible(final ReadableMap params) { - } - - @ReactMethod - public void setBottomTabsVisible(boolean hidden, boolean animated) { - NavigationCommandsHandler.setBottomTabsVisible(hidden, animated); - } - - @ReactMethod - public void push(final ReadableMap params, Promise onPushComplete) { - NavigationCommandsHandler.push(BundleConverter.toBundle(params), onPushComplete); - } - - @ReactMethod - public void pop(final ReadableMap params) { - NavigationCommandsHandler.pop(BundleConverter.toBundle(params)); - } - - @ReactMethod - public void popToRoot(final ReadableMap params) { - NavigationCommandsHandler.popToRoot(BundleConverter.toBundle(params)); - } - - @ReactMethod - public void newStack(final ReadableMap params) { - NavigationCommandsHandler.newStack(BundleConverter.toBundle(params)); - } - - @ReactMethod - public void showModal(final ReadableMap params) { - NavigationCommandsHandler.showModal(BundleConverter.toBundle(params)); - } - - @ReactMethod - public void showLightBox(final ReadableMap params) { - LightBoxParams lbp = new LightBoxParamsParser(BundleConverter.toBundle(params)).parse(); - NavigationCommandsHandler.showLightBox(lbp); - } - - @ReactMethod - public void dismissLightBox() { - NavigationCommandsHandler.dismissLightBox(); - } - - @ReactMethod - public void dismissAllModals() { - NavigationCommandsHandler.dismissAllModals(); - } - - @ReactMethod - public void dismissTopModal(final ReadableMap params) { - NavigationCommandsHandler.dismissTopModal(ScreenParamsParser.parse(BundleConverter.toBundle(params))); - } - - @ReactMethod - public void showSlidingOverlay(final ReadableMap params) { - SlidingOverlayParams slidingOverlayParams = new SlidingOverlayParamsParser().parse(BundleConverter.toBundle(params)); - NavigationCommandsHandler.showSlidingOverlay(slidingOverlayParams); - } - - @ReactMethod - public void hideSlidingOverlay(final ReadableMap params) { - NavigationCommandsHandler.hideSlidingOverlay(); - } - - @ReactMethod - public void showSnackbar(final ReadableMap params) { - SnackbarParams snackbarParams = new SnackbarParamsParser().parse(BundleConverter.toBundle(params)); - NavigationCommandsHandler.showSnackbar(snackbarParams); - } - - @ReactMethod - public void dismissSnackbar() { - NavigationCommandsHandler.dismissSnackbar(); - } - - @ReactMethod - public void showContextualMenu(final String screenInstanceId, final ReadableMap params, final Callback onButtonClicked) { - ContextualMenuParams contextualMenuParams = - new ContextualMenuParamsParser().parse(BundleConverter.toBundle(params)); - NavigationCommandsHandler.showContextualMenu(screenInstanceId, contextualMenuParams, onButtonClicked); - } - - @ReactMethod - public void dismissContextualMenu(String screenInstanceId) { - NavigationCommandsHandler.dismissContextualMenu(screenInstanceId); - } - - @ReactMethod - public void getOrientation(Promise promise) { - NavigationCommandsHandler.getOrientation(promise); - } - - @ReactMethod - public void isAppLaunched(Promise promise) { - NavigationCommandsHandler.isAppLaunched(promise); - } - - @ReactMethod - public void isRootLaunched(Promise promise) { - NavigationCommandsHandler.isRootLaunched(promise); - } - - @ReactMethod - public void getCurrentlyVisibleScreenId(Promise promise) { - NavigationCommandsHandler.getCurrentlyVisibleScreenId(promise); - } - - @ReactMethod - public void getLaunchArgs(Promise promise) { - NavigationCommandsHandler.getLaunchArgs(promise); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactPackage.java b/android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactPackage.java deleted file mode 100644 index 01d1b9afdd4..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/bridge/NavigationReactPackage.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.reactnativenavigation.bridge; - -import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.JavaScriptModule; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.uimanager.ViewManager; -import com.reactnativenavigation.views.managers.SharedElementTransitionManager; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class NavigationReactPackage implements ReactPackage { - - @Override - public List createNativeModules(ReactApplicationContext reactContext) { - return Arrays.asList( - new NavigationReactModule(reactContext) - ); - } - - // Depreciated RN 0.47 - public List> createJSModules() { - return Collections.emptyList(); - } - - @Override - public List createViewManagers(ReactApplicationContext reactContext) { - return Arrays.asList( - new SharedElementTransitionManager() - ); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/controllers/ActivityCallbacks.java b/android/app/src/main/java/com/reactnativenavigation/controllers/ActivityCallbacks.java deleted file mode 100644 index 888a9f2ecd4..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/controllers/ActivityCallbacks.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.reactnativenavigation.controllers; - -import android.app.Activity; -import android.content.Intent; -import android.content.res.Configuration; -import android.os.Bundle; -import android.view.KeyEvent; - -public class ActivityCallbacks { - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - - } - - public void onActivityStarted(Activity activity) { - - } - - public void onActivityResumed(Activity activity) { - - } - - public void onActivityPaused(Activity activity) { - - } - - public void onActivityStopped(Activity activity) { - - } - - public void onActivityResult(int requestCode, int resultCode, Intent data) { - - } - - public void onActivityDestroyed(Activity activity) { - - } - - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - - } - - public void onNewIntent(Intent intent) { - - } - - public void onConfigurationChanged(Configuration newConfig) { - - } - - public void onKeyUp(int keyCode, KeyEvent event) { - - } - -} diff --git a/android/app/src/main/java/com/reactnativenavigation/controllers/IntentDataHandler.java b/android/app/src/main/java/com/reactnativenavigation/controllers/IntentDataHandler.java deleted file mode 100644 index 9c45bd57f5d..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/controllers/IntentDataHandler.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.reactnativenavigation.controllers; - -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.Nullable; - -import com.reactnativenavigation.NavigationApplication; - -import static android.content.Intent.ACTION_VIEW; - -class IntentDataHandler { - private static Intent intent; - - static void onStartApp(Intent intent) { - setIntentData(intent); - } - - static void onResume(Intent intent) { - if (hasIntentData()) { - setIntentData(intent); - } else { - saveIntentData(intent); - } - } - - static void saveIntentData(Intent intent) { - IntentDataHandler.intent = intent; - } - - static void onPostResume(Intent intent) { - if (hasIntentData()) { - fakeOnNewIntentForLinkingModule(intent); - clear(); - } - } - - static void onPause(@Nullable Intent intent) { - if (intent != null) { - intent.setData(null); - intent.getExtras().clear(); - intent.replaceExtras(Bundle.EMPTY); - } - clear(); - } - - private static void fakeOnNewIntentForLinkingModule(Intent intent) { - if (intent != null) { - NavigationApplication.instance.getReactGateway().onNewIntent(intent); - } - } - - private static boolean hasIntentData() { - return intent != null; - } - - private static void setIntentData(@Nullable Intent intent) { - if (intent != null && IntentDataHandler.intent != null) { - intent.setData(IntentDataHandler.intent.getData()); - intent.putExtras(IntentDataHandler.intent); - intent.setAction(ACTION_VIEW); - } - } - - private static void clear() { - intent = null; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/controllers/Modal.java b/android/app/src/main/java/com/reactnativenavigation/controllers/Modal.java deleted file mode 100644 index 7825e26ec9b..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/controllers/Modal.java +++ /dev/null @@ -1,255 +0,0 @@ -package com.reactnativenavigation.controllers; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.AppCompatActivity; -import android.view.KeyEvent; -import android.view.Window; -import android.view.WindowManager; - -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.Promise; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.R; -import com.reactnativenavigation.layouts.Layout; -import com.reactnativenavigation.layouts.ModalScreenLayout; -import com.reactnativenavigation.layouts.ScreenStackContainer; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.Orientation; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.params.SlidingOverlayParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.params.parsers.ModalAnimationFactory; -import com.reactnativenavigation.screens.NavigationType; -import com.reactnativenavigation.utils.NavigationBar; -import com.reactnativenavigation.utils.StatusBar; - -import java.util.List; - -class Modal extends Dialog implements DialogInterface.OnDismissListener, ScreenStackContainer { - - private final AppCompatActivity activity; - private final OnModalDismissedListener onModalDismissedListener; - private final ScreenParams screenParams; - private Layout layout; - private boolean isDestroyed; - - public void setTopBarVisible(String screenInstanceId, boolean hidden, boolean animated) { - layout.setTopBarVisible(screenInstanceId, hidden, animated); - } - - void setTitleBarTitle(String screenInstanceId, String title) { - layout.setTitleBarTitle(screenInstanceId, title); - } - - void setTitleBarSubtitle(String screenInstanceId, String subtitle) { - layout.setTitleBarSubtitle(screenInstanceId, subtitle); - } - - void setTitleBarRightButtons(String screenInstanceId, String navigatorEventId, List titleBarButtons) { - layout.setTitleBarRightButtons(screenInstanceId, navigatorEventId, titleBarButtons); - } - - public void setTitleBarLeftButton(String screenInstanceId, String navigatorEventId, TitleBarLeftButtonParams titleBarLeftButton) { - layout.setTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButton); - } - - void setFab(String screenInstanceId, String navigatorEventId, FabParams fab) { - layout.setFab(screenInstanceId, navigatorEventId, fab); - } - - void updateScreenStyle(String screenInstanceId, Bundle styleParams) { - layout.updateScreenStyle(screenInstanceId, styleParams); - } - - public void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked) { - layout.showContextualMenu(screenInstanceId, params, onButtonClicked); - } - - public void dismissContextualMenu(String screenInstanceId) { - layout.dismissContextualMenu(screenInstanceId); - } - - void showSlidingOverlay(SlidingOverlayParams params) { - layout.showSlidingOverlay(params); - } - - void hideSlidingOverlay() { - layout.hideSlidingOverlay(); - } - - @Override - public boolean onTitleBarBackButtonClick() { - if (!layout.onBackPressed()) { - onBackPressed(); - } - return true; - } - - public void onSideMenuButtonClick() { - } - - void selectTopTabByScreen(String screenInstanceId) { - layout.selectTopTabByScreen(screenInstanceId); - } - - public void selectTopTabByTabIndex(String screenInstanceId, int index) { - layout.selectTopTabByTabIndex(screenInstanceId, index); - } - - String getCurrentlyVisibleScreenId() { - return layout.getCurrentlyVisibleScreenId(); - } - - String getCurrentlyVisibleEventId() { - return layout.getCurrentScreen().getNavigatorEventId(); - } - - interface OnModalDismissedListener { - void onModalDismissed(Modal modal); - } - - Modal(AppCompatActivity activity, OnModalDismissedListener onModalDismissedListener, ScreenParams screenParams) { - super(activity, R.style.Modal); - this.activity = activity; - this.onModalDismissedListener = onModalDismissedListener; - this.screenParams = screenParams; - createContent(); - setAnimation(screenParams); - setStatusBarStyle(screenParams.styleParams); - setNavigationBarStyle(screenParams.styleParams); - setDrawUnderStatusBar(screenParams.styleParams); - } - - private void setStatusBarStyle(StyleParams styleParams) { - Window window = getWindow(); - if (window == null) return; - StatusBar.setTextColorScheme(window.getDecorView(), styleParams.statusBarTextColorScheme); - } - - private void setDrawUnderStatusBar(StyleParams styleParams) { - Window window = getWindow(); - if (window == null) return; - StatusBar.displayOverScreen(window.getDecorView(), styleParams.drawUnderStatusBar); - } - - private void setNavigationBarStyle(StyleParams styleParams) { - NavigationBar.setColor(getWindow(), styleParams.navigationBarColor); - } - - public AppCompatActivity getActivity() { - return activity; - } - - private void createContent() { - setCancelable(true); - setOnDismissListener(this); - requestWindowFeature(Window.FEATURE_NO_TITLE); - layout = new ModalScreenLayout(getActivity(), screenParams, this); - setWindowFlags(); - setOrientation(screenParams.styleParams.orientation); - setContentView(layout.asView()); - } - - private void setWindowFlags() { - Window window = getWindow(); - if (window == null) return; - window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - } - } - - private void setAnimation(ScreenParams screenParams) { - if (getWindow() == null) return; - final WindowManager.LayoutParams attributes = getWindow().getAttributes(); - attributes.windowAnimations = ModalAnimationFactory.create(screenParams); - getWindow().setAttributes(attributes); - } - - @Override - public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { - NavigationApplication.instance.getActivityCallbacks().onKeyUp(keyCode, event); - return super.onKeyUp(keyCode, event); - } - - @Override - public void push(ScreenParams params, Promise onPushComplete) { - layout.push(params, onPushComplete); - } - - @Override - public void pop(ScreenParams screenParams) { - layout.pop(screenParams); - } - - @Override - public void popToRoot(ScreenParams params) { - layout.popToRoot(params); - } - - @Override - public void newStack(ScreenParams params) { - layout.newStack(params); - } - - boolean containsNavigator(String navigatorId) { - return layout.containsNavigator(navigatorId); - } - - @Override - public void destroy() { - isDestroyed = true; - layout.destroy(); - } - - @Override - public void onBackPressed() { - if (!layout.onBackPressed()) { - super.onBackPressed(); - } - } - - void dismiss(ScreenParams params) { - setAnimation(params); - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - dismiss(); - } - }); - } - - @Override - public void dismiss() { - if (!isDestroyed) { - NavigationApplication.instance.getEventEmitter().sendWillDisappearEvent(layout.getCurrentScreen().getScreenParams(), NavigationType.DismissModal); - NavigationApplication.instance.getEventEmitter().sendDidDisappearEvent(layout.getCurrentScreen().getScreenParams(), NavigationType.DismissModal); - } - super.dismiss(); - } - - @Override - public void onDismiss(DialogInterface dialog) { - if (isDestroyed) { - return; - } - destroy(); - onModalDismissedListener.onModalDismissed(this); - } - - void onModalDismissed() { - setOrientation(screenParams.styleParams.orientation); - layout.onModalDismissed(); - } - - private void setOrientation(Orientation orientation) { - getActivity().setRequestedOrientation(orientation.orientationCode); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/controllers/ModalController.java b/android/app/src/main/java/com/reactnativenavigation/controllers/ModalController.java deleted file mode 100644 index 58e5112ff7a..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/controllers/ModalController.java +++ /dev/null @@ -1,195 +0,0 @@ -package com.reactnativenavigation.controllers; - -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.view.Window; - -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.Promise; -import com.reactnativenavigation.events.EventBus; -import com.reactnativenavigation.events.ModalDismissedEvent; -import com.reactnativenavigation.layouts.ScreenStackContainer; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.params.SlidingOverlayParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; - -import java.util.List; -import java.util.Stack; - -class ModalController implements ScreenStackContainer, Modal.OnModalDismissedListener { - private final AppCompatActivity activity; - private Stack stack = new Stack<>(); - - ModalController(AppCompatActivity activity) { - this.activity = activity; - } - - boolean containsNavigator(String navigatorId) { - for (Modal modal : stack) { - if (modal.containsNavigator(navigatorId)) { - return true; - } - } - return false; - } - - void showModal(ScreenParams screenParams) { - Modal modal = new Modal(activity, this, screenParams); - modal.show(); - stack.add(modal); - } - - void dismissTopModal(ScreenParams params) { - if (isShowing()) { - stack.pop().dismiss(params); - } - } - - void dismissAllModals() { - for (Modal modal : stack) { - modal.dismiss(); - } - stack.clear(); - } - - boolean isShowing() { - return !stack.empty(); - } - - public void push(ScreenParams params, Promise onPushComplete) { - stack.peek().push(params, onPushComplete); - } - - @Override - public void pop(ScreenParams screenParams) { - stack.peek().pop(screenParams); - } - - @Override - public void popToRoot(ScreenParams params) { - stack.peek().popToRoot(params); - } - - @Override - public void newStack(ScreenParams params) { - stack.peek().newStack(params); - } - - @Override - public void destroy() { - for (Modal modal : stack) { - modal.destroy(); - modal.dismiss(); - } - stack.clear(); - } - - @Override - public void onModalDismissed(Modal modal) { - stack.remove(modal); - if (isShowing()) { - stack.peek().onModalDismissed(); - } - EventBus.instance.post(new ModalDismissedEvent()); - } - - public void setTopBarVisible(String screenInstanceId, boolean hidden, boolean animated) { - for (Modal modal : stack) { - modal.setTopBarVisible(screenInstanceId, hidden, animated); - } - } - - void setTitleBarTitle(String screenInstanceId, String title) { - for (Modal modal : stack) { - modal.setTitleBarTitle(screenInstanceId, title); - } - } - - void setTitleBarSubtitle(String screenInstanceId, String subtitle) { - for (Modal modal : stack) { - modal.setTitleBarSubtitle(screenInstanceId, subtitle); - } - } - - void setTitleBarRightButtons(String screenInstanceId, String navigatorEventId, List titleBarButtons) { - for (Modal modal : stack) { - modal.setTitleBarRightButtons(screenInstanceId, navigatorEventId, titleBarButtons); - } - } - - void setTitleBarLeftButton(String screenInstanceId, String navigatorEventId, TitleBarLeftButtonParams titleBarLeftButton) { - for (Modal modal : stack) { - modal.setTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButton); - } - } - - void setFab(String screenInstanceId, String navigatorEventId, FabParams fab) { - for (Modal modal : stack) { - modal.setFab(screenInstanceId, navigatorEventId, fab); - } - } - - void updateScreenStyle(String screenInstanceId, Bundle styleParams) { - for (Modal modal : stack) { - modal.updateScreenStyle(screenInstanceId, styleParams); - } - } - - public void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked) { - for (Modal modal : stack) { - modal.showContextualMenu(screenInstanceId, params, onButtonClicked); - } - } - - public void dismissContextualMenu(String screenInstanceId) { - for (Modal modal : stack) { - modal.dismissContextualMenu(screenInstanceId); - } - } - - @Override - public boolean onTitleBarBackButtonClick() { - // Do nothing and let the layout handle the back button click - return false; - } - - @Override - public void onSideMenuButtonClick() { - // Do nothing and let the layout handle the click - } - - void showSlidingOverlay(SlidingOverlayParams params) { - stack.peek().showSlidingOverlay(params); - } - - void hideSlidingOverlay() { - stack.peek().hideSlidingOverlay(); - } - - Window getWindow() { - return stack.peek().getWindow(); - } - - void selectTopTabByTabIndex(String screenInstanceId, int index) { - for (Modal modal : stack) { - modal.selectTopTabByTabIndex(screenInstanceId, index); - } - } - - void selectTopTabByScreen(String screenInstanceId) { - for (Modal modal : stack) { - modal.selectTopTabByScreen(screenInstanceId); - } - } - - String getCurrentlyVisibleScreenId() { - return stack.peek().getCurrentlyVisibleScreenId(); - } - - String getCurrentlyVisibleEventId() { - return stack.peek().getCurrentlyVisibleEventId(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java b/android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java deleted file mode 100644 index f35e3a51d59..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/controllers/NavigationActivity.java +++ /dev/null @@ -1,493 +0,0 @@ -package com.reactnativenavigation.controllers; - -import android.annotation.TargetApi; -import android.content.Intent; -import android.content.res.Configuration; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.view.KeyEvent; -import android.view.Window; - -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.Promise; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; -import com.facebook.react.modules.core.PermissionAwareActivity; -import com.facebook.react.modules.core.PermissionListener; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.events.Event; -import com.reactnativenavigation.events.EventBus; -import com.reactnativenavigation.events.JsDevReloadEvent; -import com.reactnativenavigation.events.ModalDismissedEvent; -import com.reactnativenavigation.events.Subscriber; -import com.reactnativenavigation.layouts.BottomTabsLayout; -import com.reactnativenavigation.layouts.Layout; -import com.reactnativenavigation.layouts.LayoutFactory; -import com.reactnativenavigation.params.ActivityParams; -import com.reactnativenavigation.params.AppStyle; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.LightBoxParams; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.params.SlidingOverlayParams; -import com.reactnativenavigation.params.SnackbarParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.react.ReactGateway; -import com.reactnativenavigation.screens.NavigationType; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.OrientationHelper; -import com.reactnativenavigation.utils.ReflectionUtils; -import com.reactnativenavigation.views.SideMenu.Side; - -import java.util.List; - -public class NavigationActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler, Subscriber, PermissionAwareActivity { - - /** - * Although we start multiple activities, we make sure to pass Intent.CLEAR_TASK | Intent.NEW_TASK - * So that we actually have only 1 instance of the activity running at one time. - * We hold the currentActivity (resume->pause) so we know when we need to destroy the javascript context - * (when currentActivity is null, ie pause and destroy was called without resume). - * This is somewhat weird, and in the future we better use a single activity with changing contentView similar to ReactNative impl. - * Along with that, we should handle commands from the bridge using onNewIntent - */ - static NavigationActivity currentActivity; - private static Promise startAppPromise; - - private ActivityParams activityParams; - private ModalController modalController; - private Layout layout; - @Nullable - private PermissionListener mPermissionListener; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (!NavigationApplication.instance.getReactGateway().hasStartedCreatingContext() || - getIntent() == null || - getIntent().getBundleExtra("ACTIVITY_PARAMS_BUNDLE") == null) { - SplashActivity.start(this); - finish(); - return; - } - - activityParams = NavigationCommandsHandler.parseActivityParams(getIntent()); - disableActivityShowAnimationIfNeeded(); - setOrientation(); - createModalController(); - createLayout(); - NavigationApplication.instance.getActivityCallbacks().onActivityCreated(this, savedInstanceState); - } - - private void setOrientation() { - OrientationHelper.setOrientation(this, AppStyle.appStyle.orientation); - } - - private void disableActivityShowAnimationIfNeeded() { - if (!activityParams.animateShow) { - overridePendingTransition(0, 0); - } - } - - private void createModalController() { - modalController = new ModalController(this); - } - - private void createLayout() { - layout = LayoutFactory.create(this, activityParams); - if (hasBackgroundColor()) { - layout.asView().setBackgroundColor(AppStyle.appStyle.screenBackgroundColor.getColor()); - } - setContentView(layout.asView()); - } - - private boolean hasBackgroundColor() { - return AppStyle.appStyle.screenBackgroundColor != null && - AppStyle.appStyle.screenBackgroundColor.hasColor(); - } - - @Override - protected void onStart() { - super.onStart(); - NavigationApplication.instance.getActivityCallbacks().onActivityStarted(this); - } - - @Override - protected void onResume() { - super.onResume(); - if (isFinishing() || !NavigationApplication.instance.isReactContextInitialized()) { - return; - } - - currentActivity = this; - IntentDataHandler.onResume(getIntent()); - getReactGateway().onResumeActivity(this, this); - resolveStartAppPromiseOnActivityResumed(); - NavigationApplication.instance.getActivityCallbacks().onActivityResumed(this); - EventBus.instance.register(this); - IntentDataHandler.onPostResume(getIntent()); - NavigationApplication.instance.getEventEmitter().sendActivityResumed(getCurrentlyVisibleEventId()); - } - - private void resolveStartAppPromiseOnActivityResumed() { - if (startAppPromise != null) { - startAppPromise.resolve(true); - startAppPromise = null; - } - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - getReactGateway().onNewIntent(intent); - NavigationApplication.instance.getActivityCallbacks().onNewIntent(intent); - } - - @Override - protected void onPause() { - super.onPause(); - currentActivity = null; - IntentDataHandler.onPause(getIntent()); - getReactGateway().onPauseActivity(this); - NavigationApplication.instance.getActivityCallbacks().onActivityPaused(this); - EventBus.instance.unregister(this); - } - - @Override - protected void onStop() { - super.onStop(); - clearStartAppPromise(); - NavigationApplication.instance.getActivityCallbacks().onActivityStopped(this); - } - - private void clearStartAppPromise() { - if (startAppPromise != null) { - startAppPromise = null; - } - } - - @Override - protected void onDestroy() { - destroyLayouts(); - destroyJsIfNeeded(); - NavigationApplication.instance.getActivityCallbacks().onActivityDestroyed(this); - super.onDestroy(); - } - - private void destroyLayouts() { - if (modalController != null) { - modalController.destroy(); - } - if (layout != null) { - layout.destroy(); - layout = null; - } - } - - private void destroyJsIfNeeded() { - if (currentActivity == null || currentActivity.isFinishing()) { - getReactGateway().onDestroyApp(this); - } - } - - @Override - public void invokeDefaultOnBackPressed() { - if (layout != null && !layout.onBackPressed()) { - super.onBackPressed(); - } - } - - @Override - public void onBackPressed() { - if (layout != null && layout.handleBackInJs()) { - return; - } - if (getReactGateway().isInitialized()) { - getReactGateway().onBackPressed(); - } else { - super.onBackPressed(); - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - getReactGateway().onActivityResult(requestCode, resultCode, data); - NavigationApplication.instance.getActivityCallbacks().onActivityResult(requestCode, resultCode, data); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - NavigationApplication.instance.getActivityCallbacks().onKeyUp(keyCode, event); - return getReactGateway().onKeyUp(getCurrentFocus(), keyCode) || super.onKeyUp(keyCode, event); - } - - private ReactGateway getReactGateway() { - return NavigationApplication.instance.getReactGateway(); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - OrientationHelper.onConfigurationChanged(newConfig); - NavigationApplication.instance.getActivityCallbacks().onConfigurationChanged(newConfig); - super.onConfigurationChanged(newConfig); - } - - void push(ScreenParams params, Promise onPushComplete) { - if (modalController.containsNavigator(params.getNavigatorId())) { - modalController.push(params, onPushComplete); - } else { - layout.push(params, onPushComplete); - } - } - - void pop(ScreenParams params) { - if (modalController.containsNavigator(params.getNavigatorId())) { - modalController.pop(params); - } else { - layout.pop(params); - } - } - - void popToRoot(ScreenParams params) { - if (modalController.containsNavigator(params.getNavigatorId())) { - modalController.popToRoot(params); - } else { - layout.popToRoot(params); - } - } - - void newStack(ScreenParams params) { - if (modalController.containsNavigator(params.getNavigatorId())) { - modalController.newStack(params); - } else { - layout.newStack(params); - } - } - - void showModal(ScreenParams screenParams) { - Screen previousScreen = layout.getCurrentScreen(); - NavigationApplication.instance.getEventEmitter().sendWillDisappearEvent(previousScreen.getScreenParams(), NavigationType.ShowModal); - NavigationApplication.instance.getEventEmitter().sendDidDisappearEvent(previousScreen.getScreenParams(), NavigationType.ShowModal); - modalController.showModal(screenParams); - } - - void dismissTopModal(ScreenParams params) { - modalController.dismissTopModal(params); - } - - void dismissAllModals() { - modalController.dismissAllModals(); - } - - public void showLightBox(LightBoxParams params) { - layout.showLightBox(params); - } - - public void dismissLightBox() { - layout.dismissLightBox(); - } - - //TODO all these setters should be combined to something like setStyle - void setTopBarVisible(String screenInstanceId, boolean hidden, boolean animated) { - layout.setTopBarVisible(screenInstanceId, hidden, animated); - modalController.setTopBarVisible(screenInstanceId, hidden, animated); - } - - void setBottomTabsVisible(boolean hidden, boolean animated) { - if (layout instanceof BottomTabsLayout) { - ((BottomTabsLayout) layout).setBottomTabsVisible(hidden, animated); - } - } - - void setTitleBarTitle(String screenInstanceId, String title) { - layout.setTitleBarTitle(screenInstanceId, title); - modalController.setTitleBarTitle(screenInstanceId, title); - } - - public void setTitleBarSubtitle(String screenInstanceId, String subtitle) { - layout.setTitleBarSubtitle(screenInstanceId, subtitle); - modalController.setTitleBarSubtitle(screenInstanceId, subtitle); - } - - void setTitleBarButtons(String screenInstanceId, String navigatorEventId, List titleBarButtons) { - layout.setTitleBarRightButtons(screenInstanceId, navigatorEventId, titleBarButtons); - modalController.setTitleBarRightButtons(screenInstanceId, navigatorEventId, titleBarButtons); - } - - void setTitleBarLeftButton(String screenInstanceId, String navigatorEventId, TitleBarLeftButtonParams titleBarLeftButton) { - layout.setTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButton); - modalController.setTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButton); - } - - void setScreenFab(String screenInstanceId, String navigatorEventId, FabParams fab) { - layout.setFab(screenInstanceId, navigatorEventId, fab); - modalController.setFab(screenInstanceId, navigatorEventId, fab); - } - - public void setScreenStyle(String screenInstanceId, Bundle styleParams) { - layout.updateScreenStyle(screenInstanceId, styleParams); - modalController.updateScreenStyle(screenInstanceId, styleParams); - } - - public void toggleSideMenuVisible(boolean animated, Side side) { - layout.toggleSideMenuVisible(animated, side); - } - - public void setSideMenuVisible(boolean animated, boolean visible, Side side) { - layout.setSideMenuVisible(animated, visible, side); - } - - public void setSideMenuEnabled(boolean enabled, Side side) { - layout.setSideMenuEnabled(enabled, side); - } - - public void selectTopTabByTabIndex(String screenInstanceId, int index) { - layout.selectTopTabByTabIndex(screenInstanceId, index); - modalController.selectTopTabByTabIndex(screenInstanceId, index); - } - - public void selectTopTabByScreen(String screenInstanceId) { - layout.selectTopTabByScreen(screenInstanceId); - modalController.selectTopTabByScreen(screenInstanceId); - } - - public void selectBottomTabByTabIndex(Integer index) { - if (layout instanceof BottomTabsLayout) { - ((BottomTabsLayout) layout).selectBottomTabByTabIndex(index); - } - } - - public void selectBottomTabByNavigatorId(String navigatorId) { - if (layout instanceof BottomTabsLayout) { - ((BottomTabsLayout) layout).selectBottomTabByNavigatorId(navigatorId); - } - } - - public void setBottomTabBadgeByIndex(Integer index, String badge) { - if (layout instanceof BottomTabsLayout) { - ((BottomTabsLayout) layout).setBottomTabBadgeByIndex(index, badge); - } - } - - public void setBottomTabBadgeByNavigatorId(String navigatorId, String badge) { - if (layout instanceof BottomTabsLayout) { - ((BottomTabsLayout) layout).setBottomTabBadgeByNavigatorId(navigatorId, badge); - } - } - - public void setBottomTabButtonByIndex(Integer index, ScreenParams params) { - if (layout instanceof BottomTabsLayout) { - ((BottomTabsLayout) layout).setBottomTabButtonByIndex(index, params); - } - } - - public void setBottomTabButtonByNavigatorId(String navigatorId, ScreenParams params) { - if (layout instanceof BottomTabsLayout) { - ((BottomTabsLayout) layout).setBottomTabButtonByNavigatorId(navigatorId, params); - } - } - - public void showSlidingOverlay(SlidingOverlayParams params) { - if (modalController.isShowing()) { - modalController.showSlidingOverlay(params); - } else { - layout.showSlidingOverlay(params); - } - } - - public void hideSlidingOverlay() { - if (modalController.isShowing()) { - modalController.hideSlidingOverlay(); - } else { - layout.hideSlidingOverlay(); - } - } - - public void showSnackbar(SnackbarParams params) { - layout.showSnackbar(params); - } - - public void dismissSnackbar() { - layout.dismissSnackbar(); - } - - public void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked) { - if (modalController.isShowing()) { - modalController.showContextualMenu(screenInstanceId, params, onButtonClicked); - } else { - layout.showContextualMenu(screenInstanceId, params, onButtonClicked); - } - } - - public void dismissContextualMenu(String screenInstanceId) { - if (modalController.isShowing()) { - modalController.dismissContextualMenu(screenInstanceId); - } else { - layout.dismissContextualMenu(screenInstanceId); - } - } - - @Override - public void onEvent(Event event) { - if (event.getType().equals(ModalDismissedEvent.TYPE)) { - handleModalDismissedEvent(); - } else if (event.getType().equals(JsDevReloadEvent.TYPE)) { - postHandleJsDevReloadEvent(); - } - } - - private void handleModalDismissedEvent() { - if (!modalController.isShowing()) { - layout.onModalDismissed(); - OrientationHelper.setOrientation(this, AppStyle.appStyle.orientation); - } - } - - public Window getScreenWindow() { - return modalController.isShowing() ? modalController.getWindow() : getWindow(); - } - - private void postHandleJsDevReloadEvent() { - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - layout.destroy(); - modalController.destroy(); - - Object devSupportManager = ReflectionUtils.getDeclaredField(getReactGateway().getReactInstanceManager(), "mDevSupportManager"); - if (ReflectionUtils.getDeclaredField(devSupportManager, "mRedBoxDialog") != null) { // RN >= 0.52 - ReflectionUtils.setField(devSupportManager, "mRedBoxDialog", null); - } - } - }); - } - - @TargetApi(Build.VERSION_CODES.M) - public void requestPermissions(String[] permissions, int requestCode, PermissionListener listener) { - mPermissionListener = listener; - requestPermissions(permissions, requestCode); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - NavigationApplication.instance.getActivityCallbacks().onRequestPermissionsResult(requestCode, permissions, grantResults); - if (mPermissionListener != null && mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) { - mPermissionListener = null; - } - } - - public String getCurrentlyVisibleScreenId() { - return modalController.isShowing() ? modalController.getCurrentlyVisibleScreenId() : layout.getCurrentlyVisibleScreenId(); - } - - public String getCurrentlyVisibleEventId() { - return modalController.isShowing() ? modalController.getCurrentlyVisibleEventId() : layout.getCurrentScreen().getNavigatorEventId(); - } - - public static void setStartAppPromise(Promise promise) { - NavigationActivity.startAppPromise = promise; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java b/android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java deleted file mode 100644 index 4b2b11f1063..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/controllers/NavigationCommandsHandler.java +++ /dev/null @@ -1,554 +0,0 @@ -package com.reactnativenavigation.controllers; - -import android.content.*; -import android.os.*; - -import com.facebook.react.bridge.*; -import com.reactnativenavigation.*; -import com.reactnativenavigation.params.*; -import com.reactnativenavigation.params.parsers.*; -import com.reactnativenavigation.react.*; -import com.reactnativenavigation.utils.*; -import com.reactnativenavigation.views.SideMenu.*; - -import java.util.*; - -public class NavigationCommandsHandler { - - private static final String ACTIVITY_PARAMS_BUNDLE = "ACTIVITY_PARAMS_BUNDLE"; - - static ActivityParams parseActivityParams(Intent intent) { - return ActivityParamsParser.parse(intent.getBundleExtra(NavigationCommandsHandler.ACTIVITY_PARAMS_BUNDLE)); - } - - public static void startApp(Bundle params, Promise promise) { - Intent intent = new Intent(NavigationApplication.instance, NavigationActivity.class); - IntentDataHandler.onStartApp(intent); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(ACTIVITY_PARAMS_BUNDLE, params); - intent.putExtra("animationType", params.getString("animationType")); - NavigationActivity.setStartAppPromise(promise); - NavigationApplication.instance.startActivity(intent); - } - - public static void push(Bundle screenParams, final Promise onPushComplete) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - final ScreenParams params = ScreenParamsParser.parse(screenParams); - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.push(params, onPushComplete); - } - }); - } - - public static void pop(Bundle screenParams) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - final ScreenParams params = ScreenParamsParser.parse(screenParams); - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.pop(params); - } - }); - } - - public static void popToRoot(Bundle screenParams) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - final ScreenParams params = ScreenParamsParser.parse(screenParams); - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.popToRoot(params); - } - }); - } - - public static void newStack(Bundle screenParams) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - final ScreenParams params = ScreenParamsParser.parse(screenParams); - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.newStack(params); - } - }); - } - - public static void setTopBarVisible(final String screenInstanceID, final boolean hidden, final boolean animated) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setTopBarVisible(screenInstanceID, hidden, animated); - } - }); - } - - public static void setBottomTabsVisible(final boolean hidden, final boolean animated) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setBottomTabsVisible(hidden, animated); - } - }); - } - - public static void setScreenTitleBarTitle(final String screenInstanceId, final String title) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setTitleBarTitle(screenInstanceId, title); - } - }); - } - - public static void setScreenTitleBarSubtitle(final String screenInstanceId, final String subtitle) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setTitleBarSubtitle(screenInstanceId, subtitle); - } - }); - } - - public static void showModal(final Bundle params) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.showModal(ScreenParamsParser.parse(params)); - } - }); - } - - public static void showLightBox(final LightBoxParams params) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.showLightBox(params); - } - }); - } - - public static void dismissLightBox() { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.dismissLightBox(); - } - }); - } - - public static void setScreenTitleBarRightButtons(final String screenInstanceId, - final String navigatorEventId, - final List titleBarButtons) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setTitleBarButtons(screenInstanceId, navigatorEventId, titleBarButtons); - } - }); - } - - public static void setScreenTitleBarLeftButtons(final String screenInstanceId, - final String navigatorEventId, - final TitleBarLeftButtonParams titleBarButtons) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarButtons); - } - }); - } - - public static void setScreenFab(final String screenInstanceId, final String navigatorEventId, final FabParams fab) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setScreenFab(screenInstanceId, navigatorEventId, fab); - } - }); - } - - public static void setScreenStyle(final String screenInstanceId, final Bundle styleParams) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setScreenStyle(screenInstanceId, styleParams); - } - }); - } - - public static void dismissTopModal(final ScreenParams params) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.dismissTopModal(params); - } - }); - } - - public static void dismissAllModals() { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.dismissAllModals(); - } - }); - } - - public static void toggleSideMenuVisible(final boolean animated, final Side side) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.toggleSideMenuVisible(animated, side); - } - }); - } - - public static void setSideMenuVisible(final boolean animated, final boolean visible, final Side side) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setSideMenuVisible(animated, visible, side); - } - }); - } - - public static void setSideMenuEnabled(final boolean enabled, final Side side) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setSideMenuEnabled(enabled, side); - } - }); - } - - public static void selectTopTabByTabIndex(final String screenInstanceId, final int index) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.selectTopTabByTabIndex(screenInstanceId, index); - } - }); - } - - public static void selectTopTabByScreen(final String screenInstanceId) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.selectTopTabByScreen(screenInstanceId); - } - }); - } - - public static void selectBottomTabByTabIndex(final Integer index) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.selectBottomTabByTabIndex(index); - } - }); - } - - public static void selectBottomTabByNavigatorId(final String navigatorId) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.selectBottomTabByNavigatorId(navigatorId); - } - }); - } - - public static void setBottomTabBadgeByIndex(final Integer index, final String badge) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setBottomTabBadgeByIndex(index, badge); - } - }); - } - - public static void setBottomTabBadgeByNavigatorId(final String navigatorId, final String badge) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setBottomTabBadgeByNavigatorId(navigatorId, badge); - } - }); - } - - public static void setBottomTabButtonByIndex(final Integer index, final Bundle screenParams) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - final ScreenParams params = ScreenParamsParser.parse(screenParams); - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setBottomTabButtonByIndex(index, params); - } - }); - } - - public static void setBottomTabButtonByNavigatorId(final String navigatorId, final Bundle screenParams) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - final ScreenParams params = ScreenParamsParser.parse(screenParams); - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.setBottomTabButtonByNavigatorId(navigatorId, params); - } - }); - } - - public static void showSlidingOverlay(final SlidingOverlayParams params) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.showSlidingOverlay(params); - } - }); - } - - public static void hideSlidingOverlay() { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.hideSlidingOverlay(); - } - }); - } - - public static void showSnackbar(final SnackbarParams params) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.showSnackbar(params); - } - }); - } - - public static void showContextualMenu(final String screenInstanceId, final ContextualMenuParams params, final Callback onButtonClicked) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.showContextualMenu(screenInstanceId, params, onButtonClicked); - } - }); - } - - public static void dismissContextualMenu(final String screenInstanceId) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.dismissContextualMenu(screenInstanceId); - } - }); - } - - public static void dismissSnackbar() { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - currentActivity.dismissSnackbar(); - } - }); - } - - public static void getOrientation(Promise promise) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - return; - } - promise.resolve(OrientationHelper.getOrientation(currentActivity)); - } - - public static void isAppLaunched(Promise promise) { - final boolean isAppLaunched = SplashActivity.isResumed || NavigationActivity.currentActivity != null; - promise.resolve(isAppLaunched); - } - - public static void isRootLaunched(Promise promise) { - promise.resolve(NavigationActivity.currentActivity != null); - } - - public static void getCurrentlyVisibleScreenId(final Promise promise) { - final NavigationActivity currentActivity = NavigationActivity.currentActivity; - if (currentActivity == null) { - promise.resolve(""); - return; - } - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - WritableMap map = Arguments.createMap(); - map.putString("screenId", currentActivity.getCurrentlyVisibleScreenId()); - promise.resolve(map); - } - }); - } - - public static void getLaunchArgs(Promise promise) { - Bundle bundle = LaunchArgs.instance.get(); - promise.resolve(Arguments.fromBundle(bundle)); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/controllers/SplashActivity.java b/android/app/src/main/java/com/reactnativenavigation/controllers/SplashActivity.java deleted file mode 100644 index e85de9e40a1..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/controllers/SplashActivity.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.reactnativenavigation.controllers; - -import android.app.Activity; -import android.content.Intent; -import android.graphics.Color; -import android.os.Bundle; -import android.support.annotation.LayoutRes; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.view.View; - -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.react.*; -import com.reactnativenavigation.utils.CompatUtils; - -public abstract class SplashActivity extends AppCompatActivity { - public static boolean isResumed = false; - - public static void start(Activity activity) { - Intent intent = activity.getPackageManager().getLaunchIntentForPackage(activity.getPackageName()); - if (intent == null) return; - intent.setAction(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - activity.startActivity(intent); - } - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - LaunchArgs.instance.set(getIntent()); - setSplashLayout(); - IntentDataHandler.saveIntentData(getIntent()); - } - - @Override - protected void onResume() { - super.onResume(); - isResumed = true; - - if (NavigationApplication.instance.getReactGateway().hasStartedCreatingContext()) { - if (CompatUtils.isSplashOpenedOverNavigationActivity(this, getIntent())) { - finish(); - return; - } - NavigationApplication.instance.getEventEmitter().sendAppLaunchedEvent(); - if (NavigationApplication.instance.clearHostOnActivityDestroy()) { - overridePendingTransition(0, 0); - finish(); - } - return; - } - - if (ReactDevPermission.shouldAskPermission()) { - ReactDevPermission.askPermission(this); - return; - } - - if (NavigationApplication.instance.isReactContextInitialized()) { - NavigationApplication.instance.getEventEmitter().sendAppLaunchedEvent(); - return; - } - - // TODO I'm starting to think this entire flow is incorrect and should be done in Application - NavigationApplication.instance.startReactContextOnceInBackgroundAndExecuteJS(); - } - - @Override - protected void onPause() { - super.onPause(); - isResumed = false; - } - - private void setSplashLayout() { - final int splashLayout = getSplashLayout(); - if (splashLayout > 0) { - setContentView(splashLayout); - } else { - setContentView(createSplashLayout()); - } - } - - /** - * @return xml layout res id - */ - @LayoutRes - public int getSplashLayout() { - return 0; - } - - /** - * @return the layout you would like to show while react's js context loads - */ - public View createSplashLayout() { - View view = new View(this); - view.setBackgroundColor(Color.WHITE); - return view; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/ContextualMenuHiddenEvent.java b/android/app/src/main/java/com/reactnativenavigation/events/ContextualMenuHiddenEvent.java deleted file mode 100644 index 1e5d2c16deb..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/ContextualMenuHiddenEvent.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.reactnativenavigation.events; - -public class ContextualMenuHiddenEvent implements Event { - public static final String TYPE = "ContextualMenuDismissed"; - @Override - public String getType() { - return TYPE; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/Event.java b/android/app/src/main/java/com/reactnativenavigation/events/Event.java deleted file mode 100644 index 4ea83d66bdc..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/Event.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.reactnativenavigation.events; - -public interface Event { - String getType(); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/EventBus.java b/android/app/src/main/java/com/reactnativenavigation/events/EventBus.java deleted file mode 100644 index 153855ae49e..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/EventBus.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.reactnativenavigation.events; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; - -public enum EventBus { - instance; - - private final List> subscribers = new ArrayList<>(); - - public void register(Subscriber subscriber) { - if (isSubscribed(subscriber)) return; - subscribers.add(new WeakReference<>(subscriber)); - } - - public void unregister(Subscriber subscriber) { - ListIterator> iterator = subscribers.listIterator(); - while (iterator.hasNext()) { - WeakReference ref = iterator.next(); - Subscriber registered = ref.get(); - if (registered != null && registered == subscriber) { - iterator.remove(); - } - } - } - - public void post(Event event) { - ListIterator> iterator = subscribers.listIterator(); - while (iterator.hasNext()) { - WeakReference ref = iterator.next(); - Subscriber registered = ref.get(); - if (registered != null) { - registered.onEvent(event); - } - } - } - - public boolean isSubscribed(Subscriber subscriber) { - for (WeakReference ref : subscribers) { - Subscriber registered = ref.get(); - if (registered != null && registered.equals(subscriber)) { - return true; - } - } - return false; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/FabSetEvent.java b/android/app/src/main/java/com/reactnativenavigation/events/FabSetEvent.java deleted file mode 100644 index 0e5fa4ee261..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/FabSetEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.reactnativenavigation.events; - -import com.reactnativenavigation.params.FabParams; - -public class FabSetEvent implements Event { - public static final String TYPE = "FabSetEvent"; - - public FabParams fabParams; - - public FabSetEvent(FabParams fabParams) { - this.fabParams = fabParams; - } - - @Override - public String getType() { - return TYPE; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/JsDevReloadEvent.java b/android/app/src/main/java/com/reactnativenavigation/events/JsDevReloadEvent.java deleted file mode 100644 index 344167212c9..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/JsDevReloadEvent.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.reactnativenavigation.events; - -public class JsDevReloadEvent implements Event { - - public static final String TYPE = "JsDevReloadEvent"; - - @Override - public String getType() { - return TYPE; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/ModalDismissedEvent.java b/android/app/src/main/java/com/reactnativenavigation/events/ModalDismissedEvent.java deleted file mode 100644 index 69261157f7b..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/ModalDismissedEvent.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.reactnativenavigation.events; - -public class ModalDismissedEvent implements Event { - public static final String TYPE = "ModalDismissedEvent"; - - @Override - public String getType() { - return TYPE; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/ScreenChangedEvent.java b/android/app/src/main/java/com/reactnativenavigation/events/ScreenChangedEvent.java deleted file mode 100644 index 8e4fc6fa0ef..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/ScreenChangedEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.reactnativenavigation.events; - -import com.reactnativenavigation.params.BaseScreenParams; -import com.reactnativenavigation.params.FabParams; - -public class ScreenChangedEvent implements Event { - public static final String TYPE = "ScreenChangedEvent"; - public FabParams fabParams; - - public ScreenChangedEvent(BaseScreenParams screenParams) { - this.fabParams = screenParams.getFab(); - } - - @Override - public String getType() { - return TYPE; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/Subscriber.java b/android/app/src/main/java/com/reactnativenavigation/events/Subscriber.java deleted file mode 100644 index 93ccb27c574..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/Subscriber.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.reactnativenavigation.events; - -public interface Subscriber { - void onEvent(Event event); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/ViewPagerScreenChangedEvent.java b/android/app/src/main/java/com/reactnativenavigation/events/ViewPagerScreenChangedEvent.java deleted file mode 100644 index f2e44cf8088..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/ViewPagerScreenChangedEvent.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.reactnativenavigation.events; - -public class ViewPagerScreenChangedEvent implements Event { - public static final String TYPE = "ViewPagerScreenChangedEvent"; - - @Override - public String getType() { - return TYPE; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/events/ViewPagerScreenScrollStartEvent.java b/android/app/src/main/java/com/reactnativenavigation/events/ViewPagerScreenScrollStartEvent.java deleted file mode 100644 index 625cef04997..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/events/ViewPagerScreenScrollStartEvent.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.reactnativenavigation.events; - -public class ViewPagerScreenScrollStartEvent implements Event { - public static final String TYPE = "ViewPagerScreenScrollStartEvent"; - @Override - public String getType() { - return TYPE; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/layouts/BaseLayout.java b/android/app/src/main/java/com/reactnativenavigation/layouts/BaseLayout.java deleted file mode 100644 index e8c9d2f70f4..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/layouts/BaseLayout.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.reactnativenavigation.layouts; - -import android.support.v7.app.AppCompatActivity; -import android.widget.RelativeLayout; - -public abstract class BaseLayout extends RelativeLayout implements Layout { - - public BaseLayout(AppCompatActivity activity) { - super(activity); - } - - protected AppCompatActivity getActivity() { - return (AppCompatActivity) getContext(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java b/android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java deleted file mode 100644 index 3b2b25d1482..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/layouts/BottomTabsLayout.java +++ /dev/null @@ -1,603 +0,0 @@ -package com.reactnativenavigation.layouts; - -import android.annotation.SuppressLint; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.view.View; -import android.widget.RelativeLayout; - -import com.aurelhubert.ahbottomnavigation.AHBottomNavigation; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.WritableMap; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.events.EventBus; -import com.reactnativenavigation.events.ScreenChangedEvent; -import com.reactnativenavigation.params.ActivityParams; -import com.reactnativenavigation.params.AppStyle; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.LightBoxParams; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.params.SideMenuParams; -import com.reactnativenavigation.params.SlidingOverlayParams; -import com.reactnativenavigation.params.SnackbarParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.screens.NavigationType; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.screens.ScreenStack; -import com.reactnativenavigation.utils.Task; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.BottomTabs; -import com.reactnativenavigation.views.LightBox; -import com.reactnativenavigation.views.SideMenu; -import com.reactnativenavigation.views.SideMenu.Side; -import com.reactnativenavigation.views.SnackbarAndFabContainer; -import com.reactnativenavigation.views.slidingOverlay.SlidingOverlay; -import com.reactnativenavigation.views.slidingOverlay.SlidingOverlaysQueue; - -import java.util.List; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; - -@SuppressLint("ViewConstructor") -public class BottomTabsLayout extends BaseLayout implements AHBottomNavigation.OnTabSelectedListener { - - private ActivityParams params; - private SnackbarAndFabContainer snackbarAndFabContainer; - private BottomTabs bottomTabs; - private ScreenStack[] screenStacks; - private final SideMenuParams leftSideMenuParams; - private final SideMenuParams rightSideMenuParams; - private final SlidingOverlaysQueue slidingOverlaysQueue = new SlidingOverlaysQueue(); - private - @Nullable - SideMenu sideMenu; - private int currentStackIndex = 0; - private LightBox lightBox; - - public BottomTabsLayout(AppCompatActivity activity, ActivityParams params) { - super(activity); - this.params = params; - leftSideMenuParams = params.leftSideMenuParams; - rightSideMenuParams = params.rightSideMenuParams; - screenStacks = new ScreenStack[params.tabParams.size()]; - createLayout(); - } - - private void createLayout() { - createSideMenu(); - createBottomTabs(); - addBottomTabs(); - addScreenStacks(); - createSnackbarContainer(); - showInitialScreenStack(); - setInitialTabIndex(); - } - - private void setInitialTabIndex() { - bottomTabs.setCurrentItem(AppStyle.appStyle.bottomTabsInitialIndex); - } - - private void createSideMenu() { - if (leftSideMenuParams == null && rightSideMenuParams == null) { - return; - } - sideMenu = new SideMenu(getContext(), leftSideMenuParams, rightSideMenuParams); - RelativeLayout.LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - addView(sideMenu, lp); - } - - private void addScreenStacks() { - for (int i = screenStacks.length - 1; i >= 0; i--) { - createAndAddScreens(i); - } - } - - private void createAndAddScreens(int position) { - ScreenParams screenParams = params.tabParams.get(position); - ScreenStack newStack = new ScreenStack(getActivity(), getScreenStackParent(), screenParams.getNavigatorId(), this); - newStack.pushInitialScreen(screenParams, createScreenLayoutParams(screenParams)); - screenStacks[position] = newStack; - } - - private RelativeLayout getScreenStackParent() { - return sideMenu == null ? this : sideMenu.getContentContainer(); - } - - @NonNull - private LayoutParams createScreenLayoutParams(ScreenParams params) { - LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - if (params.styleParams.drawScreenAboveBottomTabs) { - lp.addRule(RelativeLayout.ABOVE, bottomTabs.getId()); - } - return lp; - } - - private void createBottomTabs() { - bottomTabs = new BottomTabs(getContext()); - bottomTabs.addTabs(params.tabParams, this); - } - - private void addBottomTabs() { - LayoutParams lp = new LayoutParams(MATCH_PARENT, WRAP_CONTENT); - lp.addRule(ALIGN_PARENT_BOTTOM); - getScreenStackParent().addView(bottomTabs, lp); - } - - private void createSnackbarContainer() { - snackbarAndFabContainer = new SnackbarAndFabContainer(getContext(), this); - RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT); - alignSnackbarContainerWithBottomTabs(lp, getCurrentScreen().getStyleParams()); - snackbarAndFabContainer.setClickable(false); - getScreenStackParent().addView(snackbarAndFabContainer, lp); - } - - private void showInitialScreenStack() { - bottomTabs.setVisibilityByInitialScreen(getInitialScreenStack().peek().getStyleParams()); - showStackAndUpdateStyle(getInitialScreenStack(), NavigationType.InitialScreen); - EventBus.instance.post(new ScreenChangedEvent(screenStacks[0].peek().getScreenParams())); - } - - private ScreenStack getInitialScreenStack() { - return screenStacks[AppStyle.appStyle.bottomTabsInitialIndex]; - } - - @Override - public View asView() { - return this; - } - - @Override - public boolean onBackPressed() { - if (handleBackInJs()) { - return true; - } - - if (getCurrentScreenStack().canPop()) { - getCurrentScreenStack().pop(true, System.currentTimeMillis()); - setBottomTabsStyleFromCurrentScreen(); - EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams())); - return true; - } else { - return false; - } - } - - @Override - public boolean handleBackInJs() { - return getCurrentScreenStack().handleBackPressInJs(); - } - - @Override - public void setTopBarVisible(String screenInstanceId, boolean hidden, boolean animated) { - for (int i = 0; i < bottomTabs.getItemsCount(); i++) { - screenStacks[i].setScreenTopBarVisible(screenInstanceId, hidden, animated); - } - } - - public void setBottomTabsVisible(boolean hidden, boolean animated) { - getCurrentScreenStack().peek().updateBottomTabsVisibility(hidden); - bottomTabs.setVisibility(hidden, animated); - } - - @Override - public void setTitleBarTitle(String screenInstanceId, String title) { - for (int i = 0; i < bottomTabs.getItemsCount(); i++) { - screenStacks[i].setScreenTitleBarTitle(screenInstanceId, title); - } - } - - @Override - public void setTitleBarSubtitle(String screenInstanceId, String subtitle) { - for (int i = 0; i < bottomTabs.getItemsCount(); i++) { - screenStacks[i].setScreenTitleBarSubtitle(screenInstanceId, subtitle); - } - } - - @Override - public void setTitleBarRightButtons(String screenInstanceId, String navigatorEventId, List titleBarButtons) { - for (int i = 0; i < bottomTabs.getItemsCount(); i++) { - screenStacks[i].setScreenTitleBarRightButtons(screenInstanceId, navigatorEventId, titleBarButtons); - } - } - - @Override - public void setTitleBarLeftButton(String screenInstanceId, String navigatorEventId, TitleBarLeftButtonParams titleBarLeftButtonParams) { - for (int i = 0; i < bottomTabs.getItemsCount(); i++) { - screenStacks[i].setScreenTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButtonParams); - } - } - - @Override - public void setFab(String screenInstanceId, String navigatorEventId, FabParams fabParams) { - for (int i = 0; i < bottomTabs.getItemsCount(); i++) { - screenStacks[i].setFab(screenInstanceId, fabParams); - } - } - - @Override - public void updateScreenStyle(String screenInstanceId, Bundle styleParams) { - for (int i = 0; i < bottomTabs.getItemsCount(); i++) { - screenStacks[i].updateScreenStyle(screenInstanceId, styleParams); - } - } - - @Override - public String getCurrentlyVisibleScreenId() { - return getCurrentScreen().getScreenInstanceId(); - } - - @Override - public void selectTopTabByTabIndex(String screenInstanceId, int index) { - for (int i = 0; i < bottomTabs.getItemsCount(); i++) { - screenStacks[i].selectTopTabByTabIndex(screenInstanceId, index); - } - } - - @Override - public void selectTopTabByScreen(String screenInstanceId) { - for (int i = 0; i < bottomTabs.getItemsCount(); i++) { - screenStacks[i].selectTopTabByScreen(screenInstanceId); - } - } - - @Override - public void toggleSideMenuVisible(boolean animated, Side side) { - if (sideMenu != null) { - sideMenu.toggleVisible(animated, side); - } - } - - @Override - public void setSideMenuVisible(boolean animated, boolean visible, Side side) { - if (sideMenu != null) { - sideMenu.setVisible(visible, animated, side); - } - } - - @Override - public void setSideMenuEnabled(boolean enabled, Side side) { - if (sideMenu != null) { - sideMenu.setDrawerLockMode(enabled ? DrawerLayout.LOCK_MODE_UNLOCKED : DrawerLayout.LOCK_MODE_LOCKED_CLOSED); - } - } - - @Override - public void showSnackbar(SnackbarParams params) { - final String eventId = getCurrentScreenStack().peek().getNavigatorEventId(); - snackbarAndFabContainer.showSnackbar(eventId, params); - } - - @Override - public void dismissSnackbar() { - snackbarAndFabContainer.dismissSnackbar(); - } - - @Override - public void showLightBox(LightBoxParams params) { - if (lightBox == null) { - lightBox = new LightBox(getActivity(), new Runnable() { - @Override - public void run() { - lightBox = null; - } - }, params); - lightBox.show(); - } - } - - @Override - public void dismissLightBox() { - if (lightBox != null) { - lightBox.hide(); - lightBox = null; - } - } - - @Override - public void showSlidingOverlay(final SlidingOverlayParams params) { - slidingOverlaysQueue.add(new SlidingOverlay(this, params)); - } - - @Override - public void hideSlidingOverlay() { - slidingOverlaysQueue.remove(); - } - - @Override - public void onModalDismissed() { - getCurrentScreenStack().peek().getScreenParams().timestamp = System.currentTimeMillis(); - NavigationApplication.instance.getEventEmitter().sendWillAppearEvent(getCurrentScreenStack().peek().getScreenParams(), NavigationType.DismissModal); - NavigationApplication.instance.getEventEmitter().sendDidAppearEvent(getCurrentScreenStack().peek().getScreenParams(), NavigationType.DismissModal); - EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams())); - } - - @Override - public boolean containsNavigator(String navigatorId) { - // Unused - return false; - } - - @Override - public void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked) { - getCurrentScreenStack().peek().showContextualMenu(params, onButtonClicked); - } - - @Override - public void dismissContextualMenu(String screenInstanceId) { - getCurrentScreenStack().peek().dismissContextualMenu(); - } - - @Override - public Screen getCurrentScreen() { - return getCurrentScreenStack().peek(); - } - - public void selectBottomTabByTabIndex(Integer index) { - if (bottomTabs.getCurrentItem() != index) { - bottomTabs.setCurrentItemWithoutInvokingTabSelectedListener(index); - switchTab(index, NavigationType.SwitchToTab); - } - } - - public void selectBottomTabByNavigatorId(final String navigatorId) { - performOnStack(navigatorId, new Task() { - @Override - public void run(ScreenStack param) { - selectBottomTabByTabIndex(getScreenStackIndex(navigatorId)); - } - }); - } - - private boolean hasBackgroundColor(StyleParams params) { - return params.screenBackgroundColor != null && - params.screenBackgroundColor.hasColor(); - } - - private void setStyleFromScreen(StyleParams params) { - bottomTabs.setStyleFromScreen(params); - if (snackbarAndFabContainer != null && snackbarAndFabContainer.getLayoutParams() instanceof RelativeLayout.LayoutParams) - alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params); - if (hasBackgroundColor(params)) { - asView().setBackgroundColor(params.screenBackgroundColor.getColor()); - } - } - - @Override - public void push(final ScreenParams params, final Promise onPushComplete) { - performOnStack(params.getNavigatorId(), new Task() { - @Override - public void run(ScreenStack screenStack) { - screenStack.push(params, createScreenLayoutParams(params), onPushComplete); - if (isCurrentStack(screenStack)) { - setStyleFromScreen(params.styleParams); - EventBus.instance.post(new ScreenChangedEvent(params)); - } - } - }); - } - - @Override - public void pop(final ScreenParams params) { - performOnStack(params.getNavigatorId(), new Task() { - @Override - public void run(ScreenStack stack) { - stack.pop(params.animateScreenTransitions, params.timestamp, new ScreenStack.OnScreenPop() { - @Override - public void onScreenPopAnimationEnd() { - setBottomTabsStyleFromCurrentScreen(); - EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams())); - } - }); - } - }); - } - - @Override - public void popToRoot(final ScreenParams params) { - performOnStack(params.getNavigatorId(), new Task() { - @Override - public void run(final ScreenStack stack) { - stack.popToRoot(params.animateScreenTransitions, params.timestamp, new ScreenStack.OnScreenPop() { - @Override - public void onScreenPopAnimationEnd() { - if (isCurrentStack(stack)) { - setBottomTabsStyleFromCurrentScreen(); - alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams); - EventBus.instance.post(new ScreenChangedEvent(stack.peek().getScreenParams())); - } - } - }); - } - }); - } - - @Override - public void newStack(final ScreenParams params) { - performOnStack(params.getNavigatorId(), new Task() { - @Override - public void run(ScreenStack screenStack) { - screenStack.newStack(params, createScreenLayoutParams(params)); - if (isCurrentStack(screenStack)) { - setStyleFromScreen(params.styleParams); - alignSnackbarContainerWithBottomTabs((LayoutParams) snackbarAndFabContainer.getLayoutParams(), params.styleParams); - EventBus.instance.post(new ScreenChangedEvent(params)); - } - } - }); - } - - private void alignSnackbarContainerWithBottomTabs(LayoutParams lp, StyleParams styleParams) { - if (styleParams.drawScreenAboveBottomTabs || !styleParams.bottomTabsHidden) { - lp.addRule(ABOVE, bottomTabs.getId()); - } else { - ViewUtils.removeRuleCompat(lp, ABOVE); - } - } - - private void performOnStack(String navigatorId, Task task) { - try { - ScreenStack screenStack = getScreenStack(navigatorId); - task.run(screenStack); - } catch (ScreenStackNotFoundException e) { - Log.e("Navigation", "Could not perform action on stack [" + navigatorId + "]." + - "This should not have happened, it probably means a navigator action" + - "was called from an unmounted tab."); - } - } - - @Override - public void destroy() { - snackbarAndFabContainer.destroy(); - for (ScreenStack screenStack : screenStacks) { - screenStack.destroy(); - } - if (sideMenu != null) { - sideMenu.destroy(); - } - if (lightBox != null) { - lightBox.destroy(); - lightBox = null; - } - slidingOverlaysQueue.destroy(); - } - - @Override - public boolean onTabSelected(int position, boolean wasSelected) { - if (wasSelected) { - sendTabReselectedEventToJs(); - return false; - } - - final int unselectedTabIndex = currentStackIndex; - sendTabSelectedEventToJs(position, unselectedTabIndex); - switchTab(position, NavigationType.BottomTabSelected); - return true; - } - - private void switchTab(int position, NavigationType navigationType) { - hideCurrentStack(); - showNewStack(position, navigationType); - EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams())); - } - - private void sendTabSelectedEventToJs(int selectedTabIndex, int unselectedTabIndex) { - String navigatorEventId = screenStacks[selectedTabIndex].peek().getNavigatorEventId(); - WritableMap data = createTabSelectedEventData(selectedTabIndex, unselectedTabIndex); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("bottomTabSelected", navigatorEventId, data); - - data = createTabSelectedEventData(selectedTabIndex, unselectedTabIndex); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("bottomTabSelected", data); - } - - private WritableMap createTabSelectedEventData(int selectedTabIndex, int unselectedTabIndex) { - WritableMap data = Arguments.createMap(); - data.putInt("selectedTabIndex", selectedTabIndex); - data.putInt("unselectedTabIndex", unselectedTabIndex); - return data; - } - - private void sendTabReselectedEventToJs() { - WritableMap data = Arguments.createMap(); - String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId(); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("bottomTabReselected", navigatorEventId, data); - } - - private void showNewStack(int position, NavigationType type) { - showStackAndUpdateStyle(screenStacks[position], type); - currentStackIndex = position; - } - - private void showStackAndUpdateStyle(ScreenStack newStack, NavigationType type) { - newStack.show(type); - setStyleFromScreen(newStack.getCurrentScreenStyleParams()); - } - - private void hideCurrentStack() { - ScreenStack currentScreenStack = getCurrentScreenStack(); - currentScreenStack.hide(NavigationType.BottomTabSelected); - } - - private ScreenStack getCurrentScreenStack() { - return screenStacks[currentStackIndex]; - } - - private - @NonNull - ScreenStack getScreenStack(String navigatorId) throws ScreenStackNotFoundException { - int index = getScreenStackIndex(navigatorId); - return screenStacks[index]; - } - - public void setBottomTabBadgeByIndex(Integer index, String badge) { - bottomTabs.setNotification(badge, index); - } - - public void setBottomTabBadgeByNavigatorId(String navigatorId, String badge) { - bottomTabs.setNotification(badge, getScreenStackIndex(navigatorId)); - } - - public void setBottomTabButtonByIndex(Integer index, ScreenParams params) { - bottomTabs.setTabButton(params, index); - } - - public void setBottomTabButtonByNavigatorId(String navigatorId, ScreenParams params) { - bottomTabs.setTabButton(params, getScreenStackIndex(navigatorId)); - } - - private int getScreenStackIndex(String navigatorId) throws ScreenStackNotFoundException { - for (int i = 0; i < screenStacks.length; i++) { - if (screenStacks[i].getNavigatorId().equals(navigatorId)) { - return i; - } - } - throw new ScreenStackNotFoundException("Stack " + navigatorId + " not found"); - } - - private class ScreenStackNotFoundException extends RuntimeException { - ScreenStackNotFoundException(String navigatorId) { - super(navigatorId); - } - } - - private boolean isCurrentStack(ScreenStack screenStack) { - return getCurrentScreenStack() == screenStack; - } - - private void setBottomTabsStyleFromCurrentScreen() { - setStyleFromScreen(getCurrentScreenStack().getCurrentScreenStyleParams()); - } - - @Override - public boolean onTitleBarBackButtonClick() { - if (getCurrentScreenStack().canPop()) { - getCurrentScreenStack().pop(true, System.currentTimeMillis(), new ScreenStack.OnScreenPop() { - @Override - public void onScreenPopAnimationEnd() { - setBottomTabsStyleFromCurrentScreen(); - EventBus.instance.post(new ScreenChangedEvent(getCurrentScreenStack().peek().getScreenParams())); - } - }); - return true; - } - return false; - } - - @Override - public void onSideMenuButtonClick() { - final String navigatorEventId = getCurrentScreenStack().peek().getNavigatorEventId(); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("sideMenu", navigatorEventId); - if (sideMenu != null) { - sideMenu.openDrawer(Side.Left); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java b/android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java deleted file mode 100644 index 51d7bbe4728..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/layouts/Layout.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.reactnativenavigation.layouts; - -import android.os.Bundle; -import android.view.View; - -import com.facebook.react.bridge.Callback; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.LightBoxParams; -import com.reactnativenavigation.params.SlidingOverlayParams; -import com.reactnativenavigation.params.SnackbarParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.views.SideMenu.Side; - -import java.util.List; - -public interface Layout extends ScreenStackContainer { - View asView(); - - boolean onBackPressed(); - - boolean handleBackInJs(); - - void setTopBarVisible(String screenInstanceId, boolean hidden, boolean animated); - - void setTitleBarTitle(String screenInstanceId, String title); - - void setTitleBarSubtitle(String screenInstanceId, String subtitle); - - void setTitleBarRightButtons(String screenInstanceId, String navigatorEventId, List titleBarButtons); - - void setTitleBarLeftButton(String screenInstanceId, String navigatorEventId, TitleBarLeftButtonParams titleBarLeftButtonParams); - - void setFab(String screenInstanceId, String navigatorEventId, FabParams fabParams); - - void toggleSideMenuVisible(boolean animated, Side side); - - void setSideMenuVisible(boolean animated, boolean visible, Side side); - - void setSideMenuEnabled(boolean enabled, Side side); - - void showSnackbar(SnackbarParams params); - - void showSlidingOverlay(SlidingOverlayParams params); - - void hideSlidingOverlay(); - - void onModalDismissed(); - - boolean containsNavigator(String navigatorId); - - void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked); - - void dismissContextualMenu(String screenInstanceId); - - Screen getCurrentScreen(); - - void dismissSnackbar(); - - void showLightBox(LightBoxParams params); - - void dismissLightBox(); - - void selectTopTabByTabIndex(String screenInstanceId, int index); - - void selectTopTabByScreen(String screenInstanceId); - - void updateScreenStyle(String screenInstanceId, Bundle styleParams); - - String getCurrentlyVisibleScreenId(); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/layouts/LayoutFactory.java b/android/app/src/main/java/com/reactnativenavigation/layouts/LayoutFactory.java deleted file mode 100644 index e8ba8436506..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/layouts/LayoutFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.reactnativenavigation.layouts; - -import android.support.v7.app.AppCompatActivity; -import android.util.Log; - -import com.reactnativenavigation.params.ActivityParams; - -public class LayoutFactory { - public static Layout create(AppCompatActivity activity, ActivityParams params) { - switch (params.type) { - case TabBased: - return createBottomTabsScreenLayout(activity, params); - case SingleScreen: - default: - return createSingleScreenLayout(activity, params); - } - } - - private static Layout createSingleScreenLayout(AppCompatActivity activity, ActivityParams params) { - return new SingleScreenLayout(activity, params.leftSideMenuParams, params.rightSideMenuParams, params.screenParams); - } - - private static Layout createBottomTabsScreenLayout(AppCompatActivity activity, ActivityParams params) { - if (params.tabParams.size() > 5) { - removeAllButTheFirst5Tabs(params); - } - return new BottomTabsLayout(activity, params); - } - - private static void removeAllButTheFirst5Tabs(ActivityParams params) { - Log.e("Navigation", "LayoutFactory:createBottomTabsScreenLayout() does not support more than 5 tabs, currently"); - while (params.tabParams.size() > 5) { - params.tabParams.remove(params.tabParams.size() - 1); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/layouts/ModalScreenLayout.java b/android/app/src/main/java/com/reactnativenavigation/layouts/ModalScreenLayout.java deleted file mode 100644 index a00f80b4f90..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/layouts/ModalScreenLayout.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.reactnativenavigation.layouts; - -import android.support.v7.app.AppCompatActivity; - -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.views.LeftButtonOnClickListener; - -public class ModalScreenLayout extends SingleScreenLayout { - - public ModalScreenLayout(AppCompatActivity activity, - ScreenParams screenParams, - LeftButtonOnClickListener leftButtonOnClickListener) { - super(activity, null, null, screenParams); - this.leftButtonOnClickListener = leftButtonOnClickListener; - } - - @Override - protected void pushInitialScreen(LayoutParams lp) { - stack.pushInitialModalScreenWithAnimation(screenParams, lp); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/layouts/ScreenStackContainer.java b/android/app/src/main/java/com/reactnativenavigation/layouts/ScreenStackContainer.java deleted file mode 100644 index 37fb57e57db..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/layouts/ScreenStackContainer.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.reactnativenavigation.layouts; - -import com.facebook.react.bridge.Promise; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.views.LeftButtonOnClickListener; - -public interface ScreenStackContainer extends LeftButtonOnClickListener { - void push(ScreenParams screenParams, Promise onPushComplete); - - void pop(ScreenParams screenParams); - - void popToRoot(ScreenParams params); - - void newStack(ScreenParams params); - - void destroy(); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java b/android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java deleted file mode 100644 index 17720d90b2d..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/layouts/SingleScreenLayout.java +++ /dev/null @@ -1,343 +0,0 @@ -package com.reactnativenavigation.layouts; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.view.View; -import android.widget.RelativeLayout; - -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.Promise; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.events.EventBus; -import com.reactnativenavigation.events.ScreenChangedEvent; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.LightBoxParams; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.params.SideMenuParams; -import com.reactnativenavigation.params.SlidingOverlayParams; -import com.reactnativenavigation.params.SnackbarParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.screens.NavigationType; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.screens.ScreenStack; -import com.reactnativenavigation.views.LeftButtonOnClickListener; -import com.reactnativenavigation.views.LightBox; -import com.reactnativenavigation.views.SideMenu; -import com.reactnativenavigation.views.SideMenu.Side; -import com.reactnativenavigation.views.SnackbarAndFabContainer; -import com.reactnativenavigation.views.slidingOverlay.SlidingOverlay; -import com.reactnativenavigation.views.slidingOverlay.SlidingOverlaysQueue; - -import java.util.List; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - -public class SingleScreenLayout extends BaseLayout { - - protected final ScreenParams screenParams; - private final SideMenuParams leftSideMenuParams; - private final SideMenuParams rightSideMenuParams; - protected ScreenStack stack; - private SnackbarAndFabContainer snackbarAndFabContainer; - protected LeftButtonOnClickListener leftButtonOnClickListener; - private @Nullable SideMenu sideMenu; - private final SlidingOverlaysQueue slidingOverlaysQueue = new SlidingOverlaysQueue(); - private LightBox lightBox; - - public SingleScreenLayout(AppCompatActivity activity, SideMenuParams leftSideMenuParams, - SideMenuParams rightSideMenuParams, ScreenParams screenParams) { - super(activity); - this.screenParams = screenParams; - this.leftSideMenuParams = leftSideMenuParams; - this.rightSideMenuParams = rightSideMenuParams; - createLayout(); - } - - private void createLayout() { - if (leftSideMenuParams == null && rightSideMenuParams == null) { - createStack(getScreenStackParent()); - } else { - sideMenu = createSideMenu(); - createStack(getScreenStackParent()); - } - createFabAndSnackbarContainer(); - sendScreenChangedEventAfterInitialPush(); - } - - private RelativeLayout getScreenStackParent() { - return sideMenu == null ? this : sideMenu.getContentContainer(); - } - - private SideMenu createSideMenu() { - SideMenu sideMenu = new SideMenu(getContext(), leftSideMenuParams, rightSideMenuParams); - RelativeLayout.LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - addView(sideMenu, lp); - return sideMenu; - } - - private void createStack(RelativeLayout parent) { - if (stack != null) { - stack.destroy(); - } - stack = new ScreenStack(getActivity(), parent, screenParams.getNavigatorId(), this); - LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - pushInitialScreen(lp); - } - - protected void pushInitialScreen(LayoutParams lp) { - stack.pushInitialScreen(screenParams, lp); - stack.show(NavigationType.Push); - } - - private void sendScreenChangedEventAfterInitialPush() { - if (screenParams.topTabParams != null) { - EventBus.instance.post(new ScreenChangedEvent(screenParams.topTabParams.get(0))); - } else { - EventBus.instance.post(new ScreenChangedEvent(screenParams)); - } - } - - private void createFabAndSnackbarContainer() { - snackbarAndFabContainer = new SnackbarAndFabContainer(getContext(), this); - RelativeLayout.LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - lp.addRule(ALIGN_PARENT_BOTTOM); - snackbarAndFabContainer.setLayoutParams(lp); - getScreenStackParent().addView(snackbarAndFabContainer); - } - - @Override - public boolean onBackPressed() { - if (handleBackInJs()) { - return true; - } - - if (stack.canPop()) { - stack.pop(true, System.currentTimeMillis()); - EventBus.instance.post(new ScreenChangedEvent(stack.peek().getScreenParams())); - return true; - } else { - return false; - } - } - - @Override - public boolean handleBackInJs() { - return stack.handleBackPressInJs(); - } - - @Override - public void destroy() { - stack.destroy(); - snackbarAndFabContainer.destroy(); - if (sideMenu != null) { - sideMenu.destroy(); - } - if (sideMenu != null) { - sideMenu.destroy(); - } - if (lightBox != null) { - lightBox.destroy(); - } - slidingOverlaysQueue.destroy(); - } - - @Override - public void push(ScreenParams params, Promise onPushComplete) { - stack.push(params, new LayoutParams(MATCH_PARENT, MATCH_PARENT), onPushComplete); - EventBus.instance.post(new ScreenChangedEvent(params)); - } - - @Override - public void pop(ScreenParams params) { - stack.pop(params.animateScreenTransitions, params.timestamp, new ScreenStack.OnScreenPop() { - @Override - public void onScreenPopAnimationEnd() { - EventBus.instance.post(new ScreenChangedEvent(stack.peek().getScreenParams())); - } - }); - } - - @Override - public void popToRoot(ScreenParams params) { - stack.popToRoot(params.animateScreenTransitions, params.timestamp, new ScreenStack.OnScreenPop() { - @Override - public void onScreenPopAnimationEnd() { - EventBus.instance.post(new ScreenChangedEvent(stack.peek().getScreenParams())); - } - }); - } - - @Override - public void newStack(final ScreenParams params) { - stack.newStack(params, new LayoutParams(MATCH_PARENT, MATCH_PARENT)); - EventBus.instance.post(new ScreenChangedEvent(params)); - } - - @Override - public void setTopBarVisible(String screenInstanceID, boolean visible, boolean animate) { - stack.setScreenTopBarVisible(screenInstanceID, visible, animate); - } - - @Override - public void setTitleBarTitle(String screenInstanceId, String title) { - stack.setScreenTitleBarTitle(screenInstanceId, title); - } - - @Override - public void setTitleBarSubtitle(String screenInstanceId, String subtitle) { - stack.setScreenTitleBarSubtitle(screenInstanceId, subtitle); - } - - @Override - public View asView() { - return this; - } - - @Override - public void setTitleBarRightButtons(String screenInstanceId, String navigatorEventId, - List titleBarRightButtons) { - stack.setScreenTitleBarRightButtons(screenInstanceId, navigatorEventId, titleBarRightButtons); - } - - @Override - public void setTitleBarLeftButton(String screenInstanceId, String navigatorEventId, TitleBarLeftButtonParams titleBarLeftButtonParams) { - stack.setScreenTitleBarLeftButton(screenInstanceId, navigatorEventId, titleBarLeftButtonParams); - } - - @Override - public void setFab(String screenInstanceId, String navigatorEventId, FabParams fabParams) { - stack.setFab(screenInstanceId, fabParams); - } - - @Override - public void toggleSideMenuVisible(boolean animated, Side side) { - if (sideMenu != null) { - sideMenu.toggleVisible(animated, side); - } - } - - @Override - public void setSideMenuVisible(boolean animated, boolean visible, Side side) { - if (sideMenu != null) { - sideMenu.setVisible(visible, animated, side); - } - } - - @Override - public void setSideMenuEnabled(boolean enabled, Side side) { - if (sideMenu != null) { - sideMenu.setEnabled(enabled, side); - } - } - - @Override - public void showSnackbar(SnackbarParams params) { - final String navigatorEventId = stack.peek().getNavigatorEventId(); - snackbarAndFabContainer.showSnackbar(navigatorEventId, params); - } - - @Override - public void dismissSnackbar() { - snackbarAndFabContainer.dismissSnackbar(); - } - - @Override - public void showLightBox(LightBoxParams params) { - if (lightBox == null) { - lightBox = new LightBox(getActivity(), new Runnable() { - @Override - public void run() { - lightBox = null; - } - }, params); - lightBox.show(); - } - } - - @Override - public void dismissLightBox() { - if (lightBox != null) { - lightBox.hide(); - lightBox = null; - } - } - - @Override - public void selectTopTabByTabIndex(String screenInstanceId, int index) { - stack.selectTopTabByTabIndex(screenInstanceId, index); - } - - @Override - public void selectTopTabByScreen(String screenInstanceId) { - stack.selectTopTabByScreen(screenInstanceId); - } - - @Override - public void updateScreenStyle(String screenInstanceId, Bundle styleParams) { - stack.updateScreenStyle(screenInstanceId, styleParams); - } - - @Override - public String getCurrentlyVisibleScreenId() { - return stack.peek().getScreenInstanceId(); - } - - @Override - public void showSlidingOverlay(final SlidingOverlayParams params) { - slidingOverlaysQueue.add(new SlidingOverlay(this, params)); - } - - @Override - public void hideSlidingOverlay() { - slidingOverlaysQueue.remove(); - } - - @Override - public void onModalDismissed() { - stack.peek().getScreenParams().timestamp = System.currentTimeMillis(); - NavigationApplication.instance.getEventEmitter().sendWillAppearEvent(stack.peek().getScreenParams(), NavigationType.DismissModal); - NavigationApplication.instance.getEventEmitter().sendDidAppearEvent(stack.peek().getScreenParams(), NavigationType.DismissModal); - EventBus.instance.post(new ScreenChangedEvent(stack.peek().getScreenParams())); - } - - @Override - public boolean containsNavigator(String navigatorId) { - return stack.getNavigatorId().equals(navigatorId); - } - - @Override - public void showContextualMenu(String screenInstanceId, ContextualMenuParams params, Callback onButtonClicked) { - stack.showContextualMenu(screenInstanceId, params, onButtonClicked); - } - - @Override - public void dismissContextualMenu(String screenInstanceId) { - stack.dismissContextualMenu(screenInstanceId); - } - - @Override - public Screen getCurrentScreen() { - return stack.peek(); - } - - @Override - public boolean onTitleBarBackButtonClick() { - if (leftButtonOnClickListener != null) { - return leftButtonOnClickListener.onTitleBarBackButtonClick(); - } - - return onBackPressed(); - } - - @Override - public void onSideMenuButtonClick() { - final String navigatorEventId = stack.peek().getNavigatorEventId(); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("sideMenu", navigatorEventId); - if (sideMenu != null) { - sideMenu.openDrawer(Side.Left); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/ActivityParams.java b/android/app/src/main/java/com/reactnativenavigation/params/ActivityParams.java deleted file mode 100644 index 67f987d2191..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/ActivityParams.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.reactnativenavigation.params; - -import java.util.List; - -public class ActivityParams { - public enum Type { - SingleScreen, TabBased - } - - public Type type; - public ScreenParams screenParams; - public List tabParams; - public SideMenuParams leftSideMenuParams; - public SideMenuParams rightSideMenuParams; - public boolean animateShow; -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/AppStyle.java b/android/app/src/main/java/com/reactnativenavigation/params/AppStyle.java deleted file mode 100644 index 59245a66c90..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/AppStyle.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.reactnativenavigation.params; - -import android.os.Bundle; - -import com.reactnativenavigation.params.parsers.StyleParamsParser; - -public class AppStyle { - public static StyleParams appStyle; - - public static void setAppStyle(Bundle params) { - appStyle = new StyleParamsParser(params.getBundle("appStyle")).parse(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/BaseScreenParams.java b/android/app/src/main/java/com/reactnativenavigation/params/BaseScreenParams.java deleted file mode 100644 index ce93a5799f2..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/BaseScreenParams.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.reactnativenavigation.params; - -import android.graphics.drawable.Drawable; -import android.os.Bundle; - -import java.util.List; - -public class BaseScreenParams { - public double timestamp; - public String screenId; - public String title; - public String subtitle; - public Drawable tabIcon; - public NavigationParams navigationParams; - public List rightButtons; - public TitleBarLeftButtonParams leftButton; - public FabParams fabParams; - - public boolean overrideBackPressInJs; - public StyleParams styleParams; - public String fragmentCreatorClassName; - public Bundle fragmentCreatorPassProps; - public boolean animateScreenTransitions; - public String animationType; - - public boolean isFragmentScreen() { - return fragmentCreatorClassName != null; - } - - public String getScreenInstanceId() { - return navigationParams.screenInstanceId; - } - - public String getNavigatorId() { - return navigationParams.navigatorId; - } - - public String getNavigatorEventId() { - return navigationParams.navigatorEventId; - } - - public boolean hasCollapsingTopBar() { - return styleParams.collapsingTopBarParams != null; - } - - public FabParams getFab() { - return fabParams; - } - - public void setFab(FabParams params) { - fabParams = params; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/BaseTitleBarButtonParams.java b/android/app/src/main/java/com/reactnativenavigation/params/BaseTitleBarButtonParams.java deleted file mode 100644 index 254fe01ba02..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/BaseTitleBarButtonParams.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.reactnativenavigation.params; - -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.view.MenuItem; - -public class BaseTitleBarButtonParams { - public enum ShowAsAction { - IfRoom(MenuItem.SHOW_AS_ACTION_IF_ROOM), - Always(MenuItem.SHOW_AS_ACTION_ALWAYS), - Never(MenuItem.SHOW_AS_ACTION_NEVER), - WithText(MenuItem.SHOW_AS_ACTION_WITH_TEXT); - - public final int action; - - ShowAsAction(int action) { - this.action = action; - } - } - - public String eventId; - public String label; - public Drawable icon; - public String componentName; - public Bundle componentProps; - public StyleParams.Color color; - public StyleParams.Color disabledColor; - public ShowAsAction showAsAction; - public boolean enabled = true; - public boolean disableIconTint = false; - - public void setStyleFromScreen(StyleParams styleParams) { - setColorFromScreenStyle(styleParams.titleBarButtonColor); - } - - private void setColorFromScreenStyle(StyleParams.Color titleBarButtonColor) { - if (titleBarButtonColor.hasColor() && shouldOverrideColorFromScreenStyle()) { - color = titleBarButtonColor; - } - } - - private boolean shouldOverrideColorFromScreenStyle() { - // Override color if no color is defined, or if the defined color was set by AppStyle - return !color.hasColor() || color == AppStyle.appStyle.titleBarButtonColor; - } - - public StyleParams.Color getColor() { - if (enabled) { - return color; - } - return disabledColor.hasColor() ? disabledColor : AppStyle.appStyle.titleBarDisabledButtonColor; - } - - public boolean hasComponent() { - return componentName != null; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/CollapsingTopBarParams.java b/android/app/src/main/java/com/reactnativenavigation/params/CollapsingTopBarParams.java deleted file mode 100644 index c590c03b528..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/CollapsingTopBarParams.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.reactnativenavigation.params; - -import android.support.annotation.Nullable; - -import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseBehaviour; - -public class CollapsingTopBarParams { - public @Nullable String imageUri; - public @Nullable String reactViewId; - public StyleParams.Color scrimColor; - public CollapseBehaviour collapseBehaviour; - public boolean expendOnTopTabChange; - public boolean showTitleWhenExpended; - public boolean showTitleWhenCollapsed; - public StyleParams.Color expendedTitleBarColor; - - public boolean hasBackgroundImage() { - return imageUri != null; - } - - public boolean hasReactView() { - return reactViewId != null; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuButtonParams.java b/android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuButtonParams.java deleted file mode 100644 index 0a02425c917..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuButtonParams.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.reactnativenavigation.params; - -public class ContextualMenuButtonParams extends TitleBarButtonParams { - public int index; -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuParams.java b/android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuParams.java deleted file mode 100644 index dbbdd5a296f..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/ContextualMenuParams.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.reactnativenavigation.params; - -import java.util.List; - -public class ContextualMenuParams { - public List buttons; - public TitleBarLeftButtonParams leftButton; - public NavigationParams navigationParams; - - public void setButtonsColor(StyleParams.Color buttonColor) { - for (ContextualMenuButtonParams button : buttons) { - button.color = buttonColor; - } - leftButton.color = buttonColor; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/FabActionParams.java b/android/app/src/main/java/com/reactnativenavigation/params/FabActionParams.java deleted file mode 100644 index ca1c6357982..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/FabActionParams.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.reactnativenavigation.params; - -import android.graphics.drawable.Drawable; - -public class FabActionParams { - public String id; - public String navigatorEventId; - public Drawable icon; - public StyleParams.Color backgroundColor; - public StyleParams.Color iconColor; -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/FabParams.java b/android/app/src/main/java/com/reactnativenavigation/params/FabParams.java deleted file mode 100644 index 1f7c29217ec..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/FabParams.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.reactnativenavigation.params; - -import android.graphics.drawable.Drawable; - -import java.util.List; - -public class FabParams { - public Drawable collapsedIcon; - public Drawable expendedIcon; - public StyleParams.Color backgroundColor; - public StyleParams.Color collapsedIconColor; - public StyleParams.Color expendedIconColor; - public String collapsedId; - public String expendedId; - public String navigatorEventId; - public List actions; - public String screenInstanceId; - - public boolean hasExpendedState() { - return actions != null && actions.size() > 0; - } - - public boolean isValid() { - return collapsedId != null; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/InterpolationParams.java b/android/app/src/main/java/com/reactnativenavigation/params/InterpolationParams.java deleted file mode 100644 index 7069ecd3250..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/InterpolationParams.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.reactnativenavigation.params; - -import android.animation.TimeInterpolator; -import android.support.v4.view.animation.FastOutSlowInInterpolator; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; -import android.view.animation.LinearInterpolator; - -public abstract class InterpolationParams { - public enum Type { - Path("path"), Linear("linear"); - private String name; - - Type(String name) { - this.name = name; - } - - public static Type fromString(String name) { - for (Type type : values()) { - if (type.name.equals(name)) { - return type; - } - } - return Linear; - } - } - - public enum Easing { - AccelerateDecelerate("accelerateDecelerate", new AccelerateDecelerateInterpolator()), - Accelerate("accelerate", new AccelerateInterpolator()), - Decelerate("decelerate", new DecelerateInterpolator()), - FastOutSlowIn("FastOutSlowIn", new FastOutSlowInInterpolator()), - Linear("linear", new LinearInterpolator()); - - private String name; - private TimeInterpolator interpolator; - - Easing(String name, TimeInterpolator interpolator) { - this.name = name; - this.interpolator = interpolator; - } - - public static Easing fromString(String name) { - for (Easing easing : values()) { - if (easing.name.equals(name)) { - return easing; - } - } - return Linear; - } - - public TimeInterpolator getInterpolator() { - return interpolator; - } - } - - public Type type; - public Easing easing; - - public abstract Interpolator get(); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/LightBoxParams.java b/android/app/src/main/java/com/reactnativenavigation/params/LightBoxParams.java deleted file mode 100644 index 71fdff5e60d..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/LightBoxParams.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.reactnativenavigation.params; - -public class LightBoxParams { - public String screenId; - public NavigationParams navigationParams; - public StyleParams.Color backgroundColor; - public boolean tapBackgroundToDismiss; - public boolean overrideBackPress; - public int adjustSoftInput; -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/LinearInterpolationParams.java b/android/app/src/main/java/com/reactnativenavigation/params/LinearInterpolationParams.java deleted file mode 100644 index 7d015696030..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/LinearInterpolationParams.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.reactnativenavigation.params; - -import android.view.animation.Interpolator; -import android.view.animation.LinearInterpolator; - -public class LinearInterpolationParams extends InterpolationParams { - @Override - public Interpolator get() { - return new LinearInterpolator(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/NavigationParams.java b/android/app/src/main/java/com/reactnativenavigation/params/NavigationParams.java deleted file mode 100644 index f61282a8d56..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/NavigationParams.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.reactnativenavigation.params; - -import android.os.Bundle; - -public class NavigationParams { - public static final NavigationParams EMPTY = new NavigationParams(Bundle.EMPTY); - - private static final String SCREEN_INSTANCE_ID = "screenInstanceID"; - private static final String NAVIGATOR_ID = "navigatorID"; - private static final String NAVIGATOR_EVENT_ID = "navigatorEventID"; - - public String screenInstanceId; - public String navigatorId; - public String navigatorEventId; - - public NavigationParams(Bundle bundle) { - screenInstanceId = bundle.getString(SCREEN_INSTANCE_ID); - navigatorId = bundle.getString(NAVIGATOR_ID); - navigatorEventId = bundle.getString(NAVIGATOR_EVENT_ID); - } - - public Bundle toBundle() { - Bundle b = new Bundle(); - b.putString(SCREEN_INSTANCE_ID, screenInstanceId); - b.putString(NAVIGATOR_ID, navigatorId); - b.putString(NAVIGATOR_EVENT_ID, navigatorEventId); - return b; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/Orientation.java b/android/app/src/main/java/com/reactnativenavigation/params/Orientation.java deleted file mode 100644 index ba85e2cd010..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/Orientation.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.reactnativenavigation.params; - -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; - -public enum Orientation { - Portrait("portrait", Configuration.ORIENTATION_PORTRAIT, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT), - Landscape("landscape", Configuration.ORIENTATION_LANDSCAPE, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE), - auto("auto", Configuration.ORIENTATION_UNDEFINED, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - - public String name; - public int configurationCode; - public int orientationCode; - - Orientation(String name, int configurationCode, int orientationCode) { - this.name = name; - this.configurationCode = configurationCode; - this.orientationCode = orientationCode; - } - - public static Orientation fromString(String name) { - for (Orientation orientation : values()) { - if (orientation.name.equals(name)) { - return orientation; - } - } - throw new RuntimeException(); - } - - public static String fromConfigurationCode(int configurationCode) { - for (Orientation orientation : values()) { - if (orientation.configurationCode == configurationCode) { - return orientation.name; - } - } - throw new RuntimeException(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/PageParams.java b/android/app/src/main/java/com/reactnativenavigation/params/PageParams.java deleted file mode 100644 index 769dc93defe..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/PageParams.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.reactnativenavigation.params; - -public class PageParams extends BaseScreenParams { - - -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/PathInterpolationParams.java b/android/app/src/main/java/com/reactnativenavigation/params/PathInterpolationParams.java deleted file mode 100644 index 73908e59d71..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/PathInterpolationParams.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.reactnativenavigation.params; - -import android.annotation.TargetApi; -import android.os.Build; -import android.view.animation.Interpolator; - -import com.reactnativenavigation.views.sharedElementTransition.ControlPoint; - -@TargetApi(Build.VERSION_CODES.LOLLIPOP) -public class PathInterpolationParams extends InterpolationParams { - - public ControlPoint p1; - public ControlPoint p2; - - @Override - public Interpolator get() { - // Not called - return null; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/ScreenParams.java b/android/app/src/main/java/com/reactnativenavigation/params/ScreenParams.java deleted file mode 100644 index 7172dd02969..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/ScreenParams.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.reactnativenavigation.params; - -import java.util.List; - -public class ScreenParams extends BaseScreenParams { - public String tabLabel; - public List topTabParams; - public List sharedElementsTransitions; - - public boolean hasTopTabs() { - return topTabParams != null && !topTabParams.isEmpty(); - } - - public FabParams getFab() { - return hasTopTabs() ? topTabParams.get(0).fabParams : fabParams; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/SideMenuParams.java b/android/app/src/main/java/com/reactnativenavigation/params/SideMenuParams.java deleted file mode 100644 index 293a979d76d..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/SideMenuParams.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.reactnativenavigation.params; - -import com.reactnativenavigation.views.SideMenu; - -public class SideMenuParams extends BaseScreenParams { - public boolean disableOpenGesture; - public SideMenu.Side side; - public int fixedWidth; -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/SlidingOverlayParams.java b/android/app/src/main/java/com/reactnativenavigation/params/SlidingOverlayParams.java deleted file mode 100644 index 3af43bb062d..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/SlidingOverlayParams.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.reactnativenavigation.params; - -public class SlidingOverlayParams { - public enum Position { - Top, Bottom; - - public static Position fromString(String string) { - switch(string) { - case "bottom": - return Position.Bottom; - case "top": - default: - return Position.Top; - } - } - } - - public String screenInstanceId; - public NavigationParams navigationParams; - public Integer autoDismissTimerSec; - public Position position; -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/SnackbarParams.java b/android/app/src/main/java/com/reactnativenavigation/params/SnackbarParams.java deleted file mode 100644 index d3435da6868..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/SnackbarParams.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.reactnativenavigation.params; - -public class SnackbarParams { - public String text; - public String buttonText; - public StyleParams.Color buttonColor; - public StyleParams.Color backgroundColor; - public String eventId; - public int duration; - public StyleParams.Color textColor; -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/StatusBarTextColorScheme.java b/android/app/src/main/java/com/reactnativenavigation/params/StatusBarTextColorScheme.java deleted file mode 100644 index ae903e11633..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/StatusBarTextColorScheme.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.reactnativenavigation.params; - -import android.os.Build; -import android.support.annotation.Nullable; - -public enum StatusBarTextColorScheme { - Light, Dark, Undefined; - - public static StatusBarTextColorScheme fromString(@Nullable String colorScheme, StatusBarTextColorScheme defaultScheme) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || colorScheme == null) return defaultScheme; - switch (colorScheme) { - case "light": - return Light; - case "dark": - return Dark; - default: - return defaultScheme; - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/StyleParams.java b/android/app/src/main/java/com/reactnativenavigation/params/StyleParams.java deleted file mode 100644 index 8da9a4c6c77..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/StyleParams.java +++ /dev/null @@ -1,164 +0,0 @@ -package com.reactnativenavigation.params; - -import android.graphics.Typeface; -import android.os.Bundle; -import android.support.annotation.ColorInt; -import android.text.TextUtils; - -import com.reactnativenavigation.utils.TypefaceLoader; - -public class StyleParams { - public Bundle params; - - public StyleParams(Bundle params) { - this.params = params; - } - public static class Color { - @ColorInt - private Integer color = null; - - public Color() { - color = null; - } - - public Color(Integer color) { - this.color = color; - } - - public boolean hasColor() { - return color != null; - } - - @ColorInt - public int getColor() { - if (!hasColor()) { - throw new RuntimeException("Color undefined"); - } - return color; - } - - public static Color parse(Bundle bundle, String key) { - return bundle.containsKey(key) ? new Color(bundle.getInt(key)) : new Color(); - } - - public String getHexColor() { - return String.format("#%06X", (0xFFFFFF & getColor())); - } - - public int getColor(int defaultColor) { - return hasColor() ? getColor() : defaultColor; - } - - @Override - public String toString() { - return this.getHexColor(); - } - } - - public static class Font { - private Typeface typeface; - String fontFamilyName; - - public Font(String font) { - fontFamilyName = font; - typeface = new TypefaceLoader(font).getTypeFace(); - } - - public Font() { - } - - public boolean hasFont() { - return typeface != null && fontFamilyName != null; - } - - public Typeface get() { - if (typeface == null) { - throw new RuntimeException("Font undefined"); - } - return typeface; - } - - @Override - public String toString() { - return fontFamilyName; - } - } - - public Orientation orientation; - public String screenAnimationType; - public StatusBarTextColorScheme statusBarTextColorScheme; - public Color statusBarColor; - public boolean statusBarHidden; - public boolean drawUnderStatusBar; - public Color contextualMenuStatusBarColor; - public Color contextualMenuButtonsColor; - public Color contextualMenuBackgroundColor; - - public Color topBarColor; - public Color topBarBorderColor; - public float topBarBorderWidth; - public String topBarReactView; - public String topBarReactViewAlignment; - public Bundle topBarReactViewInitialProps; - public CollapsingTopBarParams collapsingTopBarParams; - public boolean topBarCollapseOnScroll; - public boolean topBarElevationShadowEnabled; - public boolean topTabsHidden; - public boolean drawScreenBelowTopBar; - - public boolean titleBarHidden; - public boolean titleBarHideOnScroll; - public boolean topBarTransparent; - public boolean topBarTranslucent; - public Color titleBarTitleColor; - public Color titleBarSubtitleColor; - public int titleBarSubtitleFontSize; - public Font titleBarSubtitleFontFamily; - public Color titleBarButtonColor; - public Color titleBarDisabledButtonColor; - public Font titleBarTitleFont; - public int titleBarTitleFontSize; - public boolean titleBarTitleFontBold; - public boolean titleBarTitleTextCentered; - public int titleBarHeight; - public boolean backButtonHidden; - public Font titleBarButtonFontFamily; - public int titleBarTopPadding; - - public Color topTabTextColor; - public Font topTabTextFontFamily; - public Color topTabIconColor; - public Color selectedTopTabTextColor; - public Color selectedTopTabIconColor; - public int selectedTopTabIndicatorHeight; - public Color selectedTopTabIndicatorColor; - public boolean topTabsScrollable; - public int topTabsHeight; - - public Color screenBackgroundColor; - - public boolean drawScreenAboveBottomTabs; - - public Color snackbarButtonColor; - - public int bottomTabsInitialIndex; - public boolean bottomTabsHidden; - public boolean bottomTabsHiddenOnScroll; - public Color bottomTabsColor; - public Color selectedBottomTabsButtonColor; - public Color bottomTabsButtonColor; - public boolean forceTitlesDisplay; - public Color bottomTabBadgeTextColor; - public Color bottomTabBadgeBackgroundColor; - public Font bottomTabFontFamily; - - public Color navigationBarColor; - - public boolean hasTopBarCustomComponent() { - return !TextUtils.isEmpty(topBarReactView); - } - - public boolean hasCustomTitleBarHeight() { - return titleBarHeight != -1; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/TitleBarButtonParams.java b/android/app/src/main/java/com/reactnativenavigation/params/TitleBarButtonParams.java deleted file mode 100644 index d8017f935c7..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/TitleBarButtonParams.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.reactnativenavigation.params; - -public class TitleBarButtonParams extends BaseTitleBarButtonParams { - public StyleParams.Font font; - public String hint; - - @Override - public void setStyleFromScreen(StyleParams styleParams) { - super.setStyleFromScreen(styleParams); - font = styleParams.titleBarButtonFontFamily.hasFont() ? styleParams.titleBarButtonFontFamily : styleParams.titleBarTitleFont; - } - - public boolean hasFont() { - return font != null && font.hasFont(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/TitleBarLeftButtonParams.java b/android/app/src/main/java/com/reactnativenavigation/params/TitleBarLeftButtonParams.java deleted file mode 100644 index 6bfaa8df1d9..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/TitleBarLeftButtonParams.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.reactnativenavigation.params; - -import android.support.annotation.Nullable; - -import com.balysv.materialmenu.MaterialMenuDrawable; - -public class TitleBarLeftButtonParams extends TitleBarButtonParams { - @Nullable public MaterialMenuDrawable.IconState iconState; - - public TitleBarLeftButtonParams(TitleBarButtonParams params) { - icon = params.icon; - color = params.color; - eventId = params.eventId; - enabled = params.enabled; - } - - public boolean isBackButton() { - return eventId.equals("back"); - } - - public boolean hasDefaultIcon() { - return iconState != null; - } - - public boolean hasCustomIcon() { - return icon != null; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ActivityParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/ActivityParamsParser.java deleted file mode 100644 index d6bc364ff97..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ActivityParamsParser.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.ActivityParams; -import com.reactnativenavigation.params.AppStyle; -import com.reactnativenavigation.params.SideMenuParams; -import com.reactnativenavigation.views.SideMenu; - -public class ActivityParamsParser extends Parser { - public static ActivityParams parse(Bundle params) { - ActivityParams result = new ActivityParams(); - - AppStyle.setAppStyle(params); - - if (hasKey(params, "screen")) { - result.type = ActivityParams.Type.SingleScreen; - result.screenParams = ScreenParamsParser.parse(params.getBundle("screen")); - } - - if (hasKey(params, "tabs")) { - result.type = ActivityParams.Type.TabBased; - result.tabParams = new ScreenParamsParser().parseTabs(params.getBundle("tabs")); - if (result.tabParams.size() == 0) { - throw new RuntimeException("Tried to start tab based app with zero tabs"); - } - } - - if (hasKey(params, "sideMenu")) { - SideMenuParams[] sideMenus = SideMenuParamsParser.parse(params.getBundle("sideMenu")); - result.leftSideMenuParams = sideMenus[SideMenu.Side.Left.ordinal()]; - result.rightSideMenuParams = sideMenus[SideMenu.Side.Right.ordinal()]; - } - - result.animateShow = params.getBoolean("animateShow", true); - - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/AnimationParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/AnimationParser.java deleted file mode 100644 index 9b2ab4972ed..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/AnimationParser.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -class AnimationParser extends Parser { - private Bundle params; - - AnimationParser(Bundle params) { - this.params = params; - } - - public boolean parse() { - if (params.isEmpty()) { - return true; - } - final String animationType = params.getString("animationType", "slide-up"); - return !animationType.equals("none") && params.getBoolean("animated", true); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ButtonParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/ButtonParser.java deleted file mode 100644 index 8a84a338dbd..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ButtonParser.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; - -import java.util.List; - -public class ButtonParser extends Parser { - private static final String KEY_RIGHT_BUTTONS = "rightButtons"; - private static final String KEY_LEFT_BUTTON = "leftButton"; - private static final String KEY_FAB = "fab"; - private static final String KEY_BACK_BUTTON_HIDDEN = "backButtonHidden"; - - public static List parseRightButton(Bundle params) { - List rightButtons = null; - if (hasKey(params, KEY_RIGHT_BUTTONS)) { - rightButtons = new TitleBarButtonParamsParser().parseButtons(params.getBundle(KEY_RIGHT_BUTTONS)); - } - return rightButtons; - } - - public static TitleBarLeftButtonParams parseLeftButton(Bundle params) { - TitleBarLeftButtonParams leftButton = null; - if (hasKey(params, KEY_LEFT_BUTTON)) { - leftButton = new TitleBarLeftButtonParamsParser().parseSingleButton(params.getBundle(KEY_LEFT_BUTTON)); - - boolean backButtonHidden = params.getBoolean(KEY_BACK_BUTTON_HIDDEN, false); - if (backButtonHidden && leftButton.isBackButton()) { - leftButton = null; - } - } - return leftButton; - } - - public static FabParams parseFab(Bundle params, String navigatorEventId, String screenInstanceId) { - FabParams fabParams = null; - if (hasKey(params, KEY_FAB)) { - fabParams = new FabParamsParser().parse(params.getBundle(KEY_FAB), navigatorEventId, screenInstanceId); - } - return fabParams; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/CollapsingTopBarParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/CollapsingTopBarParamsParser.java deleted file mode 100644 index d5d7ad31401..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/CollapsingTopBarParamsParser.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.CollapsingTopBarParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseBehaviour; -import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseTitleBarBehaviour; -import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseTopBarBehaviour; -import com.reactnativenavigation.views.collapsingToolbar.behaviours.TitleBarHideOnScrollBehaviour; - -class CollapsingTopBarParamsParser extends Parser { - private Bundle params; - private boolean titleBarHideOnScroll; - private boolean drawBelowTopBar; - private final boolean hasReactView; - private final boolean hasBackgroundImage; - - CollapsingTopBarParamsParser(Bundle params, boolean titleBarHideOnScroll, boolean drawBelowTopBar) { - this.params = params; - this.titleBarHideOnScroll = titleBarHideOnScroll; - this.drawBelowTopBar = drawBelowTopBar; - hasReactView = params.containsKey("collapsingToolBarComponent"); - hasBackgroundImage = params.containsKey("collapsingToolBarImage"); - } - - public CollapsingTopBarParams parse() { - if (!validateParams()) { - return null; - } - CollapsingTopBarParams result = new CollapsingTopBarParams(); - result.imageUri = params.getString("collapsingToolBarImage", null); - result.reactViewId = params.getString("collapsingToolBarComponent", null); - result.expendOnTopTabChange = params.getBoolean("expendCollapsingToolBarOnTopTabChange"); - result.scrimColor = getColor(params, "collapsingToolBarCollapsedColor", new StyleParams.Color()); - result.expendedTitleBarColor = getColor(params, "collapsingToolBarExpendedColor", new StyleParams.Color()); - result.showTitleWhenCollapsed = hasReactView; - result.showTitleWhenExpended = params.getBoolean("showTitleWhenExpended", result.expendedTitleBarColor.hasColor()); - result.collapseBehaviour = getCollapseBehaviour(); - return result; - } - - private boolean validateParams() { - return titleBarHideOnScroll || hasImageOrReactView(); - } - - private CollapseBehaviour getCollapseBehaviour() { - if (hasImageOrReactView()) { - return new CollapseTopBarBehaviour(); - } - if (titleBarHideOnScroll && drawBelowTopBar) { - return new CollapseTitleBarBehaviour(); - } - return new TitleBarHideOnScrollBehaviour(); - } - - private boolean hasImageOrReactView() { - return hasBackgroundImage || hasReactView; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuButtonParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuButtonParamsParser.java deleted file mode 100644 index 25a27930661..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuButtonParamsParser.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.ContextualMenuButtonParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.react.ImageLoader; - -import java.util.List; - -public class ContextualMenuButtonParamsParser extends TitleBarButtonParamsParser { - public List parseContextualMenuButtons(Bundle params) { - return parseBundle(params, new ParseStrategy() { - @Override - public ContextualMenuButtonParams parse(Bundle button) { - return parseSingleContextualMenuButton(button); - } - }); - } - - private ContextualMenuButtonParams parseSingleContextualMenuButton(Bundle button) { - ContextualMenuButtonParams result = new ContextualMenuButtonParams(); - if (button.get("icon") != null) { - result.icon = ImageLoader.loadImage(button.getString("icon")); - } - result.showAsAction = parseShowAsAction(button.getString("showAsAction")); - result.color = StyleParams.Color.parse(button, "color"); - result.label = button.getString("label"); - result.index = button.getInt("index"); - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuParamsParser.java deleted file mode 100644 index 47bc85b5167..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ContextualMenuParamsParser.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.NavigationParams; - -public class ContextualMenuParamsParser extends Parser { - public ContextualMenuParams parse(Bundle bundle) { - ContextualMenuParams result = new ContextualMenuParams(); - result.buttons = new ContextualMenuButtonParamsParser().parseContextualMenuButtons(bundle.getBundle("buttons")); - result.leftButton = new TitleBarLeftButtonParamsParser().parseSingleButton(bundle.getBundle("backButton")); - result.navigationParams = new NavigationParams(bundle.getBundle("navigationParams")); - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/FabActionParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/FabActionParamsParser.java deleted file mode 100644 index cbad0b45ed0..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/FabActionParamsParser.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.FabActionParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.react.ImageLoader; -import com.reactnativenavigation.utils.ViewUtils; - -public class FabActionParamsParser extends Parser { - public FabActionParams parse(Bundle params, String navigatorEventId) { - FabActionParams fabActionParams = new FabActionParams(); - fabActionParams.id = params.getString("id"); - fabActionParams.navigatorEventId = navigatorEventId; - fabActionParams.icon = ImageLoader.loadImage(params.getString("icon")); - fabActionParams.backgroundColor = StyleParams.Color.parse(params, "backgroundColor"); - fabActionParams.iconColor = StyleParams.Color.parse(params, "iconColor"); - if (fabActionParams.iconColor.hasColor()) { - ViewUtils.tintDrawable(fabActionParams.icon, fabActionParams.iconColor.getColor(), true); - } - return fabActionParams; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/FabParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/FabParamsParser.java deleted file mode 100644 index 4e6352d0cfd..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/FabParamsParser.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.graphics.drawable.Drawable; -import android.os.Bundle; - -import com.reactnativenavigation.params.FabActionParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.react.ImageLoader; -import com.reactnativenavigation.utils.ViewUtils; - -public class FabParamsParser extends Parser { - public FabParams parse(Bundle params, final String navigatorEventId, String screenInstanceId) { - FabParams fabParams = new FabParams(); - fabParams.collapsedId = params.getString("collapsedId"); - fabParams.expendedId = params.getString("expendedId"); - fabParams.collapsedIconColor = getColor(params, "collapsedIconColor", new StyleParams.Color()); - fabParams.expendedIconColor = getColor(params, "expendedIconColor", new StyleParams.Color()); - fabParams.navigatorEventId = navigatorEventId; - fabParams.screenInstanceId = screenInstanceId; - fabParams.backgroundColor = getColor(params, "backgroundColor", new StyleParams.Color()); - - if (hasKey(params, "collapsedIcon")) { - fabParams.collapsedIcon = ImageLoader.loadImage(params.getString("collapsedIcon")); - tintIcon(fabParams.collapsedIcon, fabParams.collapsedIconColor); - } - if (hasKey(params, "expendedIcon")) { - fabParams.expendedIcon = ImageLoader.loadImage(params.getString("expendedIcon")); - tintIcon(fabParams.expendedIcon, fabParams.expendedIconColor); - } - if (hasKey(params, "actions")) { - fabParams.actions = parseBundle(params.getBundle("actions"), new ParseStrategy() { - @Override - public FabActionParams parse(Bundle params) { - return new FabActionParamsParser().parse(params, navigatorEventId); - } - }); - } - return fabParams; - } - - private void tintIcon(Drawable icon, StyleParams.Color color) { - if (color.hasColor()) { - ViewUtils.tintDrawable(icon, color.getColor(), true); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/InterpolationParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/InterpolationParser.java deleted file mode 100644 index 6a9d0aee887..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/InterpolationParser.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.InterpolationParams; -import com.reactnativenavigation.params.LinearInterpolationParams; -import com.reactnativenavigation.params.PathInterpolationParams; -import com.reactnativenavigation.views.sharedElementTransition.ControlPoint; - -class InterpolationParser extends Parser { - private Bundle params; - - private static final float[] defaultShowControlPoints = new float[]{0.5f, 1, 0, 0.5f}; - private static final float[] defaultHideControlPoints = new float[]{0.5f, 0, 1, 0.5f}; - - InterpolationParser(Bundle params) { - this.params = params; - } - - InterpolationParams parseShowInterpolation() { - if (params.isEmpty()) { - return new LinearInterpolationParams(); - } - return parse(params, defaultShowControlPoints); - } - - InterpolationParams parseHideInterpolation() { - if (params.isEmpty()) { - return new LinearInterpolationParams(); - } - return parse(params, defaultHideControlPoints); - } - - private InterpolationParams parse(Bundle params, float[] defaultControlPoints) { - InterpolationParams.Type type = InterpolationParams.Type.fromString(params.getString("type")); - InterpolationParams result = InterpolationParams.Type.Path.equals(type) ? - parsePathInterpolation(params, defaultControlPoints) : - new LinearInterpolationParams(); - result.easing = InterpolationParams.Easing.fromString(params.getString("easing")); - return result; - } - - private InterpolationParams parsePathInterpolation(Bundle params, float[] defaultValues) { - PathInterpolationParams result = new PathInterpolationParams(); - result.p1 = new ControlPoint( - Float.valueOf(params.getString("controlX1")), defaultValues[0], - Float.valueOf(params.getString("controlY1")), defaultValues[1]); - result.p2 = new ControlPoint( - Float.valueOf(params.getString("controlX2")), defaultValues[2], - Float.valueOf(params.getString("controlY2")), defaultValues[3] - ); - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/LightBoxParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/LightBoxParamsParser.java deleted file mode 100644 index 907a0b59a1c..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/LightBoxParamsParser.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; -import android.view.WindowManager; - -import com.reactnativenavigation.params.LightBoxParams; -import com.reactnativenavigation.params.NavigationParams; - -public class LightBoxParamsParser extends Parser { - private Bundle params; - - public LightBoxParamsParser(Bundle params) { - this.params = params; - } - - public LightBoxParams parse() { - LightBoxParams result = new LightBoxParams(); - if (params.isEmpty()) { - return result; - } - result.screenId = params.getString("screenId"); - result.navigationParams = new NavigationParams(params.getBundle("navigationParams")); - result.backgroundColor = getColor(params, "backgroundColor"); - result.tapBackgroundToDismiss = params.getBoolean("tapBackgroundToDismiss"); - result.overrideBackPress = params.getBoolean("overrideBackPress"); - result.adjustSoftInput = Adjustment.fromString(params.getString("adjustSoftInput")).value; - return result; - } - - public enum Adjustment { - NOTHING("nothing", WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING), - PAN("pan", WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN), - RESIZE("resize", WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE), - UNSPECIFIED("unspecified", WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED); - - private String name; - private int value; - - Adjustment(String name, int value) { - this.name = name; - this.value = value; - } - - @Override - public String toString() { - return name; - } - - public static Adjustment fromString(String name) { - for (Adjustment adjustment : values()) { - if (adjustment.name.equals(name)) { - return adjustment; - } - } - return UNSPECIFIED; - } - - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ModalAnimationFactory.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/ModalAnimationFactory.java deleted file mode 100644 index 413f39d6287..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ModalAnimationFactory.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import com.reactnativenavigation.R; -import com.reactnativenavigation.params.ScreenParams; - -public class ModalAnimationFactory { - public static int create(ScreenParams params) { - if (!params.animateScreenTransitions) return R.style.ModalNoAnimation; - switch (params.animationType) { - case "fade": - return R.style.ModalFadeAnimation; - case "slide-horizontal": - return R.style.ModalSlideHorizontal; - case "screen": - return R.style.ModalScreenAnimations; - default: - return R.style.ModalDefaultAnimations; - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/Parser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/Parser.java deleted file mode 100644 index 6ff775889c5..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/Parser.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.StyleParams; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class Parser { - static boolean hasKey(Bundle bundle, String key) { - return bundle.keySet().contains(key); - } - - static void assertKeyExists(Bundle bundle, String key) { - if (!hasKey(bundle, key)) { - throw new KeyDoesNotExistsException(key); - } - } - - private static class KeyDoesNotExistsException extends RuntimeException { - KeyDoesNotExistsException(String key) { - super(key); - } - } - - interface ParseStrategy { - T parse(Bundle params); - } - - List parseBundle(Bundle params, ParseStrategy strategy) { - ArrayList result = new ArrayList<>(Collections.nCopies(params.keySet().size(), (T) null)); - for (String key : params.keySet()) { - result.set(Integer.parseInt(key), strategy.parse(params.getBundle(key))); - } - return result; - } - - protected StyleParams.Color getColor(Bundle params, String backgroundColor) { - return getColor(params, backgroundColor, null); - } - - protected StyleParams.Color getColor(Bundle bundle, String key, StyleParams.Color defaultColor) { - StyleParams.Color color = StyleParams.Color.parse(bundle, key); - return color.hasColor() || defaultColor == null ? color : defaultColor; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ScreenParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/ScreenParamsParser.java deleted file mode 100644 index 8620741fcea..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/ScreenParamsParser.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.graphics.drawable.Drawable; -import android.os.Bundle; - -import com.reactnativenavigation.params.AppStyle; -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.params.PageParams; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.react.ImageLoader; - -import java.util.ArrayList; -import java.util.List; - -public class ScreenParamsParser extends Parser { - private static final String KEY_TITLE = "title"; - private static final String KEY_SUBTITLE = "subtitle"; - private static final String KEY_SCREEN_ID = "screenId"; - private static final String KEY_TIMESTAMP = "timestamp"; - private static final String KEY_NAVIGATION_PARAMS = "navigationParams"; - private static final String STYLE_PARAMS = "styleParams"; - private static final String TOP_TABS = "topTabs"; - private static final String FRAGMENT_CREATOR_CLASS_NAME = "fragmentCreatorClassName"; - private static final String FRAGMENT_CREATOR_PASS_PROPS = "fragmentCreatorPassProps"; - private static final String OVERRIDE_BACK_PRESS = "overrideBackPress"; - private static final String ANIMATION_TYPE = "animationType"; - - @SuppressWarnings("ConstantConditions") - public static ScreenParams parse(Bundle params) { - ScreenParams result = new ScreenParams(); - result.screenId = params.getString(KEY_SCREEN_ID); - result.timestamp = params.getDouble(KEY_TIMESTAMP); - assertKeyExists(params, KEY_NAVIGATION_PARAMS); - result.navigationParams = new NavigationParams(params.getBundle(KEY_NAVIGATION_PARAMS)); - - result.styleParams = new StyleParamsParser(params.getBundle(STYLE_PARAMS)).parse(); - - result.title = params.getString(KEY_TITLE); - result.subtitle = params.getString(KEY_SUBTITLE); - result.rightButtons = ButtonParser.parseRightButton(params); - result.overrideBackPressInJs = params.getBoolean(OVERRIDE_BACK_PRESS, false); - result.leftButton = ButtonParser.parseLeftButton(params); - - result.topTabParams = parseTopTabs(params); - - if (hasKey(params, FRAGMENT_CREATOR_CLASS_NAME)) { - result.fragmentCreatorClassName = params.getString(FRAGMENT_CREATOR_CLASS_NAME); - result.fragmentCreatorPassProps = params.getBundle(FRAGMENT_CREATOR_PASS_PROPS); - } - - result.fabParams = ButtonParser.parseFab(params, result.navigationParams.navigatorEventId, result.navigationParams.screenInstanceId); - - result.tabLabel = getTabLabel(params); - result.tabIcon = new TabIconParser(params).parse(); - - result.animateScreenTransitions = new AnimationParser(params).parse(); - result.sharedElementsTransitions = getSharedElementsTransitions(params); - - result.animationType = params.getString(ANIMATION_TYPE, AppStyle.appStyle.screenAnimationType); - - return result; - } - - private static List getSharedElementsTransitions(Bundle params) { - Bundle sharedElements = params.getBundle("sharedElements"); - if (sharedElements == null) { - return new ArrayList<>(); - } - List result = new ArrayList<>(); - for (String key : sharedElements.keySet()) { - result.add(sharedElements.getString(key)); - } - return result; - } - - private static Drawable getTabIcon(Bundle params) { - Drawable tabIcon = null; - if (hasKey(params, "icon")) { - tabIcon = ImageLoader.loadImage(params.getString("icon")); - } - return tabIcon; - } - - private static String getTabLabel(Bundle params) { - String tabLabel = null; - if (hasKey(params, "label")) { - tabLabel = params.getString("label"); - } - return tabLabel; - } - - private static List parseTopTabs(Bundle params) { - List topTabParams = null; - if (hasKey(params, TOP_TABS)) { - topTabParams = new TopTabParamsParser().parse(params.getBundle(TOP_TABS)); - } - return topTabParams; - } - - List parseTabs(Bundle params) { - return parseBundle(params, new ParseStrategy() { - @Override - public ScreenParams parse(Bundle screen) { - return ScreenParamsParser.parse(screen); - } - }); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SharedElementParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/SharedElementParamsParser.java deleted file mode 100644 index 8474c579db2..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SharedElementParamsParser.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.facebook.react.bridge.ReadableMap; -import com.reactnativenavigation.bridge.BundleConverter; - -public class SharedElementParamsParser { - private static final int DEFAULT_DURATION = 300; - - private int showDuration = DEFAULT_DURATION; - private int hideDuration = DEFAULT_DURATION; - private Bundle showInterpolation = Bundle.EMPTY; - private Bundle hideInterpolation = Bundle.EMPTY; - public boolean animateClipBounds; - - public void setDuration(int duration) { - showDuration = duration; - hideDuration = duration; - } - - public void setShowDuration(int duration) { - showDuration = duration; - } - - public void setHideDuration(int duration) { - hideDuration = duration; - } - - public void setShowInterpolation(ReadableMap showInterpolation) { - this.showInterpolation = BundleConverter.toBundle(showInterpolation); - } - - public void setHideInterpolation(ReadableMap hideInterpolation) { - this.hideInterpolation = BundleConverter.toBundle(hideInterpolation); - } - - public SharedElementTransitionParams parseShowTransitionParams() { - SharedElementTransitionParams result = new SharedElementTransitionParams(); - result.duration = showDuration; - result.interpolation = new InterpolationParser(showInterpolation).parseShowInterpolation(); - result.animateClipBounds = animateClipBounds; - return result; - } - - public SharedElementTransitionParams parseHideTransitionParams() { - SharedElementTransitionParams result = new SharedElementTransitionParams(); - result.duration = hideDuration; - result.interpolation = new InterpolationParser(hideInterpolation).parseHideInterpolation(); - result.animateClipBounds = animateClipBounds; - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SharedElementTransitionParams.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/SharedElementTransitionParams.java deleted file mode 100644 index 5c62b4d50e1..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SharedElementTransitionParams.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import com.reactnativenavigation.params.InterpolationParams; - -public class SharedElementTransitionParams { - public InterpolationParams interpolation; - public int duration; - public boolean animateClipBounds; -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SideMenuParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/SideMenuParamsParser.java deleted file mode 100644 index c026323003d..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SideMenuParamsParser.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; -import android.support.annotation.Nullable; - -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.params.SideMenuParams; -import com.reactnativenavigation.views.SideMenu.Side; - -class SideMenuParamsParser extends Parser { - public static SideMenuParams[] parse(Bundle sideMenues) { - SideMenuParams[] result = new SideMenuParams[2]; - result[Side.Left.ordinal()] = parseSideMenu(sideMenues.getBundle("left"), Side.Left); - result[Side.Right.ordinal()] = parseSideMenu(sideMenues.getBundle("right"), Side.Right); - return result; - } - - private static SideMenuParams parseSideMenu(@Nullable Bundle sideMenu, Side side) { - if (sideMenu == null || sideMenu.isEmpty()) { - return null; - } - SideMenuParams result = new SideMenuParams(); - result.screenId = sideMenu.getString("screenId"); - result.navigationParams = new NavigationParams(sideMenu.getBundle("navigationParams")); - result.disableOpenGesture = sideMenu.getBoolean("disableOpenGesture", false); - result.fixedWidth = sideMenu.getInt("fixedWidth", 0); - result.side = side; - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SlidingOverlayParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/SlidingOverlayParamsParser.java deleted file mode 100644 index 44de9c6020c..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SlidingOverlayParamsParser.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.params.SlidingOverlayParams; - -public class SlidingOverlayParamsParser extends Parser { - - public SlidingOverlayParams parse(Bundle bundle) { - final SlidingOverlayParams result = new SlidingOverlayParams(); - result.screenInstanceId = bundle.getString("screen"); - result.navigationParams = new NavigationParams(bundle.getBundle("navigationParams")); - result.autoDismissTimerSec = bundle.containsKey("autoDismissTimerSec") - ? bundle.getInt("autoDismissTimerSec") - : null; - result.position = SlidingOverlayParams.Position.fromString(bundle.getString("position", "top")); - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SnackbarParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/SnackbarParamsParser.java deleted file mode 100644 index 67164062d3b..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/SnackbarParamsParser.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.graphics.Color; -import android.os.Bundle; -import android.support.design.widget.Snackbar; - -import com.reactnativenavigation.params.AppStyle; -import com.reactnativenavigation.params.SnackbarParams; -import com.reactnativenavigation.params.StyleParams; - -public class SnackbarParamsParser extends Parser { - public SnackbarParams parse(Bundle params) { - SnackbarParams result = new SnackbarParams(); - result.text = params.getString("text"); - result.textColor = getColor(params, "textColor", new StyleParams.Color(Color.WHITE)); - result.buttonText = params.getString("actionText"); - result.buttonColor = getColor(params, "actionColor", AppStyle.appStyle.snackbarButtonColor); - result.backgroundColor = getColor(params, "backgroundColor"); - result.duration = getDuration(params.getString("duration", "short")); - result.eventId = params.getString("actionId"); - return result; - } - - private int getDuration(String duration) { - switch (duration) { - case "short": - return Snackbar.LENGTH_SHORT; - case "long": - return Snackbar.LENGTH_LONG; - case "indefinite": - return Snackbar.LENGTH_INDEFINITE; - default: - return Snackbar.LENGTH_SHORT; - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/StyleParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/StyleParamsParser.java deleted file mode 100644 index 0d295b91245..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/StyleParamsParser.java +++ /dev/null @@ -1,362 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.graphics.Color; -import android.os.Bundle; - -import com.reactnativenavigation.params.AppStyle; -import com.reactnativenavigation.params.Orientation; -import com.reactnativenavigation.params.StatusBarTextColorScheme; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.utils.ViewUtils; - -public class StyleParamsParser { - private Bundle params; - - public StyleParamsParser(Bundle params) { - this.params = params; - } - - public StyleParamsParser merge(Bundle b) { - params.putAll(b); - return this; - } - - public StyleParams parse() { - if (params == null) { - return createDefaultStyleParams(); - } - - StyleParams result = new StyleParams(params); - result.orientation = Orientation.fromString(params.getString("orientation", getDefaultOrientation())); - result.screenAnimationType = params.getString("screenAnimationType", getDefaultScreenAnimationType()); - result.statusBarColor = getColor("statusBarColor", getDefaultStatusBarColor()); - result.statusBarHidden = getBoolean("statusBarHidden", getDefaultStatusHidden()); - result.statusBarTextColorScheme = StatusBarTextColorScheme.fromString(params.getString("statusBarTextColorScheme"), getDefaultStatusBarTextColorScheme()); - result.drawUnderStatusBar = params.getBoolean("drawUnderStatusBar", getDefaultDrawUnderStatusBar()); - result.contextualMenuStatusBarColor = getColor("contextualMenuStatusBarColor", getDefaultContextualMenuStatusBarColor()); - result.contextualMenuButtonsColor = getColor("contextualMenuButtonsColor", getDefaultContextualMenuButtonsColor()); - result.contextualMenuBackgroundColor = getColor("contextualMenuBackgroundColor", getDefaultContextualMenuBackgroundColor()); - - result.topBarColor = getColor("topBarColor", getDefaultTopBarColor()); - result.topBarReactView = params.getString("topBarReactView"); - result.topBarReactViewAlignment = params.getString("topBarReactViewAlignment"); - result.topBarReactViewInitialProps = getBundle("topBarReactViewInitialProps"); - result.titleBarHideOnScroll = getBoolean("titleBarHideOnScroll", getDefaultTitleBarHideOnScroll()); - result.topBarTransparent = getBoolean("topBarTransparent", getDefaultTopBarHidden()); - result.topBarCollapseOnScroll = getBoolean("topBarCollapseOnScroll", false); - result.drawScreenBelowTopBar = params.getBoolean("drawBelowTopBar", getDefaultScreenBelowTopBar()); - if (result.topBarTransparent) { - result.drawScreenBelowTopBar = false; - } - result.collapsingTopBarParams = new CollapsingTopBarParamsParser(params, result.titleBarHideOnScroll, result.drawScreenBelowTopBar).parse(); - result.titleBarHidden = getBoolean("titleBarHidden", getDefaultTopBarHidden()); - result.topBarElevationShadowEnabled = getBoolean("topBarElevationShadowEnabled", getDefaultTopBarElevationShadowEnabled()); - result.titleBarTitleColor = getColor("titleBarTitleColor", getDefaultTitleBarColor()); - result.topBarTranslucent = getBoolean("topBarTranslucent", getDefaultTopBarTranslucent()); - result.topBarBorderColor = getColor("topBarBorderColor", getDefaultTopBarBorderColor()); - result.topBarBorderWidth = Float.parseFloat(params.getString("topBarBorderWidth", getDefaultTopBarBorderWidth())); - - result.titleBarSubtitleColor = getColor("titleBarSubtitleColor", getDefaultSubtitleBarColor()); - result.titleBarSubtitleFontSize = getInt("titleBarSubtitleFontSize", getDefaultSubtitleTextFontSize()); - result.titleBarSubtitleFontFamily = getFont("titleBarSubtitleFontFamily", getDefaultSubtitleFontFamily()); - result.titleBarButtonColor = getColor("titleBarButtonColor", getTitleBarButtonColor()); - result.titleBarButtonFontFamily = getFont("titleBarButtonFontFamily", getDefaultTitleBarButtonFont()); - result.titleBarDisabledButtonColor = getColor("titleBarDisabledButtonColor", getTitleBarDisabledButtonColor()); - result.titleBarTitleFont = getFont("titleBarTitleFontFamily", getDefaultTitleTextFontFamily()); - result.titleBarTitleFontSize = getInt("titleBarTitleFontSize", getDefaultTitleTextFontSize()); - result.titleBarTitleFontBold = getBoolean("titleBarTitleFontBold", getDefaultTitleTextFontBold()); - result.titleBarTitleTextCentered = getBoolean("titleBarTitleTextCentered", getDefaultTitleBarTextCentered()); - result.titleBarHeight = getInt("titleBarHeight", getDefaultTitleBarHeight()); - result.backButtonHidden = getBoolean("backButtonHidden", getDefaultBackButtonHidden()); - result.topTabsHidden = getBoolean("topTabsHidden", getDefaultTopTabsHidden()); - result.titleBarTopPadding = getInt("titleBarTopPadding", getTitleBarTopPadding()); - - result.topTabTextColor = getColor("topTabTextColor", getDefaultTopTabTextColor()); - result.topTabTextFontFamily = getFont("topTabTextFontFamily", getDefaultTopTabTextFontFamily()); - result.topTabIconColor = getColor("topTabIconColor", getDefaultTopTabIconColor()); - result.selectedTopTabIconColor = getColor("selectedTopTabIconColor", getDefaultSelectedTopTabIconColor()); - result.selectedTopTabTextColor = getColor("selectedTopTabTextColor", getDefaultSelectedTopTabTextColor()); - result.selectedTopTabIndicatorHeight = getInt("selectedTopTabIndicatorHeight", getDefaultSelectedTopTabIndicatorHeight()); - result.selectedTopTabIndicatorColor = getColor("selectedTopTabIndicatorColor", getDefaultSelectedTopTabIndicatorColor()); - result.topTabsScrollable = getBoolean("topTabsScrollable", getDefaultTopTabsScrollable()); - result.topTabsHeight = getInt("topTabsHeight", getDefaultTopTabsHeight()); - - result.screenBackgroundColor = getColor("screenBackgroundColor", getDefaultScreenBackgroundColor()); - - result.bottomTabsInitialIndex = getInt("initialTabIndex", 0); - result.bottomTabsHidden = getBoolean("bottomTabsHidden", getDefaultBottomTabsHidden()); - result.drawScreenAboveBottomTabs = !result.bottomTabsHidden && - params.getBoolean("drawScreenAboveBottomTabs", getDefaultDrawScreenAboveBottomTabs()); - if (result.titleBarHideOnScroll) { - result.drawScreenAboveBottomTabs = false; - } - result.bottomTabsHiddenOnScroll = getBoolean("bottomTabsHiddenOnScroll", getDefaultBottomTabsHiddenOnScroll()); - result.bottomTabsColor = getColor("bottomTabsColor", getDefaultBottomTabsColor()); - result.bottomTabsButtonColor = getColor("bottomTabsButtonColor", getDefaultBottomTabsButtonColor()); - result.selectedBottomTabsButtonColor = getColor("bottomTabsSelectedButtonColor", getDefaultSelectedBottomTabsButtonColor()); - result.bottomTabBadgeTextColor = getColor("bottomTabBadgeTextColor", getBottomTabBadgeTextColor()); - result.bottomTabBadgeBackgroundColor = getColor("bottomTabBadgeBackgroundColor", getBottomTabBadgeBackgroundColor()); - - result.navigationBarColor = getColor("navigationBarColor", getDefaultNavigationColor()); - result.forceTitlesDisplay = getBoolean("forceTitlesDisplay", getDefaultForceTitlesDisplay()); - - result.bottomTabFontFamily = getFont("bottomTabFontFamily", getDefaultBottomTabsFontFamily()); - - return result; - } - - private String getDefaultScreenAnimationType() { - return AppStyle.appStyle == null ? "slide-up" : AppStyle.appStyle.screenAnimationType; - } - - private StatusBarTextColorScheme getDefaultStatusBarTextColorScheme() { - return AppStyle.appStyle == null ? StatusBarTextColorScheme.Undefined : AppStyle.appStyle.statusBarTextColorScheme; - } - - private String getDefaultOrientation() { - return AppStyle.appStyle == null ? null : AppStyle.appStyle.orientation.name; - } - - private StyleParams createDefaultStyleParams() { - StyleParams result = new StyleParams(Bundle.EMPTY); - result.titleBarDisabledButtonColor = getTitleBarDisabledButtonColor(); - result.topBarElevationShadowEnabled = true; - result.titleBarHideOnScroll = false; - result.orientation = Orientation.auto; - result.bottomTabFontFamily = new StyleParams.Font(); - result.titleBarTitleFont = new StyleParams.Font(); - result.titleBarSubtitleFontFamily = new StyleParams.Font(); - result.titleBarButtonFontFamily = new StyleParams.Font(); - result.topTabTextFontFamily = new StyleParams.Font(); - result.titleBarHeight = -1; - result.screenAnimationType = "slide-up"; - result.drawUnderStatusBar = false; - return result; - } - - private StyleParams.Color getDefaultContextualMenuStatusBarColor() { - return new StyleParams.Color(Color.parseColor("#7c7c7c")); - } - - private StyleParams.Color getDefaultContextualMenuBackgroundColor() { - return new StyleParams.Color(Color.WHITE); - } - - private StyleParams.Color getDefaultContextualMenuButtonsColor() { - return new StyleParams.Color(Color.parseColor("#757575")); - } - - private boolean getDefaultDrawScreenAboveBottomTabs() { - return AppStyle.appStyle == null || AppStyle.appStyle.drawScreenAboveBottomTabs; - } - - private StyleParams.Color getDefaultSelectedTopTabIndicatorColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.selectedTopTabIndicatorColor; - } - - private int getDefaultSelectedTopTabIndicatorHeight() { - return AppStyle.appStyle == null ? -1 : AppStyle.appStyle.selectedTopTabIndicatorHeight; - } - - private StyleParams.Color getDefaultSelectedTopTabTextColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.selectedTopTabTextColor; - } - - private StyleParams.Color getDefaultSelectedTopTabIconColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.selectedTopTabIconColor; - } - - private StyleParams.Color getDefaultNavigationColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.navigationBarColor; - } - - private boolean getDefaultForceTitlesDisplay() { - return AppStyle.appStyle != null && AppStyle.appStyle.forceTitlesDisplay; - } - - private StyleParams.Color getDefaultSelectedBottomTabsButtonColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.selectedBottomTabsButtonColor; - } - - private StyleParams.Color getBottomTabBadgeTextColor() { - return new StyleParams.Color(); - } - - private StyleParams.Color getBottomTabBadgeBackgroundColor() { - return new StyleParams.Color(); - } - - private StyleParams.Color getDefaultBottomTabsButtonColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.bottomTabsButtonColor; - } - - private StyleParams.Color getDefaultBottomTabsColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.bottomTabsColor; - } - - private boolean getDefaultBottomTabsHiddenOnScroll() { - return AppStyle.appStyle != null && AppStyle.appStyle.bottomTabsHiddenOnScroll; - } - - private boolean getDefaultBottomTabsHidden() { - return AppStyle.appStyle != null && AppStyle.appStyle.bottomTabsHidden; - } - - private boolean getDefaultScreenBelowTopBar() { - return AppStyle.appStyle != null && AppStyle.appStyle.drawScreenBelowTopBar; - } - - private StyleParams.Color getDefaultScreenBackgroundColor() { - return AppStyle.appStyle != null ? AppStyle.appStyle.screenBackgroundColor : getColor("screenBackgroundColor", new StyleParams.Color()); - } - - private boolean getDefaultTopTabsHidden() { - return AppStyle.appStyle != null && AppStyle.appStyle.topTabsHidden; - } - - private StyleParams.Color getDefaultTopTabTextColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.topTabTextColor; - } - - private boolean getDefaultTopTabsScrollable() { - return AppStyle.appStyle != null && AppStyle.appStyle.topTabsScrollable; - } - - private int getDefaultTopTabsHeight() { - return AppStyle.appStyle == null ? -1 : AppStyle.appStyle.topTabsHeight; - } - - private StyleParams.Color getDefaultTopTabIconColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.topTabIconColor; - } - - private boolean getDefaultBackButtonHidden() { - return AppStyle.appStyle != null && AppStyle.appStyle.backButtonHidden; - } - - private StyleParams.Color getDefaultTitleBarColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.titleBarTitleColor; - } - - private StyleParams.Color getDefaultSubtitleBarColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.titleBarSubtitleColor; - } - - private StyleParams.Color getTitleBarButtonColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.titleBarButtonColor; - } - - private StyleParams.Color getTitleBarDisabledButtonColor() { - return AppStyle.appStyle == null ? new StyleParams.Color(Color.LTGRAY) : AppStyle.appStyle.titleBarDisabledButtonColor; - } - - private boolean getDefaultTopBarHidden() { - return AppStyle.appStyle != null && AppStyle.appStyle.topBarTransparent; - } - - private boolean getDefaultTopBarElevationShadowEnabled() { - return AppStyle.appStyle == null || AppStyle.appStyle.topBarElevationShadowEnabled; - } - - private boolean getDefaultTopBarTranslucent() { - return AppStyle.appStyle != null && AppStyle.appStyle.topBarTranslucent; - } - - private StyleParams.Color getDefaultTopBarBorderColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.topBarBorderColor; - } - - private String getDefaultTopBarBorderWidth() { - return String.valueOf(AppStyle.appStyle == null ? ViewUtils.convertDpToPixel(1) : AppStyle.appStyle.topBarBorderWidth); - } - - private boolean getDefaultTitleBarHideOnScroll() { - return AppStyle.appStyle != null && AppStyle.appStyle.titleBarHideOnScroll; - } - - private StyleParams.Color getDefaultTopBarColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.topBarColor; - } - - private StyleParams.Color getDefaultStatusBarColor() { - return AppStyle.appStyle == null ? new StyleParams.Color() : AppStyle.appStyle.statusBarColor; - } - - private boolean getDefaultStatusHidden() { - return AppStyle.appStyle != null && AppStyle.appStyle.statusBarHidden; - } - - private boolean getDefaultDrawUnderStatusBar() { - return AppStyle.appStyle != null && AppStyle.appStyle.drawUnderStatusBar; - } - - private StyleParams.Font getDefaultBottomTabsFontFamily() { - return AppStyle.appStyle == null ? new StyleParams.Font() : AppStyle.appStyle.bottomTabFontFamily; - } - - private StyleParams.Font getDefaultTitleTextFontFamily() { - return AppStyle.appStyle == null ? new StyleParams.Font() : AppStyle.appStyle.titleBarTitleFont; - } - - private int getDefaultTitleTextFontSize() { - return AppStyle.appStyle == null ? -1 : AppStyle.appStyle.titleBarTitleFontSize; - } - - private int getDefaultSubtitleTextFontSize() { - return AppStyle.appStyle == null ? -1 : AppStyle.appStyle.titleBarSubtitleFontSize; - } - - private StyleParams.Font getDefaultSubtitleFontFamily() { - return AppStyle.appStyle == null ? new StyleParams.Font() : AppStyle.appStyle.titleBarSubtitleFontFamily; - } - - private StyleParams.Font getDefaultTopTabTextFontFamily() { - return AppStyle.appStyle == null ? new StyleParams.Font() : AppStyle.appStyle.topTabTextFontFamily; - } - - private StyleParams.Font getDefaultTitleBarButtonFont() { - return AppStyle.appStyle == null ? new StyleParams.Font() : AppStyle.appStyle.titleBarButtonFontFamily; - } - - private boolean getDefaultTitleTextFontBold() { - return AppStyle.appStyle != null && AppStyle.appStyle.titleBarTitleFontBold; - } - - private boolean getDefaultTitleBarTextCentered() { - return AppStyle.appStyle != null && AppStyle.appStyle.titleBarTitleTextCentered; - } - - private int getDefaultTitleBarHeight() { - return AppStyle.appStyle == null ? -1 : AppStyle.appStyle.titleBarHeight; - } - - private int getTitleBarTopPadding() { - return AppStyle.appStyle == null ? 0 : AppStyle.appStyle.titleBarTopPadding; - } - - private boolean getBoolean(String key, boolean defaultValue) { - return params.containsKey(key) ? params.getBoolean(key) : defaultValue; - } - - private StyleParams.Color getColor(String key, StyleParams.Color defaultColor) { - StyleParams.Color color = StyleParams.Color.parse(params, key); - if (color.hasColor()) { - return color; - } else { - return defaultColor != null && defaultColor.hasColor() ? defaultColor : color; - } - } - - private StyleParams.Font getFont(String titleBarTitleFontFamily, StyleParams.Font defaultFont) { - StyleParams.Font font = new StyleParams.Font(params.getString(titleBarTitleFontFamily)); - return font.hasFont() ? font : defaultFont; - } - - private int getInt(String key, int defaultValue) { - return params.containsKey(key) ? params.getInt(key) : defaultValue; - } - - private Bundle getBundle(String key) { - return params.containsKey(key) ? params.getBundle(key) : Bundle.EMPTY; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/TabIconParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/TabIconParser.java deleted file mode 100644 index a1a6949048d..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/TabIconParser.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.graphics.drawable.Drawable; -import android.os.Bundle; - -import com.reactnativenavigation.react.ImageLoader; - -class TabIconParser extends Parser { - - private Bundle params; - - TabIconParser(Bundle params) { - this.params = params; - } - - public Drawable parse() { - Drawable tabIcon = null; - if (hasKey(params, "icon")) { - tabIcon = ImageLoader.loadImage(params.getString("icon")); - } - return tabIcon; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarButtonParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarButtonParamsParser.java deleted file mode 100644 index e99922554ed..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarButtonParamsParser.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.reactnativenavigation.params.AppStyle; -import com.reactnativenavigation.params.BaseTitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.react.ImageLoader; - -import java.util.List; - -public class TitleBarButtonParamsParser extends Parser { - public List parseButtons(Bundle params) { - return parseBundle(params, new ParseStrategy() { - @Override - public TitleBarButtonParams parse(Bundle button) { - return parseSingleButton(button); - } - }); - } - - public TitleBarButtonParams parseSingleButton(Bundle bundle) { - TitleBarButtonParams result = new TitleBarButtonParams(); - result.label = bundle.getString("title"); - if (hasKey(bundle, "icon")) { - result.icon = ImageLoader.loadImage(bundle.getString("icon")); - } - result.color = getColor(bundle, "color", AppStyle.appStyle.titleBarButtonColor); - result.disabledColor = getColor(bundle, "titleBarDisabledButtonColor", AppStyle.appStyle.titleBarDisabledButtonColor); - result.showAsAction = parseShowAsAction(bundle.getString("showAsAction")); - result.enabled = bundle.getBoolean("enabled", true); - result.hint = bundle.getString("hint", ""); - result.eventId = bundle.getString("id"); - result.disableIconTint = bundle.getBoolean("disableIconTint", false); - result.componentName = bundle.getString("component"); - result.componentProps = bundle.getBundle("passProps"); - return result; - } - - BaseTitleBarButtonParams.ShowAsAction parseShowAsAction(String showAsAction) { - if (showAsAction == null) { - return BaseTitleBarButtonParams.ShowAsAction.IfRoom; - } - - switch (showAsAction) { - case "always": - return BaseTitleBarButtonParams.ShowAsAction.Always; - case "never": - return BaseTitleBarButtonParams.ShowAsAction.Never; - case "withText": - return BaseTitleBarButtonParams.ShowAsAction.WithText; - case "ifRoom": - default: - return BaseTitleBarButtonParams.ShowAsAction.IfRoom; - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarLeftButtonParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarLeftButtonParamsParser.java deleted file mode 100644 index ded7fd9e191..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/TitleBarLeftButtonParamsParser.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; - -import com.balysv.materialmenu.MaterialMenuDrawable; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; - -public class TitleBarLeftButtonParamsParser extends TitleBarButtonParamsParser { - - public TitleBarLeftButtonParams parseSingleButton(Bundle params) { - TitleBarLeftButtonParams leftButtonParams = new TitleBarLeftButtonParams(super.parseSingleButton(params)); - if (params.isEmpty()) { - return leftButtonParams; - } - leftButtonParams.iconState = getIconStateFromId(leftButtonParams.eventId); - return leftButtonParams; - } - - private MaterialMenuDrawable.IconState getIconStateFromId(String id) { - switch (id) { - case "back": - return MaterialMenuDrawable.IconState.ARROW; - case "cancel": - return MaterialMenuDrawable.IconState.X; - case "accept": - return MaterialMenuDrawable.IconState.CHECK; - case "sideMenu": - return MaterialMenuDrawable.IconState.BURGER; - default: - return null; - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/params/parsers/TopTabParamsParser.java b/android/app/src/main/java/com/reactnativenavigation/params/parsers/TopTabParamsParser.java deleted file mode 100644 index bafa0afad00..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/params/parsers/TopTabParamsParser.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.reactnativenavigation.params.parsers; - -import android.os.Bundle; -import android.support.annotation.NonNull; - -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.params.PageParams; - -import java.util.List; - -class TopTabParamsParser extends Parser { - private static final String KEY_SCREEN_ID = "screenId"; - private static final String KEY_TITLE = "title"; - private static final String NAVIGATION_PARAMS = "navigationParams"; - - @SuppressWarnings("ConstantConditions") - public List parse(Bundle params) { - return parseBundle(params, new ParseStrategy() { - @Override - public PageParams parse(Bundle topTabs) { - return parseItem(topTabs); - } - }); - } - - @NonNull - private static PageParams parseItem(Bundle params) { - PageParams result = new PageParams(); - result.screenId = params.getString(KEY_SCREEN_ID); - result.title = params.getString(KEY_TITLE); - result.tabIcon = new TabIconParser(params).parse(); - result.navigationParams = new NavigationParams(params.getBundle(NAVIGATION_PARAMS)); - result.leftButton = ButtonParser.parseLeftButton(params); - result.rightButtons = ButtonParser.parseRightButton(params); - result.fabParams = ButtonParser.parseFab(params, result.navigationParams.navigatorEventId, result.navigationParams.screenInstanceId); - result.styleParams = new StyleParamsParser(params.getBundle("styleParams")).parse(); - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/ImageLoader.java b/android/app/src/main/java/com/reactnativenavigation/react/ImageLoader.java deleted file mode 100644 index f4dab28e094..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/ImageLoader.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.reactnativenavigation.react; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.net.Uri; - -import com.reactnativenavigation.NavigationApplication; - -public class ImageLoader { - private static final String FILE_SCHEME = "file"; - - public static Drawable loadImage(String iconSource) { - if (NavigationApplication.instance.isDebug()) { - return JsDevImageLoader.loadIcon(iconSource); - } else { - Uri uri = Uri.parse(iconSource); - if (isLocalFile(uri)) { - return loadFile(uri); - } else { - return loadResource(iconSource); - } - } - } - - private static boolean isLocalFile(Uri uri) { - return FILE_SCHEME.equals(uri.getScheme()); - } - - private static Drawable loadFile(Uri uri) { - Bitmap bitmap = BitmapFactory.decodeFile(uri.getPath()); - return new BitmapDrawable(NavigationApplication.instance.getResources(), bitmap); - } - - private static Drawable loadResource(String iconSource) { - return ResourceDrawableIdHelper.instance.getResourceDrawable(NavigationApplication.instance, iconSource); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/JsDevImageLoader.java b/android/app/src/main/java/com/reactnativenavigation/react/JsDevImageLoader.java deleted file mode 100644 index d64b359e3d6..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/JsDevImageLoader.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.reactnativenavigation.react; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.StrictMode; -import android.support.annotation.NonNull; -import android.util.Log; - -import com.reactnativenavigation.NavigationApplication; - -import java.io.IOException; -import java.net.URL; - -public class JsDevImageLoader { - private static final String TAG = "JsDevImageLoader"; - public static Drawable loadIcon(String iconDevUri) { - try { - StrictMode.ThreadPolicy threadPolicy = StrictMode.getThreadPolicy(); - StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitNetwork().build()); - - Drawable drawable = tryLoadIcon(iconDevUri); - - StrictMode.setThreadPolicy(threadPolicy); - return drawable; - } catch (Exception e) { - Log.e(TAG, "Unable to load icon: " + iconDevUri); - return new BitmapDrawable(); - } - } - - @NonNull - private static Drawable tryLoadIcon(String iconDevUri) throws IOException { - URL url = new URL(iconDevUri); - Bitmap bitmap = BitmapFactory.decodeStream(url.openStream()); - return new BitmapDrawable(NavigationApplication.instance.getResources(), bitmap); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/JsDevReloadHandler.java b/android/app/src/main/java/com/reactnativenavigation/react/JsDevReloadHandler.java deleted file mode 100644 index c99fc1791a0..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/JsDevReloadHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.reactnativenavigation.react; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.view.KeyEvent; -import android.view.View; -import android.widget.EditText; - -import com.facebook.react.ReactInstanceManager; -import com.reactnativenavigation.NavigationApplication; - -class JsDevReloadHandler { - - private static boolean shouldRefreshOnRR = false; - private final BroadcastReceiver reloadReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - reload(); - } - }; - - void onResumeActivity() { - if (getReactInstanceManager().getDevSupportManager().getDevSupportEnabled()) { - NavigationApplication.instance.registerReceiver(reloadReceiver, new IntentFilter("react.native.RELOAD")); - } - } - - void onPauseActivity() { - if (getReactInstanceManager().getDevSupportManager().getDevSupportEnabled()) { - NavigationApplication.instance.unregisterReceiver(reloadReceiver); - } - } - - boolean onKeyUp(View currentFocus, int keyCode) { - ReactInstanceManager reactInstanceManager = getReactInstanceManager(); - - if (reactInstanceManager != null && - reactInstanceManager.getDevSupportManager().getDevSupportEnabled()) { - if (keyCode == KeyEvent.KEYCODE_MENU) { - reactInstanceManager.showDevOptionsDialog(); - return true; - } - if (keyCode == KeyEvent.KEYCODE_R && !(currentFocus instanceof EditText)) { - // Enable double-tap-R-to-reload - if (shouldRefreshOnRR) { - reload(); - return true; - } else { - shouldRefreshOnRR = true; - NavigationApplication.instance.runOnMainThread( - new Runnable() { - @Override - public void run() { - shouldRefreshOnRR = false; - } - }, - 500); - } - } - } - return false; - } - - private void reload() { - getReactInstanceManager().getDevSupportManager().handleReloadJS(); - shouldRefreshOnRR = false; - } - - private ReactInstanceManager getReactInstanceManager() { - return NavigationApplication - .instance - .getReactGateway() - .getReactInstanceManager(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/JsDevReloadListenerReplacer.java b/android/app/src/main/java/com/reactnativenavigation/react/JsDevReloadListenerReplacer.java deleted file mode 100644 index 1f3ae447c92..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/JsDevReloadListenerReplacer.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.reactnativenavigation.react; - -import com.facebook.react.ReactInstanceManager; -import com.reactnativenavigation.utils.ReflectionUtils; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -class JsDevReloadListenerReplacer { - private final ReactInstanceManager reactInstanceManager; - private final Listener listener; - - interface Listener { - void onJsDevReload(); - } - - JsDevReloadListenerReplacer(ReactInstanceManager reactInstanceManager, Listener listener) { - this.reactInstanceManager = reactInstanceManager; - this.listener = listener; - } - - void replace() { - Object originalHelper = getOriginalHelper(); - - Object devSupportManager = ReflectionUtils.getDeclaredField(reactInstanceManager, "mDevSupportManager"); - - Object proxy = Proxy.newProxyInstance( - originalHelper.getClass().getClassLoader(), - originalHelper.getClass().getInterfaces(), - new DevHelperProxy(originalHelper, listener)); - - if (ReflectionUtils.getDeclaredField(reactInstanceManager, "mDevInterface") == null) { // RN >= 0.52 - ReflectionUtils.setField(devSupportManager, "mReactInstanceManagerHelper", proxy); - } else { // RN <= 0.51 - ReflectionUtils.setField(reactInstanceManager, "mDevInterface", proxy); - ReflectionUtils.setField(devSupportManager, "mReactInstanceCommandsHandler", proxy); - } - } - - - private Object getOriginalHelper() { - Object devInterface = ReflectionUtils.getDeclaredField(reactInstanceManager, "mDevInterface"); - - if (devInterface == null) { // RN >= 0.52 - Object devSupportManager = ReflectionUtils.getDeclaredField(reactInstanceManager, "mDevSupportManager"); - return ReflectionUtils.getDeclaredField(devSupportManager, "mReactInstanceManagerHelper"); - } - - return devInterface; // RN <= 0.51 - } - - - private static class DevHelperProxy implements InvocationHandler { - private Object originalReactHelper; - private final Listener listener; - - DevHelperProxy(Object originalReactHelper, Listener listener) { - this.originalReactHelper = originalReactHelper; - this.listener = listener; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - String methodName = method.getName(); - - if (methodName.equals("onJSBundleLoadedFromServer") || methodName.equals("onReloadWithJSDebugger")) { - listener.onJsDevReload(); - } - - return method.invoke(originalReactHelper, args); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/LaunchArgs.java b/android/app/src/main/java/com/reactnativenavigation/react/LaunchArgs.java deleted file mode 100644 index 3f31bc5ec98..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/LaunchArgs.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.reactnativenavigation.react; - -import android.content.*; -import android.os.*; - -public enum LaunchArgs { - instance; - - private static final Bundle EMPTY = new Bundle(); - private Bundle launchArgs; - - public void set(Intent intent) { - if (intent != null && intent.getExtras() != null && launchArgs == null) { - this.launchArgs = intent.getExtras(); - } - } - - public Bundle get() { - return this.launchArgs == null ? EMPTY : this.launchArgs; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/NavigationReactGateway.java b/android/app/src/main/java/com/reactnativenavigation/react/NavigationReactGateway.java deleted file mode 100644 index 2f1886a776b..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/NavigationReactGateway.java +++ /dev/null @@ -1,210 +0,0 @@ -package com.reactnativenavigation.react; - -import android.app.Activity; -import android.content.Intent; -import android.view.View; - -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; -import com.facebook.react.shell.MainReactPackage; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.bridge.NavigationReactEventEmitter; -import com.reactnativenavigation.bridge.NavigationReactPackage; -import com.reactnativenavigation.events.EventBus; -import com.reactnativenavigation.events.JsDevReloadEvent; - -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nullable; - -public class NavigationReactGateway implements ReactGateway { - - private final ReactNativeHost host; - private NavigationReactEventEmitter reactEventEmitter; - private JsDevReloadHandler jsDevReloadHandler; - - public NavigationReactGateway() { - host = new ReactNativeHostImpl(); - jsDevReloadHandler = new JsDevReloadHandler(); - } - - @Override - public void startReactContextOnceInBackgroundAndExecuteJS() { - getReactInstanceManager().createReactContextInBackground(); - } - - public boolean isInitialized() { - return host.hasInstance() && getReactInstanceManager().getCurrentReactContext() != null; - } - - @Override - public boolean hasStartedCreatingContext() { - return getReactInstanceManager().hasStartedCreatingInitialContext(); - } - - public ReactContext getReactContext() { - return getReactInstanceManager().getCurrentReactContext(); - } - - public NavigationReactEventEmitter getReactEventEmitter() { - return reactEventEmitter; - } - - @Override - public ReactInstanceManager getReactInstanceManager() { - return host.getReactInstanceManager(); - } - - public void onBackPressed() { - getReactInstanceManager().onBackPressed(); - } - - public void onDestroyApp(Activity activity) { - if (NavigationApplication.instance.clearHostOnActivityDestroy()) { - getReactInstanceManager().onHostDestroy(); - } else if (hasStartedCreatingContext() && isInitialized()) { - getReactInstanceManager().onHostDestroy(activity); - } - if (NavigationApplication.instance.clearHostOnActivityDestroy()) { - host.clear(); - } - } - - public void onPauseActivity(Activity activity) { - if (NavigationApplication.instance.clearHostOnActivityDestroy()) { - getReactInstanceManager().onHostPause(); - } else if (hasStartedCreatingContext() && isInitialized()) { - getReactInstanceManager().onHostPause(activity); - } - jsDevReloadHandler.onPauseActivity(); - } - - public void onNewIntent(Intent intent) { - getReactInstanceManager().onNewIntent(intent); - } - - @Override - public boolean onKeyUp(View currentFocus, int keyCode) { - return jsDevReloadHandler.onKeyUp(currentFocus, keyCode); - } - - public void onResumeActivity(Activity activity, DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler) { - getReactInstanceManager().onHostResume(activity, defaultHardwareBackBtnHandler); - jsDevReloadHandler.onResumeActivity(); - } - - public void onActivityResult(int requestCode, int resultCode, Intent data) { - ReactContext reactContext = getReactInstanceManager().getCurrentReactContext(); - if (reactContext != null) { - Activity currentActivity = reactContext.getCurrentActivity(); - getReactInstanceManager().onActivityResult(currentActivity, requestCode, resultCode, data); - } - } - - public ReactNativeHost getReactNativeHost() { - return host; - } - - //TODO temp hack - private void onReactContextInitialized() { - reactEventEmitter = new NavigationReactEventEmitter(getReactContext()); - } - - private static class ReactNativeHostImpl extends ReactNativeHost implements ReactInstanceManager.ReactInstanceEventListener { - - ReactNativeHostImpl() { - super(NavigationApplication.instance); - } - - @Override - public boolean getUseDeveloperSupport() { - return NavigationApplication.instance.isDebug(); - } - - @Override - protected List getPackages() { - List result = new ArrayList<>(); - - List additionalReactPackages = NavigationApplication.instance.createAdditionalReactPackages(); - if (additionalReactPackages != null) - result.addAll(additionalReactPackages); - - if (!containsInstanceOfClass(result, MainReactPackage.class)) { - result.add(new MainReactPackage()); - } - if (!containsInstanceOfClass(result, NavigationReactPackage.class)) { - result.add(new NavigationReactPackage()); - } - - return result; - } - - private boolean containsInstanceOfClass(List list, Class packageClass) { - for (ReactPackage reactPackage : list) { - if (packageClass.isInstance(reactPackage)) return true; - } - return false; - } - - @Override - protected ReactInstanceManager createReactInstanceManager() { - ReactInstanceManager manager = super.createReactInstanceManager(); - if (NavigationApplication.instance.isDebug()) { - replaceJsDevReloadListener(manager); - } - manager.addReactInstanceEventListener(this); - return manager; - } - - private void replaceJsDevReloadListener(ReactInstanceManager manager) { - new JsDevReloadListenerReplacer(manager, new JsDevReloadListenerReplacer.Listener() { - @Override - public void onJsDevReload() { - EventBus.instance.post(new JsDevReloadEvent()); - } - }).replace(); - } - - @Override - public void onReactContextInitialized(ReactContext context) { - ((NavigationReactGateway) NavigationApplication.instance.getReactGateway()).onReactContextInitialized(); - NavigationApplication.instance.onReactInitialized(context); - } - - @Override - public void clear() { - getReactInstanceManager().removeReactInstanceEventListener(this); - super.clear(); - } - - @Override - protected String getJSMainModuleName() { - String jsMainModuleName = NavigationApplication.instance.getJSMainModuleName(); - if (jsMainModuleName != null) - return jsMainModuleName; - return super.getJSMainModuleName(); - } - - @Nullable - @Override - protected String getJSBundleFile() { - String jsBundleFile = NavigationApplication.instance.getJSBundleFile(); - if (jsBundleFile != null) - return jsBundleFile; - return super.getJSBundleFile(); - } - - @Nullable - @Override - protected String getBundleAssetName() { - String bundleAssetName = NavigationApplication.instance.getBundleAssetName(); - if (bundleAssetName != null) - return bundleAssetName; - return super.getBundleAssetName(); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/ReactDevPermission.java b/android/app/src/main/java/com/reactnativenavigation/react/ReactDevPermission.java deleted file mode 100644 index b68d0d2579b..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/ReactDevPermission.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.reactnativenavigation.react; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.Intent; -import android.os.Build; -import android.provider.Settings; -import android.util.Log; -import android.widget.Toast; - -import com.facebook.react.common.ReactConstants; -import com.reactnativenavigation.NavigationApplication; - -public class ReactDevPermission { - - public static boolean shouldAskPermission() { - return NavigationApplication.instance.isDebug() && - Build.VERSION.SDK_INT >= 23 && - !Settings.canDrawOverlays(NavigationApplication.instance); - } - - @TargetApi(23) - public static void askPermission(Context context) { - if (shouldAskPermission()) { - Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); - context.startActivity(serviceIntent); - String msg = "Overlay permissions needs to be granted in order for react native apps to run in dev mode"; - Log.w(ReactConstants.TAG, "======================================\n\n"); - Log.w(ReactConstants.TAG, msg); - Log.w(ReactConstants.TAG, "\n\n======================================"); - for (int i = 0; i < 5; i++) { - Toast.makeText(context, msg, Toast.LENGTH_LONG).show(); - } - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/ReactGateway.java b/android/app/src/main/java/com/reactnativenavigation/react/ReactGateway.java deleted file mode 100644 index a9c0b464eb7..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/ReactGateway.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.reactnativenavigation.react; - -import android.app.Activity; -import android.content.Intent; -import android.view.View; - -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; -import com.reactnativenavigation.bridge.NavigationReactEventEmitter; - -public interface ReactGateway { - - void startReactContextOnceInBackgroundAndExecuteJS(); - - boolean isInitialized(); - - ReactContext getReactContext(); - - NavigationReactEventEmitter getReactEventEmitter(); - - ReactInstanceManager getReactInstanceManager(); - - void onResumeActivity(Activity activity, DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler); - - void onPauseActivity(Activity activity); - - void onDestroyApp(Activity activity); - - void onBackPressed(); - - void onActivityResult(int requestCode, int resultCode, Intent data); - - boolean hasStartedCreatingContext(); - - void onNewIntent(Intent intent); - - boolean onKeyUp(View currentFocus, int keyCode); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/ReactViewHacks.java b/android/app/src/main/java/com/reactnativenavigation/react/ReactViewHacks.java deleted file mode 100644 index b3c10593942..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/ReactViewHacks.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.reactnativenavigation.react; - -import com.facebook.react.views.image.ReactImageView; -import com.reactnativenavigation.utils.ReflectionUtils; - -public class ReactViewHacks { - // Hack to prevent Image flicker until https://github.com/facebook/react-native/issues/10194 is fixed - public static void disableReactImageViewRemoteImageFadeInAnimation(ReactImageView reactImageView) { - reactImageView.setFadeDuration(0); - ReflectionUtils.setField(reactImageView, "mIsDirty", true); - reactImageView.maybeUpdateView(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/react/ResourceDrawableIdHelper.java b/android/app/src/main/java/com/reactnativenavigation/react/ResourceDrawableIdHelper.java deleted file mode 100644 index e8435664203..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/react/ResourceDrawableIdHelper.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.reactnativenavigation.react;// Copyright 2004-present Facebook. All Rights Reserved. - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.net.Uri; - -import com.facebook.common.util.UriUtil; - -import java.util.HashMap; -import java.util.Map; - -import javax.annotation.Nullable; - -/** - * Direct copy paste from react-native, because they made that class package scope. -_-" - * Can be deleted in react-native ^0.29 - */ -public class ResourceDrawableIdHelper { - public static final ResourceDrawableIdHelper instance = new ResourceDrawableIdHelper(); - - private Map mResourceDrawableIdMap; - - public ResourceDrawableIdHelper() { - mResourceDrawableIdMap = new HashMap<>(); - } - - public int getResourceDrawableId(Context context, @Nullable String name) { - if (name == null || name.isEmpty()) { - return 0; - } - name = name.toLowerCase().replace("-", "_"); - if (mResourceDrawableIdMap.containsKey(name)) { - return mResourceDrawableIdMap.get(name); - } - int id = context.getResources().getIdentifier( - name, - "drawable", - context.getPackageName()); - mResourceDrawableIdMap.put(name, id); - return id; - } - - @Nullable - public Drawable getResourceDrawable(Context context, @Nullable String name) { - int resId = getResourceDrawableId(context, name); - return resId > 0 ? context.getResources().getDrawable(resId) : null; - } - - public Uri getResourceDrawableUri(Context context, @Nullable String name) { - int resId = getResourceDrawableId(context, name); - return resId > 0 ? new Uri.Builder() - .scheme(UriUtil.LOCAL_RESOURCE_SCHEME) - .path(String.valueOf(resId)) - .build() : Uri.EMPTY; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/CollapsingSingleScreen.java b/android/app/src/main/java/com/reactnativenavigation/screens/CollapsingSingleScreen.java deleted file mode 100644 index 2c853034d73..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/CollapsingSingleScreen.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.support.v7.app.AppCompatActivity; -import android.view.MotionEvent; -import android.widget.ScrollView; - -import com.facebook.react.uimanager.RootViewUtil; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.views.CollapsingContentView; -import com.reactnativenavigation.views.LeftButtonOnClickListener; -import com.reactnativenavigation.views.TopBar; -import com.reactnativenavigation.views.collapsingToolbar.CollapseAmount; -import com.reactnativenavigation.views.collapsingToolbar.CollapseCalculator; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingTopBar; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingView; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingViewMeasurer; -import com.reactnativenavigation.views.collapsingToolbar.OnScrollListener; -import com.reactnativenavigation.views.collapsingToolbar.OnScrollViewAddedListener; -import com.reactnativenavigation.views.collapsingToolbar.ScrollListener; -import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseBehaviour; - -public class CollapsingSingleScreen extends SingleScreen { - - public CollapsingSingleScreen(AppCompatActivity activity, ScreenParams screenParams, LeftButtonOnClickListener titleBarBarBackButtonListener) { - super(activity, screenParams, titleBarBarBackButtonListener); - } - - @Override - public void destroy() { - super.destroy(); - ((CollapsingContentView) contentView).destroy(); - } - - @Override - protected TopBar createTopBar() { - final CollapsingTopBar topBar = new CollapsingTopBar(getContext(), styleParams); - topBar.setScrollListener(getScrollListener(topBar)); - return topBar; - } - - @Override - protected void createContent() { - contentView = new CollapsingContentView(getContext(), screenParams.screenId, screenParams.navigationParams); - setViewMeasurer(); - setupCollapseDetection((CollapsingTopBar) topBar); - post(new Runnable() { - @Override - public void run() { - addView(contentView, createLayoutParams()); - } - }); - } - - private void setViewMeasurer() { - if (screenParams.styleParams.drawScreenBelowTopBar || screenParams.styleParams.drawScreenAboveBottomTabs) { - contentView.setViewMeasurer(new CollapsingViewMeasurer((CollapsingTopBar) topBar, this, screenParams.styleParams)); - } - } - - private void setupCollapseDetection(final CollapsingTopBar topBar) { - ((CollapsingContentView) contentView).setupCollapseDetection(getScrollListener(topBar), new OnScrollViewAddedListener() { - @Override - public void onScrollViewAdded(ScrollView scrollView) { - topBar.onScrollViewAdded(scrollView); - } - }); - } - - private ScrollListener getScrollListener(final CollapsingTopBar topBar) { - return new ScrollListener(new CollapseCalculator(topBar, getCollapseBehaviour()), - new OnScrollListener() { - @Override - public void onScroll(MotionEvent event, CollapseAmount amount) { - if (screenParams.styleParams.drawScreenBelowTopBar) { - RootViewUtil.getRootView(contentView).onChildStartedNativeGesture(event); - ((CollapsingView) contentView).collapse(amount); - } - topBar.collapse(amount); - } - - @Override - public void onFling(CollapseAmount amount) { - if (screenParams.styleParams.drawScreenBelowTopBar) { - ((CollapsingView) contentView).fling(amount); - } - topBar.fling(amount); - } - }, - getCollapseBehaviour() - ); - } - - private CollapseBehaviour getCollapseBehaviour() { - return screenParams.styleParams.collapsingTopBarParams.collapseBehaviour; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/CollapsingViewPagerScreen.java b/android/app/src/main/java/com/reactnativenavigation/screens/CollapsingViewPagerScreen.java deleted file mode 100644 index b795829127e..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/CollapsingViewPagerScreen.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.support.v4.view.ViewPager; -import android.support.v7.app.AppCompatActivity; -import android.view.MotionEvent; -import android.widget.ScrollView; - -import com.facebook.react.uimanager.RootViewUtil; -import com.reactnativenavigation.events.Event; -import com.reactnativenavigation.events.ViewPagerScreenChangedEvent; -import com.reactnativenavigation.events.ViewPagerScreenScrollStartEvent; -import com.reactnativenavigation.params.PageParams; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.views.CollapsingContentView; -import com.reactnativenavigation.views.ContentView; -import com.reactnativenavigation.views.LeftButtonOnClickListener; -import com.reactnativenavigation.views.TopBar; -import com.reactnativenavigation.views.collapsingToolbar.CollapseAmount; -import com.reactnativenavigation.views.collapsingToolbar.CollapseCalculator; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingTopBar; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingView; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingViewMeasurer; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingViewPager; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingViewPagerContentViewMeasurer; -import com.reactnativenavigation.views.collapsingToolbar.OnScrollListener; -import com.reactnativenavigation.views.collapsingToolbar.OnScrollViewAddedListener; -import com.reactnativenavigation.views.collapsingToolbar.ScrollListener; -import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseBehaviour; - -@SuppressLint("ViewConstructor") -public class CollapsingViewPagerScreen extends ViewPagerScreen { - public CollapsingViewPagerScreen(AppCompatActivity activity, ScreenParams screenParams, LeftButtonOnClickListener backButtonListener) { - super(activity, screenParams, backButtonListener); - } - - @Override - protected TopBar createTopBar() { - final CollapsingTopBar topBar = new CollapsingTopBar(getContext(), styleParams); - topBar.setScrollListener(getScrollListener(topBar)); - return topBar; - } - - @Override - protected ViewPager createViewPager(Context context) { - CollapsingViewPager viewPager = new CollapsingViewPager(context); - if (screenParams.styleParams.drawScreenBelowTopBar) { - viewPager.setViewMeasurer(new CollapsingViewMeasurer((CollapsingTopBar) topBar, this, styleParams)); - } - return viewPager; - } - - protected ContentView createContentView(PageParams tab) { - CollapsingContentView contentView = new CollapsingContentView(getContext(), tab.screenId, tab.navigationParams); - contentView.setViewMeasurer(new CollapsingViewPagerContentViewMeasurer((CollapsingTopBar) topBar, this, screenParams.styleParams)); - setupCollapseDetection(contentView); - return contentView; - } - - private void setupCollapseDetection(CollapsingContentView contentView) { - ScrollListener scrollListener = getScrollListener((CollapsingView) topBar); - contentView.setupCollapseDetection(scrollListener, new OnScrollViewAddedListener() { - @Override - public void onScrollViewAdded(ScrollView scrollView) { - ((CollapsingTopBar) topBar).onScrollViewAdded(scrollView); - } - }); - } - - private ScrollListener getScrollListener(final CollapsingView topBar) { - return new ScrollListener(new CollapseCalculator(topBar, getCollapseBehaviour()), - new OnScrollListener() { - @Override - public void onScroll(MotionEvent event, CollapseAmount amount) { - RootViewUtil.getRootView(getCurrentPage()).onChildStartedNativeGesture(event); - topBar.collapse(amount); - ((CollapsingView) viewPager).collapse(amount); - } - - @Override - public void onFling(CollapseAmount amount) { - topBar.fling(amount); - ((CollapsingView) viewPager).fling(amount); - } - }, - getCollapseBehaviour() - ); - } - - private CollapseBehaviour getCollapseBehaviour() { - return screenParams.styleParams.collapsingTopBarParams.collapseBehaviour; - } - - @Override - public void onEvent(Event event) { - super.onEvent(event); - if (ViewPagerScreenScrollStartEvent.TYPE.equals(event.getType()) || ViewPagerScreenChangedEvent.TYPE.equals(event.getType())) { - if (screenParams.styleParams.collapsingTopBarParams.expendOnTopTabChange) { - ((CollapsingView) topBar).collapse(new CollapseAmount(CollapseCalculator.Direction.Down)); - ((CollapsingView) viewPager).collapse(new CollapseAmount(CollapseCalculator.Direction.Down)); - } - } - } - - @Override - public void destroy() { - super.destroy(); - for (ContentView contentView : contentViews) { - if (contentView instanceof CollapsingContentView) { - ((CollapsingContentView) contentView).destroy(); - } - } - } - - protected ContentView getCurrentPage() { - return (ContentView) viewPager.getChildAt(viewPager.getCurrentItem()); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/ContentViewPagerAdapter.java b/android/app/src/main/java/com/reactnativenavigation/screens/ContentViewPagerAdapter.java deleted file mode 100644 index f0cb96ee2ac..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/ContentViewPagerAdapter.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.support.v4.view.PagerAdapter; -import android.support.v4.view.ViewPager; -import android.view.View; -import android.view.ViewGroup; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.events.EventBus; -import com.reactnativenavigation.events.ScreenChangedEvent; -import com.reactnativenavigation.events.ViewPagerScreenChangedEvent; -import com.reactnativenavigation.events.ViewPagerScreenScrollStartEvent; -import com.reactnativenavigation.params.PageParams; -import com.reactnativenavigation.views.ContentView; - -import java.util.List; - -class ContentViewPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener { - private List contentViews; - private List pageParams; - private int currentPosition = 0; - - ContentViewPagerAdapter(List contentViews, List pageParams) { - this.contentViews = contentViews; - this.pageParams = pageParams; - } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - return contentViews.get(position); - } - - @Override - public int getCount() { - return contentViews.size(); - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return view == object; - } - - @Override - public CharSequence getPageTitle(int position) { - return pageParams.get(position).title; - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - - } - - @Override - public void onPageSelected(int position) { - EventBus.instance.post(new ViewPagerScreenChangedEvent()); - sendDisappearEvents(currentPosition); - currentPosition = position; - EventBus.instance.post(new ScreenChangedEvent(pageParams.get(currentPosition))); - sendTabSelectedEventToJs(); - sendAppearEvents(position); - } - - - @Override - public void onPageScrollStateChanged(int state) { - if (state == ViewPager.SCROLL_STATE_DRAGGING) { - EventBus.instance.post(new ViewPagerScreenScrollStartEvent()); - } - } - - private void sendAppearEvents(int position) { - PageParams pageParams = this.pageParams.get(position); - pageParams.timestamp = System.currentTimeMillis(); - NavigationApplication.instance.getEventEmitter().sendWillAppearEvent(pageParams, NavigationType.TopTabSelected); - NavigationApplication.instance.getEventEmitter().sendDidAppearEvent(pageParams, NavigationType.TopTabSelected); - } - - private void sendDisappearEvents(int position) { - PageParams pageParams = this.pageParams.get(position); - pageParams.timestamp = System.currentTimeMillis(); - NavigationApplication.instance.getEventEmitter().sendWillDisappearEvent(pageParams, NavigationType.TopTabSelected); - NavigationApplication.instance.getEventEmitter().sendDidDisappearEvent(pageParams, NavigationType.TopTabSelected); - } - - private void sendTabSelectedEventToJs() { - WritableMap data = Arguments.createMap(); - String navigatorEventId = contentViews.get(currentPosition).getNavigatorEventId(); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("tabSelected", navigatorEventId, data); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/FragmentScreen.java b/android/app/src/main/java/com/reactnativenavigation/screens/FragmentScreen.java deleted file mode 100644 index addcbb41fa9..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/FragmentScreen.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.app.Fragment; -import android.app.FragmentManager; -import android.app.FragmentTransaction; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.widget.FrameLayout; - -import com.reactnativenavigation.R; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.ContentView; -import com.reactnativenavigation.views.LeftButtonOnClickListener; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - -@SuppressWarnings("ResourceType") -public class FragmentScreen extends Screen { - - private static final String CONTRACT_GET_FRAGMENT = "getFragment"; - private static final String CONTRACT_GET_SUPPORT_FRAGMENT = "getSupportFragment"; - private FrameLayout content; - private ContentView contentView; - - public FragmentScreen(AppCompatActivity activity, ScreenParams screenParams, LeftButtonOnClickListener leftButtonOnClickListener) { - super(activity, screenParams, leftButtonOnClickListener); - } - - @Override - public ContentView getContentView() { - return contentView; - } - - @Override - protected void createContent() { - content = new FrameLayout(getContext()); - content.setId(R.id.fragment_screen_content); - addContent(); - addFragment(); - } - - private void addContent() { - contentView = new ContentView(getContext(), - screenParams.screenId, - screenParams.navigationParams); - addView(contentView, 0, 0); - LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - if (screenParams.styleParams.drawScreenBelowTopBar) { - params.addRule(BELOW, topBar.getId()); - } - addView(content, params); - } - - - private void addFragment() { - try { - Fragment fragment = tryGetFragment(); - if (fragment != null) { - addFragment(fragment); - return; - } - - android.support.v4.app.Fragment supportFragment = tryGetSupportFragment(); - if (supportFragment != null) { - addSupportFragment(supportFragment); - return; - } - throw new RuntimeException("must provide public static method " + CONTRACT_GET_FRAGMENT + " or " + CONTRACT_GET_SUPPORT_FRAGMENT); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private void addFragment(Fragment fragment) { - FragmentManager fm = activity.getFragmentManager(); - FragmentTransaction transaction = fm.beginTransaction(); - transaction.add(R.id.fragment_screen_content, fragment); - transaction.commitAllowingStateLoss(); - } - - private void addSupportFragment(android.support.v4.app.Fragment supportFragment) { - android.support.v4.app.FragmentManager fm = activity.getSupportFragmentManager(); - android.support.v4.app.FragmentTransaction transaction = fm.beginTransaction(); - transaction.add(R.id.fragment_screen_content, supportFragment); - transaction.commitAllowingStateLoss(); - } - - @Nullable - private Fragment tryGetFragment() throws ClassNotFoundException, IllegalAccessException, InvocationTargetException { - try { - String className = screenParams.fragmentCreatorClassName; - Class fragmentCreatorClass = Class.forName(className); - Method method = fragmentCreatorClass.getMethod(CONTRACT_GET_FRAGMENT, Bundle.class); - return (android.app.Fragment) method.invoke(null, screenParams.fragmentCreatorPassProps); - } catch (NoSuchMethodException noSuchMethod) { - return null; - } - } - - @Nullable - private android.support.v4.app.Fragment tryGetSupportFragment() throws ClassNotFoundException, IllegalAccessException, InvocationTargetException { - try { - String className = screenParams.fragmentCreatorClassName; - Class fragmentCreatorClass = Class.forName(className); - Method method = fragmentCreatorClass.getMethod(CONTRACT_GET_SUPPORT_FRAGMENT, Bundle.class); - return (android.support.v4.app.Fragment) method.invoke(null, screenParams.fragmentCreatorPassProps); - } catch (NoSuchMethodException noSuchMethod) { - return null; - } - } - - @Override - public void unmountReactView() { - contentView.unmountReactView(); - } - - @Override - public String getNavigatorEventId() { - return screenParams.getNavigatorEventId(); - } - - @Override - public void setOnDisplayListener(final OnDisplayListener onContentViewDisplayedListener) { - ViewUtils.runOnPreDraw(content, new Runnable() { - @Override - public void run() { - onContentViewDisplayedListener.onDisplay(); - } - }); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/NavigationType.java b/android/app/src/main/java/com/reactnativenavigation/screens/NavigationType.java deleted file mode 100644 index 59a218dfccc..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/NavigationType.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.reactnativenavigation.screens; - -public enum NavigationType { - Push, - Pop, - BottomTabSelected, - SwitchToTab, - TopTabSelected, - InitialScreen, - ShowModal, - DismissModal, - OpenSideMenu, - CloseSideMenu -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/Screen.java b/android/app/src/main/java/com/reactnativenavigation/screens/Screen.java deleted file mode 100644 index 010212e6ad6..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/Screen.java +++ /dev/null @@ -1,359 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.animation.LayoutTransition; -import android.content.res.Configuration; -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.widget.RelativeLayout; - -import com.facebook.react.bridge.Callback; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.controllers.NavigationActivity; -import com.reactnativenavigation.events.ContextualMenuHiddenEvent; -import com.reactnativenavigation.events.Event; -import com.reactnativenavigation.events.EventBus; -import com.reactnativenavigation.events.FabSetEvent; -import com.reactnativenavigation.events.Subscriber; -import com.reactnativenavigation.events.ViewPagerScreenChangedEvent; -import com.reactnativenavigation.params.BaseScreenParams; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.params.StatusBarTextColorScheme; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.params.parsers.StyleParamsParser; -import com.reactnativenavigation.utils.NavigationBar; -import com.reactnativenavigation.utils.StatusBar; -import com.reactnativenavigation.views.ContentView; -import com.reactnativenavigation.views.LeftButtonOnClickListener; -import com.reactnativenavigation.views.TopBar; -import com.reactnativenavigation.views.sharedElementTransition.SharedElementTransition; -import com.reactnativenavigation.views.sharedElementTransition.SharedElements; - -import java.util.List; -import java.util.Map; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; - -public abstract class Screen extends RelativeLayout implements Subscriber { - - public interface OnDisplayListener { - void onDisplay(); - } - - protected final AppCompatActivity activity; - protected final ScreenParams screenParams; - protected TopBar topBar; - private final LeftButtonOnClickListener leftButtonOnClickListener; - private ScreenAnimator screenAnimator; - protected StyleParams styleParams; - public final SharedElements sharedElements; - - public Screen(AppCompatActivity activity, ScreenParams screenParams, LeftButtonOnClickListener leftButtonOnClickListener) { - super(activity); - this.activity = activity; - this.screenParams = screenParams; - styleParams = screenParams.styleParams; - this.leftButtonOnClickListener = leftButtonOnClickListener; - screenAnimator = new ScreenAnimator(this); - createViews(); - EventBus.instance.register(this); - sharedElements = new SharedElements(); - setDrawUnderStatusBar(styleParams.drawUnderStatusBar); - } - - public void registerSharedElement(SharedElementTransition toView, String key) { - sharedElements.addToElement(toView, key); - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - setStyle(); - } - - @Override - public void onEvent(Event event) { - if (ContextualMenuHiddenEvent.TYPE.equals(event.getType()) && isShown()) { - topBar.onContextualMenuHidden(); - setStyle(); - } - if (ViewPagerScreenChangedEvent.TYPE.equals(event.getType()) && isShown() ) { - topBar.dismissContextualMenu(); - topBar.onViewPagerScreenChanged(getScreenParams()); - } - } - - public void updateVisibleScreenStyle(Bundle styleParams) { - updateStyle(styleParams); - setStyle(); - } - - public void updateInvisibleScreenStyle(Bundle styleParams) { - updateStyle(styleParams); - } - - private void updateStyle(Bundle styleParams) { - screenParams.styleParams = new StyleParamsParser(screenParams.styleParams.params).merge(styleParams).parse(); - this.styleParams = screenParams.styleParams; - topBar.setButtonColor(this.styleParams); - } - - public void setStyle() { - setStatusBarColor(styleParams.statusBarColor); - setStatusBarHidden(styleParams.statusBarHidden); - setStatusBarTextColorScheme(styleParams.statusBarTextColorScheme); - setNavigationBarColor(styleParams.navigationBarColor); - setDrawUnderStatusBar(styleParams.drawUnderStatusBar); - topBar.setStyle(styleParams); - if (styleParams.screenBackgroundColor.hasColor()) { - setBackgroundColor(styleParams.screenBackgroundColor.getColor()); - } - } - - public void updateBottomTabsVisibility(boolean hidden) { - styleParams.bottomTabsHidden = hidden; - } - - private void createViews() { - createAndAddTopBar(); - createTitleBar(); - createContent(); - } - - protected abstract void createContent(); - - public abstract ContentView getContentView(); - - public TopBar getTopBar() { - return topBar; - } - - private void createTitleBar() { - addTitleBarButtons(); - if (screenParams.styleParams.hasTopBarCustomComponent()) { - topBar.setReactView(screenParams.styleParams); - } else { - topBar.setTitle(screenParams.title, styleParams); - topBar.setSubtitle(screenParams.subtitle, styleParams); - } - } - - private void addTitleBarButtons() { - setButtonColorFromScreen(screenParams.rightButtons); - if (screenParams.leftButton != null) { - screenParams.leftButton.setStyleFromScreen(screenParams.styleParams); - } - topBar.addTitleBarAndSetButtons(screenParams.rightButtons, - screenParams.leftButton, - leftButtonOnClickListener, - getNavigatorEventId(), - screenParams.overrideBackPressInJs, - styleParams); - } - - private void createAndAddTopBar() { - topBar = createTopBar(); - addTopBar(); - } - - protected TopBar createTopBar() { - return new TopBar(getContext()); - } - - private void addTopBar() { - addView(topBar, new LayoutParams(MATCH_PARENT, WRAP_CONTENT)); - } - - private void setStatusBarColor(StyleParams.Color statusBarColor) { - StatusBar.setColor(((NavigationActivity) activity).getScreenWindow(), statusBarColor); - } - - private void setStatusBarHidden(boolean statusBarHidden) { - StatusBar.setHidden(((NavigationActivity) activity).getScreenWindow(), statusBarHidden); - } - - private void setDrawUnderStatusBar(boolean drawUnderStatusBar) { - StatusBar.displayOverScreen(this, drawUnderStatusBar); - } - - private void setStatusBarTextColorScheme(StatusBarTextColorScheme textColorScheme) { - StatusBar.setTextColorScheme(this, textColorScheme); - } - - public void setNavigationBarColor(StyleParams.Color navigationBarColor) { - NavigationBar.setColor(((NavigationActivity) activity).getScreenWindow(), navigationBarColor); - } - - public abstract void unmountReactView(); - - public String getScreenInstanceId() { - return screenParams.getScreenInstanceId(); - } - - public boolean hasScreenInstance(String screenInstanceId) { - return screenParams.getScreenInstanceId().equals(screenInstanceId); - } - - public abstract String getNavigatorEventId(); - - public BaseScreenParams getScreenParams() { - return screenParams; - } - - public void setTopBarVisible(boolean visible, boolean animate) { - screenParams.styleParams.titleBarHidden = !visible; - if (animate && styleParams.drawScreenBelowTopBar) { - setLayoutTransition(new LayoutTransition()); - getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING); - } else { - setLayoutTransition(null); - } - topBar.setVisible(visible, animate); - } - - public void setTitleBarTitle(String title) { - topBar.setTitle(title, styleParams); - } - - public void setTitleBarSubtitle(String subtitle) { - topBar.setSubtitle(subtitle, styleParams); - } - - public void setTitleBarRightButtons(String navigatorEventId, List titleBarButtons) { - setButtonColorFromScreen(titleBarButtons); - topBar.setTitleBarRightButtons(navigatorEventId, titleBarButtons); - } - - public void setTitleBarLeftButton(String navigatorEventId, LeftButtonOnClickListener backButtonListener, - TitleBarLeftButtonParams titleBarLeftButtonParams) { - titleBarLeftButtonParams.setStyleFromScreen(styleParams); - topBar.setTitleBarLeftButton(navigatorEventId, - backButtonListener, - titleBarLeftButtonParams, - screenParams.overrideBackPressInJs); - } - - public void setFab(FabParams fabParams) { - screenParams.fabParams = fabParams; - if (isShown()) { - EventBus.instance.post(new FabSetEvent(fabParams)); - } - } - - public StyleParams getStyleParams() { - return screenParams.styleParams; - } - - private void setButtonColorFromScreen(List titleBarButtonParams) { - if (titleBarButtonParams == null) { - return; - } - - for (TitleBarButtonParams titleBarButtonParam : titleBarButtonParams) { - titleBarButtonParam.setStyleFromScreen(styleParams); - } - } - - public abstract void setOnDisplayListener(OnDisplayListener onContentViewDisplayedListener); - - public void show(NavigationType type) { - NavigationApplication.instance.getEventEmitter().sendWillAppearEvent(getScreenParams(), type); - NavigationApplication.instance.getEventEmitter().sendDidAppearEvent(getScreenParams(), type); - screenAnimator.show(screenParams.animateScreenTransitions); - } - - public void show(boolean animated, final NavigationType type) { - NavigationApplication.instance.getEventEmitter().sendWillAppearEvent(getScreenParams(), type); - screenAnimator.show(animated, new Runnable() { - @Override - public void run() { - NavigationApplication.instance.getEventEmitter().sendDidAppearEvent(getScreenParams(), type); - } - }); - } - - public void show(boolean animated, final Runnable onAnimationEnd, final NavigationType type) { - NavigationApplication.instance.getEventEmitter().sendWillAppearEvent(getScreenParams(), type); - setStyle(); - screenAnimator.show(animated, new Runnable() { - @Override - public void run() { - NavigationApplication.instance.getEventEmitter().sendDidAppearEvent(getScreenParams(), type); - if (onAnimationEnd != null) onAnimationEnd.run(); - } - }); - } - - public void showWithSharedElementsTransitions(Map fromElements, final Runnable onAnimationEnd) { - setStyle(); - sharedElements.setFromElements(fromElements); - screenAnimator.showWithSharedElementsTransitions(onAnimationEnd); - } - - public void hideWithSharedElementTransitions(Map toElements, final Runnable onAnimationEnd) { - sharedElements.setFromElements(sharedElements.getToElements()); - sharedElements.setToElements(toElements); - screenAnimator.hideWithSharedElementsTransition(onAnimationEnd); - } - - public void hide(Map sharedElements, Runnable onAnimationEnd, NavigationType type) { - removeHiddenSharedElements(); - if (hasVisibleSharedElements()) { - hideWithSharedElementTransitions(sharedElements, onAnimationEnd); - } else { - hide(false, onAnimationEnd, type); - } - } - - public void animateHide(Map sharedElements, Runnable onAnimationEnd, NavigationType type) { - removeHiddenSharedElements(); - if (hasVisibleSharedElements()) { - hideWithSharedElementTransitions(sharedElements, onAnimationEnd); - } else { - hide(true, onAnimationEnd, type); - } - } - - @SuppressWarnings("SimplifiableIfStatement") - private boolean hasVisibleSharedElements() { - if (screenParams.sharedElementsTransitions.isEmpty()) { - return false; - } - return !sharedElements.getToElements().isEmpty(); - } - - public void removeHiddenSharedElements() { - sharedElements.removeHiddenElements(); - } - - private void hide(boolean animated, final Runnable onAnimatedEnd, final NavigationType type) { - NavigationApplication.instance.getEventEmitter().sendWillDisappearEvent(getScreenParams(), type); - screenAnimator.hide(animated, new Runnable() { - @Override - public void run() { - NavigationApplication.instance.getEventEmitter().sendDidDisappearEvent(getScreenParams(), type); - if (onAnimatedEnd != null) onAnimatedEnd.run(); - } - }); - } - - public void showContextualMenu(ContextualMenuParams params, Callback onButtonClicked) { - topBar.showContextualMenu(params, styleParams, onButtonClicked); - setStatusBarColor(styleParams.contextualMenuStatusBarColor); - } - - public void dismissContextualMenu() { - topBar.dismissContextualMenu(); - } - - public void destroy() { - unmountReactView(); - EventBus.instance.unregister(this); - sharedElements.destroy(); - topBar.destroy(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/ScreenAnimator.java b/android/app/src/main/java/com/reactnativenavigation/screens/ScreenAnimator.java deleted file mode 100644 index b8e3a7354e6..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/ScreenAnimator.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.view.View; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; - -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.sharedElementTransition.SharedElementsAnimator; - -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nullable; - -class ScreenAnimator { - private static final int DURATION = 250; - private static final int ALPHA_HIDE_DURATION = 100; - private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(); - private static final DecelerateInterpolator DECELERATE_INTERPOLATOR_1x5 = new DecelerateInterpolator(1.5f); - private static final AccelerateDecelerateInterpolator ACCELERATE_DECELERATE_INTERPOLATOR = new AccelerateDecelerateInterpolator(); - private static final AccelerateInterpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator(); - private final float translationY; - private final float translationX; - private Screen screen; - - ScreenAnimator(Screen screen) { - this.screen = screen; - translationY = 0.05f * ViewUtils.getWindowHeight(screen.activity); - translationX = ViewUtils.getWindowWidth(screen.activity); - } - - public void show(boolean animate, final Runnable onAnimationEnd) { - if (animate) { - createShowAnimator(onAnimationEnd).start(); - } else { - screen.setVisibility(View.VISIBLE); - NavigationApplication.instance.runOnMainThread(onAnimationEnd, DURATION); - } - } - - public void show(boolean animate) { - if (animate) { - createShowAnimator(null).start(); - } else { - screen.setVisibility(View.VISIBLE); - } - } - - public void hide(boolean animate, Runnable onAnimationEnd) { - if (animate) { - createHideAnimator(onAnimationEnd).start(); - } else { - screen.setVisibility(View.INVISIBLE); - onAnimationEnd.run(); - } - } - - private Animator createShowAnimator(final @Nullable Runnable onAnimationEnd) { - ObjectAnimator alpha = ObjectAnimator.ofFloat(screen, View.ALPHA, 0, 1); - - AnimatorSet set = new AnimatorSet(); - switch (String.valueOf(this.screen.screenParams.animationType)) { - case "fade": { - alpha.setDuration(DURATION); - alpha.setInterpolator(DECELERATE_INTERPOLATOR); - set.play(alpha); - break; - } - case "slide-horizontal": { - ObjectAnimator translationX = ObjectAnimator.ofFloat(screen, View.TRANSLATION_X, this.translationX, 0); - translationX.setInterpolator(ACCELERATE_DECELERATE_INTERPOLATOR); - translationX.setDuration(DURATION); - set.play(translationX); - break; - } - default: { - ObjectAnimator translationY = ObjectAnimator.ofFloat(screen, View.TRANSLATION_Y, this.translationY, 0); - set.setInterpolator(DECELERATE_INTERPOLATOR_1x5); - set.setDuration(DURATION); - set.playTogether(translationY, alpha); - break; - } - } - - set.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - screen.setVisibility(View.VISIBLE); - } - - @Override - public void onAnimationEnd(Animator animation) { - if (onAnimationEnd != null) { - onAnimationEnd.run(); - } - } - }); - return set; - } - - private Animator createHideAnimator(final Runnable onAnimationEnd) { - ObjectAnimator alpha = ObjectAnimator.ofFloat(screen, View.ALPHA, 0); - - AnimatorSet set = new AnimatorSet(); - switch (String.valueOf(this.screen.screenParams.animationType)) { - case "fade": { - alpha.setDuration(DURATION); - alpha.setInterpolator(DECELERATE_INTERPOLATOR); - set.play(alpha); - break; - } - case "slide-horizontal": { - ObjectAnimator translationX = ObjectAnimator.ofFloat(screen, View.TRANSLATION_X, this.translationX); - translationX.setInterpolator(ACCELERATE_INTERPOLATOR); - translationX.setDuration(DURATION); - set.play(translationX); - break; - } - default: { - ObjectAnimator translationY = ObjectAnimator.ofFloat(screen, View.TRANSLATION_Y, this.translationY); - translationY.setDuration(DURATION); - alpha.setDuration(ALPHA_HIDE_DURATION); - set.setInterpolator(DECELERATE_INTERPOLATOR); - set.playTogether(translationY, alpha); - break; - } - } - - set.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - onAnimationEnd.run(); - } - }); - return set; - } - - void showWithSharedElementsTransitions(Runnable onAnimationEnd) { - hideContentViewAndTopBar(); - screen.setVisibility(View.VISIBLE); - new SharedElementsAnimator(this.screen.sharedElements).show(new Runnable() { - @Override - public void run() { - animateContentViewAndTopBar(1, 280); - } - }, onAnimationEnd); - } - - private void hideContentViewAndTopBar() { - if (screen.screenParams.animateScreenTransitions) { - screen.getContentView().setAlpha(0); - } - screen.getTopBar().setAlpha(0); - } - - void hideWithSharedElementsTransition(Runnable onAnimationEnd) { - new SharedElementsAnimator(screen.sharedElements).hide(new Runnable() { - @Override - public void run() { - animateContentViewAndTopBar(0, 200); - } - }, onAnimationEnd); - } - - private void animateContentViewAndTopBar(int alpha, int duration) { - List animators = new ArrayList<>(); - if (screen.screenParams.animateScreenTransitions) { - animators.add(ObjectAnimator.ofFloat(screen.getContentView(), View.ALPHA, alpha)); - } - animators.add(ObjectAnimator.ofFloat(screen.getTopBar(), View.ALPHA, alpha)); - AnimatorSet set = new AnimatorSet(); - set.playTogether(animators); - set.setDuration(duration); - set.start(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/ScreenFactory.java b/android/app/src/main/java/com/reactnativenavigation/screens/ScreenFactory.java deleted file mode 100644 index 1af87092ae2..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/ScreenFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.support.v7.app.AppCompatActivity; - -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.views.LeftButtonOnClickListener; - -class ScreenFactory { - static Screen create(AppCompatActivity activity, - ScreenParams screenParams, - LeftButtonOnClickListener leftButtonOnClickListener) { - if (screenParams.isFragmentScreen()) { - return new FragmentScreen(activity, screenParams, leftButtonOnClickListener); - } else if (screenParams.hasTopTabs()) { - if (screenParams.hasCollapsingTopBar()) { - return new CollapsingViewPagerScreen(activity, screenParams, leftButtonOnClickListener); - } else { - return new ViewPagerScreen(activity, screenParams, leftButtonOnClickListener); - } - } else if (screenParams.hasCollapsingTopBar()) { - return new CollapsingSingleScreen(activity, screenParams, leftButtonOnClickListener); - } else { - return new SingleScreen(activity, screenParams, leftButtonOnClickListener); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java b/android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java deleted file mode 100644 index b6318fdcd5a..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/ScreenStack.java +++ /dev/null @@ -1,465 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.view.View; -import android.widget.RelativeLayout; -import android.widget.RelativeLayout.LayoutParams; - -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.Promise; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.utils.KeyboardVisibilityDetector; -import com.reactnativenavigation.utils.Task; -import com.reactnativenavigation.views.LeftButtonOnClickListener; - -import java.util.List; -import java.util.Stack; - -public class ScreenStack { - private static final String TAG = "ScreenStack"; - - public interface OnScreenPop { - void onScreenPopAnimationEnd(); - } - - private final AppCompatActivity activity; - private RelativeLayout parent; - private LeftButtonOnClickListener leftButtonOnClickListener; - private Stack stack = new Stack<>(); - private final KeyboardVisibilityDetector keyboardVisibilityDetector; - private boolean isStackVisible = false; - private final String navigatorId; - - public String getNavigatorId() { - return navigatorId; - } - - public ScreenStack(AppCompatActivity activity, - RelativeLayout parent, - String navigatorId, - LeftButtonOnClickListener leftButtonOnClickListener) { - this.activity = activity; - this.parent = parent; - this.navigatorId = navigatorId; - this.leftButtonOnClickListener = leftButtonOnClickListener; - keyboardVisibilityDetector = new KeyboardVisibilityDetector(parent); - } - - public void newStack(final ScreenParams params, LayoutParams layoutParams) { - final Screen nextScreen = ScreenFactory.create(activity, params, leftButtonOnClickListener); - final Screen previousScreen = stack.peek(); - if (isStackVisible) { - pushScreenToVisibleStack(layoutParams, nextScreen, previousScreen, null, new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - removeElementsBelowTop(); - } - }); - } else { - pushScreenToInvisibleStack(layoutParams, nextScreen, previousScreen, null); - removeElementsBelowTop(); - } - } - - private void removeElementsBelowTop() { - while (stack.size() > 1) { - Screen screen = stack.get(0); - parent.removeView(screen); - screen.destroy(); - stack.remove(0); - } - } - - public void pushInitialModalScreenWithAnimation(final ScreenParams initialScreenParams, LayoutParams params) { - isStackVisible = true; - pushInitialScreen(initialScreenParams, params); - final Screen screen = stack.peek(); - screen.setOnDisplayListener(new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - screen.show(initialScreenParams.animateScreenTransitions, NavigationType.ShowModal); - screen.setStyle(); - } - }); - } - - public void pushInitialScreen(ScreenParams initialScreenParams, LayoutParams params) { - Screen initialScreen = ScreenFactory.create(activity, initialScreenParams, leftButtonOnClickListener); - initialScreen.setVisibility(View.INVISIBLE); - addScreen(initialScreen, params); - } - - public void push(final ScreenParams params, LayoutParams layoutParams, Promise onPushComplete) { - Screen nextScreen = ScreenFactory.create(activity, params, leftButtonOnClickListener); - final Screen previousScreen = stack.peek(); - if (isStackVisible) { - if (nextScreen.screenParams.sharedElementsTransitions.isEmpty()) { - pushScreenToVisibleStack(layoutParams, nextScreen, previousScreen, onPushComplete); - } else { - pushScreenToVisibleStackWithSharedElementTransition(layoutParams, nextScreen, previousScreen, onPushComplete); - } - } else { - pushScreenToInvisibleStack(layoutParams, nextScreen, previousScreen, onPushComplete); - } - } - - private void pushScreenToVisibleStack(LayoutParams layoutParams, final Screen nextScreen, - final Screen previousScreen, Promise onPushComplete) { - pushScreenToVisibleStack(layoutParams, nextScreen, previousScreen, onPushComplete, null); - } - - private void pushScreenToVisibleStack(LayoutParams layoutParams, - final Screen nextScreen, - final Screen previousScreen, - @Nullable final Promise onPushComplete, - @Nullable final Screen.OnDisplayListener onDisplay) { - nextScreen.setVisibility(View.INVISIBLE); - addScreen(nextScreen, layoutParams); - NavigationApplication.instance.getEventEmitter().sendWillDisappearEvent(previousScreen.getScreenParams(), NavigationType.Push); - nextScreen.setOnDisplayListener(new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - nextScreen.show(nextScreen.screenParams.animateScreenTransitions, new Runnable() { - @Override - public void run() { - if (onDisplay != null) onDisplay.onDisplay(); - if (onPushComplete != null) onPushComplete.resolve(null); - NavigationApplication.instance.getEventEmitter().sendDidDisappearEvent(previousScreen.getScreenParams(), NavigationType.Push); - parent.removeView(previousScreen); - } - }, NavigationType.Push); - } - }); - } - - private void pushScreenToVisibleStackWithSharedElementTransition(LayoutParams layoutParams, final Screen nextScreen, - final Screen previousScreen, @Nullable final Promise onPushComplete) { - nextScreen.setVisibility(View.INVISIBLE); - nextScreen.setOnDisplayListener(new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - nextScreen.showWithSharedElementsTransitions(previousScreen.sharedElements.getToElements(), new Runnable() { - @Override - public void run() { - if (onPushComplete != null) onPushComplete.resolve(null); - parent.removeView(previousScreen); - } - }); - } - }); - addScreen(nextScreen, layoutParams); - } - - private void pushScreenToInvisibleStack(LayoutParams layoutParams, Screen nextScreen, Screen previousScreen, - @Nullable final Promise onPushComplete) { - nextScreen.setVisibility(View.INVISIBLE); - nextScreen.setOnDisplayListener(new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - if (onPushComplete != null) onPushComplete.resolve(null); - } - }); - addScreen(nextScreen, layoutParams); - parent.removeView(previousScreen); - } - - private void addScreen(Screen screen, LayoutParams layoutParams) { - addScreenBeforeSnackbarAndFabLayout(screen, layoutParams); - stack.push(screen); - } - - private void addScreenBeforeSnackbarAndFabLayout(Screen screen, LayoutParams layoutParams) { - parent.addView(screen, parent.getChildCount() - 1, layoutParams); - } - - public void pop(boolean animated, double jsPopTimestamp) { - pop(animated, jsPopTimestamp, null); - } - - public void pop(final boolean animated, final double jsPopTimestamp, @Nullable final OnScreenPop onScreenPop) { - if (!canPop()) { - return; - } - if (keyboardVisibilityDetector.isKeyboardVisible()) { - keyboardVisibilityDetector.setKeyboardCloseListener(new Runnable() { - @Override - public void run() { - keyboardVisibilityDetector.setKeyboardCloseListener(null); - popInternal(animated, jsPopTimestamp, onScreenPop); - } - }); - keyboardVisibilityDetector.closeKeyboard(); - } else { - popInternal(animated, jsPopTimestamp, onScreenPop); - } - } - - private void popInternal(final boolean animated, double jsPopTimestamp, @Nullable final OnScreenPop onScreenPop) { - final Screen toRemove = stack.pop(); - final Screen previous = stack.peek(); - previous.screenParams.timestamp = jsPopTimestamp; - swapScreens(animated, toRemove, previous, onScreenPop); - } - - private void swapScreens(boolean animated, final Screen toRemove, Screen previous, OnScreenPop onScreenPop) { - readdPrevious(previous); - previous.setStyle(); - hideScreen(animated, toRemove, previous); - if (onScreenPop != null) { - onScreenPop.onScreenPopAnimationEnd(); - } - } - - private void hideScreen(boolean animated, final Screen toRemove, final Screen previous) { - NavigationApplication.instance.getEventEmitter().sendWillAppearEvent(previous.getScreenParams(), NavigationType.Pop); - Runnable onAnimationEnd = new Runnable() { - @Override - public void run() { - toRemove.destroy(); - parent.removeView(toRemove); - NavigationApplication.instance.getEventEmitter().sendDidAppearEvent(previous.getScreenParams(), NavigationType.Pop); - } - }; - if (animated) { - toRemove.animateHide(previous.sharedElements.getToElements(), onAnimationEnd, NavigationType.Pop); - } else { - toRemove.hide(previous.sharedElements.getToElements(), onAnimationEnd, NavigationType.Pop); - } - } - - public Screen peek() { - return stack.peek(); - } - - private void readdPrevious(Screen previous) { - previous.setVisibility(View.VISIBLE); - parent.addView(previous, 0); - } - - public void popToRoot(final boolean animated, final double jsPopTimestamp, @Nullable final OnScreenPop onScreenPop) { - if (keyboardVisibilityDetector.isKeyboardVisible()) { - keyboardVisibilityDetector.setKeyboardCloseListener(new Runnable() { - @Override - public void run() { - keyboardVisibilityDetector.setKeyboardCloseListener(null); - popToRootInternal(animated, jsPopTimestamp, onScreenPop); - } - }); - keyboardVisibilityDetector.closeKeyboard(); - } else { - popToRootInternal(animated, jsPopTimestamp, onScreenPop); - } - } - - private void popToRootInternal(final boolean animated, double jsPopTimestamp, @Nullable final OnScreenPop onScreenPop) { - while (canPop()) { - if (stack.size() == 2) { - popInternal(animated, jsPopTimestamp, onScreenPop); - } else { - popInternal(animated, jsPopTimestamp, null); - } - } - } - - public void destroy() { - for (Screen screen : stack) { - screen.destroy(); - parent.removeView(screen); - } - stack.clear(); - } - - public boolean canPop() { - return stack.size() > 1 && !isPreviousScreenAttachedToWindow(); - } - - private boolean isPreviousScreenAttachedToWindow() { - Screen previousScreen = stack.get(stack.size() - 2); - if (previousScreen.getParent() != null) { - Log.w(TAG, "Can't pop stack. reason: previous screen is already attached"); - return true; - } - return false; - } - - public void setScreenTopBarVisible(String screenInstanceId, final boolean visible, final boolean animate) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen param) { - param.setTopBarVisible(visible, animate); - } - }); - } - - public void setScreenTitleBarTitle(String screenInstanceId, final String title) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen param) { - param.setTitleBarTitle(title); - } - }); - } - - public void setScreenTitleBarSubtitle(String screenInstanceId, final String subtitle) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen param) { - param.setTitleBarSubtitle(subtitle); - } - }); - } - - public void setScreenTitleBarRightButtons(String screenInstanceId, final String navigatorEventId, final List titleBarButtons) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen param) { - param.setTitleBarRightButtons(navigatorEventId, titleBarButtons); - } - }); - } - - public void setScreenTitleBarLeftButton(String screenInstanceId, final String navigatorEventId, final TitleBarLeftButtonParams titleBarLeftButtonParams) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen screen) { - screen.setTitleBarLeftButton(navigatorEventId, leftButtonOnClickListener, titleBarLeftButtonParams); - } - }); - } - - public void setFab(String screenInstanceId, final FabParams fabParams) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen screen) { - screen.setFab(fabParams); - } - }); - } - - public void updateScreenStyle(String screenInstanceId, final Bundle styleParams) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen screen) { - if (isScreenVisible(screen)) { - screen.updateVisibleScreenStyle(styleParams); - } else { - screen.updateInvisibleScreenStyle(styleParams); - } - } - }); - } - - private boolean isScreenVisible(Screen screen) { - return isStackVisible && peek() == screen; - } - - public void showContextualMenu(String screenInstanceId, final ContextualMenuParams params, final Callback onButtonClicked) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen screen) { - screen.showContextualMenu(params, onButtonClicked); - } - }); - } - - public void dismissContextualMenu(String screenInstanceId) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen screen) { - screen.dismissContextualMenu(); - } - }); - } - - public void selectTopTabByTabIndex(String screenInstanceId, final int index) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen screen) { - if (screen.screenParams.hasTopTabs()) { - ((ViewPagerScreen) screen).selectTopTabByTabIndex(index); - } - } - }); - } - - public void selectTopTabByScreen(final String screenInstanceId) { - performOnScreen(screenInstanceId, new Task() { - @Override - public void run(Screen screen) { - ((ViewPagerScreen) screen).selectTopTabByTabByScreen(screenInstanceId); - } - }); - } - - public StyleParams getCurrentScreenStyleParams() { - return stack.peek().getStyleParams(); - } - - public boolean handleBackPressInJs() { - ScreenParams currentScreen = stack.peek().screenParams; - if (currentScreen.overrideBackPressInJs) { - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("backPress", currentScreen.getNavigatorEventId()); - return true; - } - return false; - } - - private void performOnScreen(String screenInstanceId, Task task) { - if (stack.isEmpty()) { - return; - } - for (Screen screen : stack) { - if (screen.hasScreenInstance(screenInstanceId)) { - task.run(screen); - return; - } - } - } - - public void show(NavigationType type) { - isStackVisible = true; - stack.peek().setStyle(); - stack.peek().setVisibility(View.VISIBLE); - sendScreenAppearEvent(type, stack.peek()); - } - - private void sendScreenAppearEvent(final NavigationType type, final Screen screen) { - if (type == NavigationType.InitialScreen) { - sendInitialScreenAppearEvent(type, screen); - } else { - sendScreenAppearEvent(screen, type); - } - } - - private void sendInitialScreenAppearEvent(final NavigationType type, final Screen screen) { - screen.setOnDisplayListener(new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - sendScreenAppearEvent(screen, type); - } - }); - } - - private void sendScreenAppearEvent(Screen screen, NavigationType type) { - screen.getScreenParams().timestamp = System.currentTimeMillis(); - NavigationApplication.instance.getEventEmitter().sendWillAppearEvent(screen.getScreenParams(), type); - NavigationApplication.instance.getEventEmitter().sendDidAppearEvent(screen.getScreenParams(), type); - } - - - public void hide(NavigationType type) { - NavigationApplication.instance.getEventEmitter().sendWillDisappearEvent(stack.peek().getScreenParams(), type); - NavigationApplication.instance.getEventEmitter().sendDidDisappearEvent(stack.peek().getScreenParams(), type); - isStackVisible = false; - stack.peek().setVisibility(View.INVISIBLE); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/SingleScreen.java b/android/app/src/main/java/com/reactnativenavigation/screens/SingleScreen.java deleted file mode 100644 index 7a0a7bce0f8..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/SingleScreen.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.support.v7.app.AppCompatActivity; - -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.views.ContentView; -import com.reactnativenavigation.views.LeftButtonOnClickListener; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - -public class SingleScreen extends Screen { - protected ContentView contentView; - - public SingleScreen(AppCompatActivity activity, ScreenParams screenParams, - LeftButtonOnClickListener titleBarBarBackButtonListener) { - super(activity, screenParams, titleBarBarBackButtonListener); - } - - @Override - protected void createContent() { - contentView = new ContentView(getContext(), screenParams.screenId, screenParams.navigationParams); - addView(contentView, 0, createLayoutParams()); - } - - @Override - public ContentView getContentView() { - return contentView; - } - - protected LayoutParams createLayoutParams() { - LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - if (screenParams.styleParams.drawScreenBelowTopBar) { - params.addRule(BELOW, topBar.getId()); - } - return params; - } - - @Override - public void unmountReactView() { - contentView.unmountReactView(); - } - - @Override - public String getNavigatorEventId() { - return screenParams.getNavigatorEventId(); - } - - @Override - public void setOnDisplayListener(OnDisplayListener onContentViewDisplayedListener) { - contentView.setOnDisplayListener(onContentViewDisplayedListener); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/screens/ViewPagerScreen.java b/android/app/src/main/java/com/reactnativenavigation/screens/ViewPagerScreen.java deleted file mode 100644 index c51910e9c9f..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/screens/ViewPagerScreen.java +++ /dev/null @@ -1,162 +0,0 @@ -package com.reactnativenavigation.screens; - -import android.content.Context; -import android.support.design.widget.TabLayout; -import android.support.v4.view.ViewPager; -import android.support.v7.app.AppCompatActivity; - -import com.reactnativenavigation.params.BaseScreenParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.PageParams; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.views.ContentView; -import com.reactnativenavigation.views.LeftButtonOnClickListener; -import com.reactnativenavigation.views.TopTabs; - -import java.util.ArrayList; -import java.util.List; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; - -public class ViewPagerScreen extends Screen { - - private static final int OFFSCREEN_PAGE_LIMIT = 99; - protected List contentViews; - protected ViewPager viewPager; - - public ViewPagerScreen(AppCompatActivity activity, ScreenParams screenParams, LeftButtonOnClickListener backButtonListener) { - super(activity, screenParams, backButtonListener); - } - - @Override - public BaseScreenParams getScreenParams() { - return screenParams.topTabParams.get(getCurrentItem()); - } - - @Override - public void setTitleBarLeftButton(String navigatorEventId, LeftButtonOnClickListener backButtonListener, TitleBarLeftButtonParams titleBarLeftButtonParams) { - super.setTitleBarLeftButton(getNavigatorEventId(), backButtonListener, titleBarLeftButtonParams); - } - - @Override - public void setFab(FabParams fabParams) { - super.setFab(fabParams); - getScreenParams().fabParams = fabParams; - } - - @Override - public ContentView getContentView() { - return contentViews.get(getCurrentItem()); - } - - @Override - protected void createContent() { - TopTabs topTabs = topBar.initTabs(screenParams.styleParams); - createViewPager(); - addPages(); - setupViewPager(topTabs); - setTopTabIcons(topTabs); - } - - private void createViewPager() { - viewPager = createViewPager(getContext()); - viewPager.setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT); - LayoutParams lp = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - if (screenParams.styleParams.drawScreenBelowTopBar) { - lp.addRule(BELOW, topBar.getId()); - } - addView(viewPager, lp); - } - - protected ViewPager createViewPager(Context context) { - return new ViewPager(context); - } - - private void addPages() { - contentViews = new ArrayList<>(); - for (PageParams tab : screenParams.topTabParams) { - addPage(tab); - } - } - - private void addPage(PageParams tab) { - ContentView contentView = createContentView(tab); - addContent(contentView); - contentViews.add(contentView); - } - - protected ContentView createContentView(PageParams tab) { - return new ContentView(getContext(), tab.screenId, tab.navigationParams); - } - - private void setupViewPager(TabLayout tabLayout) { - ContentViewPagerAdapter adapter = new ContentViewPagerAdapter(contentViews, screenParams.topTabParams); - viewPager.setAdapter(adapter); - viewPager.addOnPageChangeListener(adapter); - tabLayout.setupWithViewPager(viewPager); - } - - private void setTopTabIcons(TopTabs topTabs) { - for (int i = 0; i < topTabs.getTabCount(); i++) { - PageParams pageParams = screenParams.topTabParams.get(i); - if (pageParams.tabIcon != null) { - topTabs.getTabAt(i).setIcon(pageParams.tabIcon); - } - } - topTabs.setTopTabsIconColor(screenParams.styleParams); - } - - private void addContent(ContentView contentView) { - LayoutParams params = new LayoutParams(MATCH_PARENT, MATCH_PARENT); - viewPager.addView(contentView, params); - } - - @Override - public void unmountReactView() { - for (ContentView contentView : contentViews) { - contentView.unmountReactView(); - } - } - - @Override - public void setOnDisplayListener(OnDisplayListener onContentViewDisplayedListener) { - contentViews.get(0).setOnDisplayListener(onContentViewDisplayedListener); - } - - @Override - public String getScreenInstanceId() { - return screenParams.topTabParams.get(getCurrentItem()).navigationParams.screenInstanceId; - } - - @Override - public String getNavigatorEventId() { - return screenParams.topTabParams.get(getCurrentItem()).navigationParams.navigatorEventId; - } - - private int getCurrentItem() { - return viewPager == null ? 0 : viewPager.getCurrentItem(); - } - - public void selectTopTabByTabIndex(int index) { - viewPager.setCurrentItem(index); - } - - @Override - public boolean hasScreenInstance(String screenInstanceId) { - for (PageParams topTabParam : screenParams.topTabParams) { - if(screenInstanceId.equals(topTabParam.getScreenInstanceId())) { - return true; - } - } - return false; - } - - public void selectTopTabByTabByScreen(String screenInstanceId) { - for (int i = 0; i < screenParams.topTabParams.size(); i++) { - if (screenParams.topTabParams.get(i).getScreenInstanceId().equals(screenInstanceId)) { - viewPager.setCurrentItem(i); - } - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/ArrayUtils.java b/android/app/src/main/java/com/reactnativenavigation/utils/ArrayUtils.java deleted file mode 100644 index 89f22085482..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/ArrayUtils.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.reactnativenavigation.utils; - -import java.util.Arrays; - -public class ArrayUtils { - public static float[] reverse(float[] array) { - float[] result = Arrays.copyOf(array, array.length); - for(int i = 0; i < result.length / 2; i++) { - float temp = result[i]; - result[i] = result[result.length - i - 1]; - result[result.length - i - 1] = temp; - } - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/CompatUtils.java b/android/app/src/main/java/com/reactnativenavigation/utils/CompatUtils.java deleted file mode 100644 index ec78af71be4..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/CompatUtils.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.app.Activity; -import android.content.Intent; - -public class CompatUtils { - public static boolean isSplashOpenedOverNavigationActivity(final Activity act, final Intent intent) { - return intent != null && intent.getAction() != null - && intent.getAction().equals(Intent.ACTION_MAIN) - && !act.isTaskRoot() - && intent.hasCategory(Intent.CATEGORY_LAUNCHER); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/KeyboardVisibilityDetector.java b/android/app/src/main/java/com/reactnativenavigation/utils/KeyboardVisibilityDetector.java deleted file mode 100644 index 2ffea65d4da..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/KeyboardVisibilityDetector.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.content.Context; -import android.graphics.Rect; -import android.view.View; -import android.view.ViewTreeObserver; -import android.view.inputmethod.InputMethodManager; - -import com.reactnativenavigation.NavigationApplication; - -public class KeyboardVisibilityDetector { - // 0.15 ratio is perhaps enough to determine keypad height. - public static final double KEYBOARD_VISIBLE_RATIO = 0.15; - - private final KeyboardVisibilityLayoutListener keyboardVisibilityListener; - private final View screen; - private Runnable keyboardCloseListener; - - public KeyboardVisibilityDetector(final View screen) { - this.screen = screen; - keyboardVisibilityListener = new KeyboardVisibilityLayoutListener(this); - screen.getViewTreeObserver().addOnGlobalLayoutListener(keyboardVisibilityListener); - } - - public boolean isKeyboardVisible() { - return keyboardVisibilityListener.isKeyboardVisible(); - } - - public void setKeyboardCloseListener(Runnable keyboardCloseListener) { - this.keyboardCloseListener = keyboardCloseListener; - } - - public void closeKeyboard() { - InputMethodManager imm = (InputMethodManager) screen.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0); - } - - private static class KeyboardVisibilityLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener { - public static final int KEYBOARD_CLOSE_DURATION = 100; - private View screen; - private boolean isVisible = false; - private KeyboardVisibilityDetector detector; - - public KeyboardVisibilityLayoutListener(KeyboardVisibilityDetector detector) { - this.detector = detector; - this.screen = detector.screen; - } - - public boolean isKeyboardVisible() { - return isVisible; - } - - @Override - public void onGlobalLayout() { - int screenHeight = screen.getRootView().getHeight(); - int screenBottomY = getScreenBottomY(screen); - - int keyboardHeight = screenHeight - screenBottomY; - if (isKeyboardVisible(screenHeight, keyboardHeight)) { - isVisible = true; - } else { - if (isVisible && detector.keyboardCloseListener != null) { - NavigationApplication.instance.runOnMainThread(detector.keyboardCloseListener, KEYBOARD_CLOSE_DURATION); - } - isVisible = false; - } - } - - private boolean isKeyboardVisible(int screenHeight, int keypadHeight) { - return keypadHeight > screenHeight * KEYBOARD_VISIBLE_RATIO; - } - - private int getScreenBottomY(View screen) { - Rect r = new Rect(); - screen.getWindowVisibleDisplayFrame(r); - return r.bottom; - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/NavigationBar.java b/android/app/src/main/java/com/reactnativenavigation/utils/NavigationBar.java deleted file mode 100644 index dd04ac45315..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/NavigationBar.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.annotation.TargetApi; -import android.graphics.Color; -import android.os.Build; -import android.view.Window; - -import com.reactnativenavigation.params.StyleParams; - - -public class NavigationBar { - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public static void setColor(Window window, StyleParams.Color navigationBarColor) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || window == null) return; -// final Window window = ((NavigationActivity) activity).getScreenWindow(); - if (navigationBarColor.hasColor()) { - window.setNavigationBarColor(navigationBarColor.getColor()); - } else { - window.setNavigationBarColor(Color.BLACK); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/OrientationHelper.java b/android/app/src/main/java/com/reactnativenavigation/utils/OrientationHelper.java deleted file mode 100644 index aeb2731d738..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/OrientationHelper.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.app.Activity; -import android.content.res.Configuration; - -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.WritableMap; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.controllers.NavigationActivity; -import com.reactnativenavigation.params.Orientation; - -public class OrientationHelper { - public static String getOrientation(NavigationActivity currentActivity) { - return Orientation.fromConfigurationCode(currentActivity.getResources().getConfiguration().orientation); - } - - public static void setOrientation(Activity activity, Orientation orientation) { - activity.setRequestedOrientation(orientation.orientationCode); - } - - public static void onConfigurationChanged(Configuration newConfig) { - WritableMap params = Arguments.createMap(); - params.putString("orientation", Orientation.fromConfigurationCode(newConfig.orientation)); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("orientationChanged", params); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/ReflectionUtils.java b/android/app/src/main/java/com/reactnativenavigation/utils/ReflectionUtils.java deleted file mode 100644 index 2c1921fb0ef..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/ReflectionUtils.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.support.annotation.Nullable; - -import java.lang.reflect.Field; - -public class ReflectionUtils { - - public static void setField(Object obj, String name, Object value) { - try { - Field field = getField(obj.getClass(), name); - if (field == null) { - return; - } - field.setAccessible(true); - field.set(obj, value); - } catch (Exception e) { - e.printStackTrace(); - } - } - - @Nullable - public static Object getDeclaredField(Object obj, String fieldName) { - try { - Field f = getField(obj.getClass(), fieldName); - if (f == null) { - return null; - } - f.setAccessible(true); - return f.get(obj); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - private static Field getField(Class clazz, String name) { - try { - return clazz.getDeclaredField(name); - } catch (NoSuchFieldException nsfe) { - return getField(clazz.getSuperclass(), name); - } catch (Exception e) { - return null; - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/StatusBar.java b/android/app/src/main/java/com/reactnativenavigation/utils/StatusBar.java deleted file mode 100644 index af907d44bf4..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/StatusBar.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.annotation.TargetApi; -import android.graphics.Color; -import android.os.Build; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; - -import com.reactnativenavigation.params.StatusBarTextColorScheme; -import com.reactnativenavigation.params.StyleParams; - -public class StatusBar { - - public static void setHidden(Window window, boolean statusBarHidden) { - if (statusBarHidden) { - window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - } else { - window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public static void setColor(Window window, StyleParams.Color statusBarColor) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return; - if (statusBarColor.hasColor()) { - window.setStatusBarColor(statusBarColor.getColor()); - } else { - window.setStatusBarColor(Color.BLACK); - } - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public static void displayOverScreen(View view, boolean shouldDisplay) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return; - - if(shouldDisplay) { - int flags = view.getSystemUiVisibility(); - flags |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE; - flags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; - view.setSystemUiVisibility(flags); - } else { - int flags = view.getSystemUiVisibility(); - flags &= ~View.SYSTEM_UI_FLAG_LAYOUT_STABLE; - flags &= ~View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; - view.setSystemUiVisibility(flags); - } - } - - @TargetApi(Build.VERSION_CODES.M) - public static void setTextColorScheme(View view, StatusBarTextColorScheme textColorScheme) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return; - if (StatusBarTextColorScheme.Dark.equals(textColorScheme)) { - int flags = view.getSystemUiVisibility(); - flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - view.setSystemUiVisibility(flags); - } else { - clearLightStatusBar(view); - } - } - - private static void clearLightStatusBar(View view) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return; - int flags = view.getSystemUiVisibility(); - flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - view.setSystemUiVisibility(flags); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/Task.java b/android/app/src/main/java/com/reactnativenavigation/utils/Task.java deleted file mode 100644 index 5bf275773e0..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/Task.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.reactnativenavigation.utils; - -public interface Task { - void run(T param); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/TypefaceLoader.java b/android/app/src/main/java/com/reactnativenavigation/utils/TypefaceLoader.java deleted file mode 100644 index 8783cfa5640..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/TypefaceLoader.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.content.res.AssetManager; -import android.graphics.Typeface; -import android.support.annotation.NonNull; -import android.widget.TextView; - -import com.reactnativenavigation.NavigationApplication; - -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class TypefaceLoader { - private static final Map typefaceRegistry = new HashMap<>(); - - private String fontFamilyName; - - public TypefaceLoader(String fontFamilyName) { - this.fontFamilyName = fontFamilyName; - } - - public void load(@NonNull TextView view) { - Typeface result = getTypeFace(); - view.setTypeface(result); - } - - public Typeface getTypeFace() { - if (typefaceRegistry.containsKey(fontFamilyName)) { - return typefaceRegistry.get(fontFamilyName); - } - Typeface result = load(fontFamilyName); - typefaceRegistry.put(fontFamilyName, result); - return result; - } - - private Typeface load(String fontFamilyName) { - AssetManager assets = NavigationApplication.instance.getAssets(); - try { - List fonts = Arrays.asList(assets.list("fonts")); - if (fonts.contains(fontFamilyName + ".ttf")) { - return Typeface.createFromAsset(assets, "fonts/" + fontFamilyName + ".ttf"); - } - - if (fonts.contains(fontFamilyName + ".otf")) { - return Typeface.createFromAsset(assets, "fonts/" + fontFamilyName + ".otf"); - } - } catch (IOException e) { - e.printStackTrace(); - } - return Typeface.create(fontFamilyName, Typeface.NORMAL); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/TypefaceSpan.java b/android/app/src/main/java/com/reactnativenavigation/utils/TypefaceSpan.java deleted file mode 100644 index 9edc9f6a9e0..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/TypefaceSpan.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.graphics.Paint; -import android.graphics.Typeface; -import android.text.TextPaint; -import android.text.style.MetricAffectingSpan; - -public class TypefaceSpan extends MetricAffectingSpan { - private Typeface mTypeface; - - public TypefaceSpan(Typeface typeface) { - mTypeface = typeface; - } - - @Override - public void updateMeasureState(TextPaint p) { - p.setTypeface(mTypeface); - p.setFlags(p.getFlags() | Paint.SUBPIXEL_TEXT_FLAG); - } - - @Override - public void updateDrawState(TextPaint tp) { - tp.setTypeface(mTypeface); - tp.setFlags(tp.getFlags() | Paint.SUBPIXEL_TEXT_FLAG); - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java b/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java deleted file mode 100644 index cbc0fb50da9..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/ViewUtils.java +++ /dev/null @@ -1,214 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.app.Activity; -import android.content.res.Resources; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.support.annotation.Nullable; -import android.text.SpannableString; -import android.text.Spanned; -import android.text.SpannedString; -import android.text.style.ForegroundColorSpan; -import android.util.DisplayMetrics; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.ViewTreeObserver; -import android.widget.RelativeLayout; -import android.widget.TextView; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.AppStyle; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.views.utils.Point; - -import java.util.concurrent.atomic.AtomicInteger; - -public class ViewUtils { - private static final AtomicInteger viewId = new AtomicInteger(1); - private static int statusBarHeight = -1; - private static int toolBarHeight = -1; - - public static void runOnPreDraw(final View view, final Runnable task) { - view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - if (!view.getViewTreeObserver().isAlive()) { - return true; - } - view.getViewTreeObserver().removeOnPreDrawListener(this); - task.run(); - return true; - } - }); - } - - public static void tintDrawable(Drawable drawable, int tint, boolean enabled) { - drawable.setColorFilter(new PorterDuffColorFilter(enabled ? tint : - AppStyle.appStyle.titleBarDisabledButtonColor.getColor(), - PorterDuff.Mode.SRC_IN)); - } - - public static float convertDpToPixel(float dp) { - float scale = NavigationApplication.instance.getResources().getDisplayMetrics().density; - return dp * scale + 0.5f; - } - - public static float convertPixelToSp(float pixels) { - float scaledDensity = NavigationApplication.instance.getResources().getDisplayMetrics().scaledDensity; - return pixels / scaledDensity; - } - - public static float convertSpToPixel(float pixels) { - float scaledDensity = NavigationApplication.instance.getResources().getDisplayMetrics().scaledDensity; - return pixels * scaledDensity; - } - - public static int generateViewId() { - if (Build.VERSION.SDK_INT >= 17) { - return View.generateViewId(); - } else { - return compatGenerateViewId(); - } - } - - public static float getWindowWidth(Activity activity) { - DisplayMetrics metrics = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); - return metrics.widthPixels; - } - - public static float getWindowHeight(Activity activity) { - DisplayMetrics metrics = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); - return metrics.heightPixels; - } - - private static int compatGenerateViewId() { - for (; ; ) { - final int result = viewId.get(); - // aapt-generated IDs have the high byte nonzero; clamp to the range under that. - int newValue = result + 1; - if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. - if (viewId.compareAndSet(result, newValue)) { - return result; - } - } - } - - public interface Matcher { - boolean match(T child); - } - - /** - * Returns the first instance of clazz in root - */ - @Nullable - public static T findChildByClass(ViewGroup root, Class clazz) { - return findChildByClass(root, clazz, null); - } - - @Nullable - public static T findChildByClass(ViewGroup root, Class clazz, Matcher matcher) { - for (int i = 0; i < root.getChildCount(); i++) { - View view = root.getChildAt(i); - if (clazz.isAssignableFrom(view.getClass()) && (matcher == null || matcher.match((T) view))) { - return (T) view; - } - - if (view instanceof ViewGroup) { - view = (View) findChildByClass((ViewGroup) view, clazz, matcher); - if (view != null && clazz.isAssignableFrom(view.getClass())) { - if (matcher == null) { - return (T) view; - } - if (matcher.match((T) view)) { - return (T) view; - } - } - } - } - return null; - } - - public static void performOnChildren(ViewGroup root, PerformOnViewTask task) { - for (int i = 0; i < root.getChildCount(); i++) { - View child = root.getChildAt(i); - if (child instanceof ViewGroup) { - performOnChildren((ViewGroup) child, task); - } - task.runOnView(child); - } - } - - public interface PerformOnViewTask { - void runOnView(View view); - } - - public static void performOnParentScreen(View child, Task task) { - Screen parentScreen = findParentScreen(child.getParent()); - if (parentScreen != null) { - task.run(parentScreen); - } - } - - private static Screen findParentScreen(ViewParent parent) { - if (parent == null) { - return null; - } - if (parent instanceof Screen) { - return (Screen) parent; - } - return findParentScreen(parent.getParent()); - } - - public static Point getLocationOnScreen(View view) { - int[] xy = new int[2]; - view.getLocationOnScreen(xy); - xy[1] -= getStatusBarHeight(); - return new Point(xy[0], xy[1]); - } - - public static int getStatusBarHeight() { - if (statusBarHeight > 0) { - return statusBarHeight; - } - final Resources resources = NavigationApplication.instance.getResources(); - final int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); - statusBarHeight = resourceId > 0 ? - resources.getDimensionPixelSize(resourceId) : - (int) convertDpToPixel(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? 24 : 25); - return statusBarHeight; - } - - public static int getToolBarHeight() { - if (toolBarHeight > 0) { - return toolBarHeight; - } - final Resources resources = NavigationApplication.instance.getResources(); - final int resourceId = resources.getIdentifier("action_bar_size", "dimen", "android"); - toolBarHeight = resourceId > 0 ? - resources.getDimensionPixelSize(resourceId) : - (int) convertDpToPixel(56); - return toolBarHeight; - } - - - public static ForegroundColorSpan[] getForegroundColorSpans(TextView view) { - SpannedString text = new SpannedString(view.getText()); - return text.getSpans(0, text.length(), ForegroundColorSpan.class); - } - - public static void setSpanColor(SpannableString span, int color) { - span.setSpan(new ForegroundColorSpan(color), 0, span.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } - - public static void removeRuleCompat(RelativeLayout.LayoutParams layoutParams, int rule) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - layoutParams.removeRule(rule); - } else { - layoutParams.addRule(rule, 0); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/utils/ViewVisibilityChecker.java b/android/app/src/main/java/com/reactnativenavigation/utils/ViewVisibilityChecker.java deleted file mode 100644 index 763157ad6e4..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/utils/ViewVisibilityChecker.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.reactnativenavigation.utils; - -import android.support.annotation.Nullable; -import android.view.View; - -import com.reactnativenavigation.views.ContentView; - -public class ViewVisibilityChecker { - - public static boolean check(@Nullable View view) { - if (view == null) { - return false; - } - final int top = getTopRelativeToContentView(view); - final int scrollYInScreen = getScrollYInScreen(view); - return top + view.getHeight() > scrollYInScreen; - } - - private static int getTopRelativeToContentView(View view) { - return view instanceof ContentView ? 0 : view.getTop() + getTopRelativeToContentView((View) view.getParent()); - } - - private static int getScrollYInScreen(View view) { - return view instanceof ContentView ? 0 : view.getScrollY() + getScrollYInScreen((View) view.getParent()); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/BottomTabs.java b/android/app/src/main/java/com/reactnativenavigation/views/BottomTabs.java deleted file mode 100644 index 7ca224e6edc..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/BottomTabs.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.graphics.Color; -import android.text.TextUtils; - -import com.aurelhubert.ahbottomnavigation.AHBottomNavigation; -import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem; -import com.reactnativenavigation.animation.VisibilityAnimator; -import com.reactnativenavigation.params.AppStyle; -import com.reactnativenavigation.params.ScreenParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.utils.Constants; - -import java.util.List; - -public class BottomTabs extends AHBottomNavigation { - - private VisibilityAnimator visibilityAnimator; - - public BottomTabs(Context context) { - super(context); - setForceTint(true); - setId(ViewUtils.generateViewId()); - createVisibilityAnimator(); - setStyle(); - setFontFamily(); - } - - public void addTabs(List params, OnTabSelectedListener onTabSelectedListener) { - for (ScreenParams screenParams : params) { - AHBottomNavigationItem item = new AHBottomNavigationItem(screenParams.tabLabel, screenParams.tabIcon, - Color.GRAY); - addItem(item); - setOnTabSelectedListener(onTabSelectedListener); - } - setTitlesDisplayState(); - } - - public void setStyleFromScreen(StyleParams params) { - if (params.bottomTabsColor.hasColor()) { - setBackgroundColor(params.bottomTabsColor); - } - if (params.bottomTabsButtonColor.hasColor()) { - if (getInactiveColor() != params.bottomTabsButtonColor.getColor()) { - setInactiveColor(params.bottomTabsButtonColor.getColor()); - } - } - if (params.selectedBottomTabsButtonColor.hasColor()) { - if (getAccentColor() != params.selectedBottomTabsButtonColor.getColor()) { - setAccentColor(params.selectedBottomTabsButtonColor.getColor()); - } - } - - setVisibility(params.bottomTabsHidden, true); - } - - public void setTabButton(ScreenParams params, Integer index) { - if (params.tabIcon != null || params.tabLabel != null) { - AHBottomNavigationItem item = this.getItem(index); - boolean tabNeedsRefresh = false; - - if (params.tabIcon != null) { - item.setDrawable(params.tabIcon); - tabNeedsRefresh = true; - } - if (params.tabLabel != null) { - item.setTitle(params.tabLabel); - tabNeedsRefresh = true; - } - - if (tabNeedsRefresh) { - this.refresh(); - } - } - } - - private void setTitlesDisplayState() { - if (AppStyle.appStyle.forceTitlesDisplay) { - setTitleState(TitleState.ALWAYS_SHOW); - } else if (hasTabsWithLabels()) { - setTitleState(TitleState.SHOW_WHEN_ACTIVE); - } else { - setTitleState(TitleState.ALWAYS_HIDE); - } - } - - private boolean hasTabsWithLabels() { - for (int i = 0; i < getItemsCount(); i++) { - String title = getItem(i).getTitle(getContext()); - if (!TextUtils.isEmpty(title)) { - return true; - } - } - return false; - } - - public void setVisibilityByInitialScreen(StyleParams styleParams) { - setVisibility(styleParams.bottomTabsHidden, false); - } - - public void setVisibility(boolean hidden, boolean animated) { - if (visibilityAnimator != null) { - visibilityAnimator.setVisible(!hidden, animated, null); - } else { - setVisibility(hidden); - } - } - - public void setCurrentItemWithoutInvokingTabSelectedListener(Integer index) { - setCurrentItem(index, false); - } - - private void setBackgroundColor(StyleParams.Color bottomTabsColor) { - if (bottomTabsColor.hasColor()) { - if (bottomTabsColor.getColor() != getDefaultBackgroundColor()) { - setDefaultBackgroundColor(bottomTabsColor.getColor()); - } - } else if (Color.WHITE != getDefaultBackgroundColor()){ - setDefaultBackgroundColor(Color.WHITE); - } - } - - private void setVisibility(boolean bottomTabsHidden) { - setVisibility(bottomTabsHidden ? GONE : VISIBLE); - } - - private void createVisibilityAnimator() { - visibilityAnimator = new VisibilityAnimator(BottomTabs.this, - VisibilityAnimator.HideDirection.Down, - Constants.BOTTOM_TABS_HEIGHT); - } - - private void setStyle() { - if (hasBadgeBackgroundColor()) { - setNotificationBackgroundColor(AppStyle.appStyle.bottomTabBadgeBackgroundColor.getColor()); - } - if (hasBadgeTextColor()) { - setNotificationTextColor(AppStyle.appStyle.bottomTabBadgeTextColor.getColor()); - } - } - - private boolean hasBadgeTextColor() { - return AppStyle.appStyle.bottomTabBadgeTextColor != null && - AppStyle.appStyle.bottomTabBadgeTextColor.hasColor(); - } - - private boolean hasBadgeBackgroundColor() { - return AppStyle.appStyle.bottomTabBadgeBackgroundColor != null && - AppStyle.appStyle.bottomTabBadgeBackgroundColor.hasColor(); - } - - private void setFontFamily() { - if (AppStyle.appStyle.bottomTabFontFamily.hasFont()) { - setTitleTypeface(AppStyle.appStyle.bottomTabFontFamily.get()); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/CollapsingContentView.java b/android/app/src/main/java/com/reactnativenavigation/views/CollapsingContentView.java deleted file mode 100644 index 93ca5b90d48..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/CollapsingContentView.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.reactnativenavigation.views; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.support.annotation.Nullable; -import android.view.MotionEvent; -import android.view.View; - -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.views.collapsingToolbar.CollapseAmount; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingView; -import com.reactnativenavigation.views.collapsingToolbar.CollapsingViewMeasurer; -import com.reactnativenavigation.views.collapsingToolbar.OnScrollViewAddedListener; -import com.reactnativenavigation.views.collapsingToolbar.ScrollListener; -import com.reactnativenavigation.views.collapsingToolbar.ScrollViewDelegate; -import com.reactnativenavigation.views.collapsingToolbar.ViewCollapser; -import com.reactnativenavigation.views.utils.ScrollViewDetector; - -@SuppressLint("ViewConstructor") -public class CollapsingContentView extends ContentView implements CollapsingView { - - private @Nullable ScrollViewDelegate scrollViewDelegate; - private @Nullable ScrollViewDetector scrollViewDetector; - private final ViewCollapser viewCollapser; - - public CollapsingContentView(Context context, String screenId, NavigationParams navigationParams) { - super(context, screenId, navigationParams); - viewCollapser = new ViewCollapser(this); - } - - public void setupCollapseDetection(ScrollListener scrollListener, OnScrollViewAddedListener onScrollViewAddedListener) { - scrollViewDelegate = new ScrollViewDelegate(scrollListener); - scrollViewDetector = new ScrollViewDetector(this, onScrollViewAddedListener, scrollViewDelegate); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - if (scrollViewDelegate != null && scrollViewDelegate.hasScrollView()) { - boolean consumed = scrollViewDelegate.didInterceptTouchEvent(ev); - if (consumed) { - return true; - } - } - return super.dispatchTouchEvent(ev); - } - - @Override - public void onViewAdded(final View child) { - super.onViewAdded(child); - if (scrollViewDetector != null) { - scrollViewDetector.findScrollView(child); - } - } - - @Override - public void collapse(CollapseAmount amount) { - viewCollapser.collapse(amount); - } - - @Override - public void fling(CollapseAmount amount) { - viewCollapser.fling(amount); - } - - public void destroy() { - if (scrollViewDetector != null) { - scrollViewDetector.destroy(); - } - if (scrollViewDelegate != null) { - scrollViewDelegate.destroy(); - } - } - - @Override - public float getFinalCollapseValue() { - return ((CollapsingViewMeasurer) viewMeasurer).getFinalCollapseValue(); - } - - @Override - public float getCurrentCollapseValue() { - return getTranslationY(); - } - - @Override - public View asView() { - return this; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/ContentView.java b/android/app/src/main/java/com/reactnativenavigation/views/ContentView.java deleted file mode 100644 index 978d7734a2a..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/ContentView.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.os.Bundle; -import android.view.View; - -import com.facebook.react.ReactRootView; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.screens.SingleScreen; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.utils.ViewMeasurer; - -public class ContentView extends ReactRootView { - private final String screenId; - private final NavigationParams navigationParams; - private Bundle initialProps; - - boolean isContentVisible = false; - private SingleScreen.OnDisplayListener onDisplayListener; - protected ViewMeasurer viewMeasurer; - - public void setOnDisplayListener(SingleScreen.OnDisplayListener onDisplayListener) { - this.onDisplayListener = onDisplayListener; - } - - public ContentView(Context context, String screenId, NavigationParams navigationParams) { - this(context, screenId, navigationParams, Bundle.EMPTY); - } - - public ContentView(Context context, String screenId, NavigationParams navigationParams, Bundle initialProps) { - super(context); - this.screenId = screenId; - this.navigationParams = navigationParams; - this.initialProps = initialProps; - attachToJS(); - viewMeasurer = new ViewMeasurer(); - } - - public void setViewMeasurer(ViewMeasurer viewMeasurer) { - this.viewMeasurer = viewMeasurer; - } - - private void attachToJS() { - navigationParams.toBundle().putAll(initialProps); - startReactApplication(NavigationApplication.instance.getReactGateway().getReactInstanceManager(), - screenId, - createInitialParams() - ); - } - - private Bundle createInitialParams() { - final Bundle params = new Bundle(); - params.putAll(navigationParams.toBundle()); - params.putAll(initialProps); - return params; - } - - public String getNavigatorEventId() { - return navigationParams.navigatorEventId; - } - - public void unmountReactView() { - unmountReactApplication(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST); - int heightSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST); - - super.onMeasure(widthSpec, heightSpec); - - int measuredHeight = viewMeasurer.getMeasuredHeight(heightSpec); - setMeasuredDimension(viewMeasurer.getMeasuredWidth(widthSpec), measuredHeight); - } - - @Override - public void onViewAdded(final View child) { - super.onViewAdded(child); - detectContentViewVisible(child); - } - - private void detectContentViewVisible(View child) { - if (onDisplayListener != null) { - ViewUtils.runOnPreDraw(child, new Runnable() { - @Override - public void run() { - if (!isContentVisible) { - isContentVisible = true; - onDisplayListener.onDisplay(); - onDisplayListener = null; - } - } - }); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/ContextualMenu.java b/android/app/src/main/java/com/reactnativenavigation/views/ContextualMenu.java deleted file mode 100644 index 4f718cb0dde..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/ContextualMenu.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.view.Menu; -import android.view.ViewManager; - -import com.facebook.react.bridge.Callback; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.events.ContextualMenuHiddenEvent; -import com.reactnativenavigation.events.EventBus; -import com.reactnativenavigation.params.ContextualMenuButtonParams; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; - -import java.util.List; - -public class ContextualMenu extends TitleBar implements LeftButtonOnClickListener, ContextualMenuButton.ContextualButtonClickListener { - private ContextualMenuParams params; - private Callback onButtonClicked; - private final String navigatorEventId; - - public ContextualMenu(Context context, ContextualMenuParams params, StyleParams styleParams, Callback onButtonClicked) { - super(context); - this.params = params; - this.onButtonClicked = onButtonClicked; - navigatorEventId = params.navigationParams.navigatorEventId; - setStyle(styleParams); - setButtons(); - } - - public void setStyle(StyleParams styleParams) { - params.setButtonsColor(styleParams.contextualMenuButtonsColor); - if (styleParams.contextualMenuBackgroundColor.hasColor()) { - setBackgroundColor(styleParams.contextualMenuBackgroundColor.getColor()); - } - } - - public void setButtons() { - addButtonsToContextualMenu(params.buttons, getMenu()); - setBackButton(params.leftButton); - } - - private void setBackButton(TitleBarLeftButtonParams leftButton) { - setLeftButton(leftButton, this, null, false); - } - - private void addButtonsToContextualMenu(List buttons, Menu menu) { - for (int i = 0; i < buttons.size(); i++) { - final TitleBarButton button = new ContextualMenuButton(menu, this, buttons.get(i), this); - addButtonInReverseOrder(buttons, i, button); - } - } - - @Override - public boolean onTitleBarBackButtonClick() { - dismiss(); - EventBus.instance.post(new ContextualMenuHiddenEvent()); - return true; - } - - @Override - public void onSideMenuButtonClick() { - // nothing - } - - @Override - public void onClick(int index) { - dismiss(); - EventBus.instance.post(new ContextualMenuHiddenEvent()); - onButtonClicked.invoke(index); - } - - public void dismiss() { - hide(new Runnable() { - @Override - public void run() { - ((ViewManager) getParent()).removeView(ContextualMenu.this); - } - }); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("contextualMenuDismissed", navigatorEventId); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/ContextualMenuButton.java b/android/app/src/main/java/com/reactnativenavigation/views/ContextualMenuButton.java deleted file mode 100644 index 5b23203dd8c..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/ContextualMenuButton.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.reactnativenavigation.views; - -import android.view.Menu; -import android.view.MenuItem; -import android.view.ViewGroup; - -import com.reactnativenavigation.params.ContextualMenuButtonParams; - -class ContextualMenuButton extends TitleBarButton { - private ContextualMenuButtonParams contextualMenuButtonParams; - private ContextualButtonClickListener contextualButtonClickListener; - - interface ContextualButtonClickListener { - void onClick(int index); - } - - ContextualMenuButton(Menu menu, ViewGroup parent, ContextualMenuButtonParams contextualMenuButtonParams, ContextualButtonClickListener contextualButtonClickListener) { - super(menu, parent, contextualMenuButtonParams, null); - this.contextualMenuButtonParams = contextualMenuButtonParams; - this.contextualButtonClickListener = contextualButtonClickListener; - } - - @Override - public boolean onMenuItemClick(MenuItem item) { - contextualButtonClickListener.onClick(contextualMenuButtonParams.index); - return true; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonAnimator.java b/android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonAnimator.java deleted file mode 100644 index bba08689006..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonAnimator.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.reactnativenavigation.views; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.support.design.widget.FloatingActionButton; -import android.view.View; -import android.view.animation.DecelerateInterpolator; - -import java.util.List; - -public class FloatingActionButtonAnimator { - private static final int SHOW_DURATION = 120; - private static final int HIDE_DURATION = 120; - private static final float SCALE = 0.6f; - private static final int ANGLE = 90; - private static final DecelerateInterpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(1.5f); - - private final FloatingActionButton collapsedFab; - private final FloatingActionButton expendedFab; - - FloatingActionButtonAnimator(FloatingActionButton collapsedFab, FloatingActionButton expendedFab) { - this.collapsedFab = collapsedFab; - this.expendedFab = expendedFab; - } - - void show() { - collapsedFab.setScaleX(SCALE); - collapsedFab.setScaleY(SCALE); - collapsedFab.setAlpha(0.0f); - collapsedFab.setAlpha(0.0f); - collapsedFab.animate() - .alpha(1) - .scaleX(1) - .scaleY(1) - .setInterpolator(DECELERATE_INTERPOLATOR) - .setDuration(SHOW_DURATION) - .start(); - } - - public void collapse() { - hideExpended(); - showCollapsed(); - } - - void hideCollapsed() { - animateFab(collapsedFab, 0, ANGLE); - } - - void showExpended() { - animateFab(expendedFab, 1, 0); - } - - private void showCollapsed() { - animateFab(collapsedFab, 1, 0); - collapsedFab.bringToFront(); - } - - private void hideExpended() { - animateFab(expendedFab, 0, -ANGLE); - } - - private void animateFab(final FloatingActionButton fab, final int alpha, int rotation) { - fab.animate() - .alpha(alpha) - .setDuration(HIDE_DURATION) - .rotation(rotation) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - if (fab.getVisibility() == View.GONE) { - fab.setVisibility(View.VISIBLE); - } - } - - @Override - public void onAnimationEnd(Animator animation) { - fab.setVisibility(alpha == 0 ? View.GONE : View.VISIBLE); - } - }) - .start(); - } - - void removeFabFromScreen(FloatingActionButton fab, final AnimatorListenerAdapter animationListener) { - if (fab == null) { - return; - } - fab.animate() - .alpha(0) - .scaleX(SCALE) - .scaleY(SCALE) - .setDuration(HIDE_DURATION) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (animationListener != null) { - animationListener.onAnimationEnd(animation); - } - } - }) - .start(); - } - - void removeActionsFromScreen(List actions) { - for (FloatingActionButton action : actions) { - action.animate() - .alpha(0) - .scaleX(0) - .scaleY(0) - .setDuration(HIDE_DURATION) - .start(); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonCoordinator.java b/android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonCoordinator.java deleted file mode 100644 index 042149ed4a1..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/FloatingActionButtonCoordinator.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.reactnativenavigation.views; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.content.res.ColorStateList; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.support.annotation.FloatRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.CoordinatorLayout; -import android.support.design.widget.FloatingActionButton; -import android.view.Gravity; -import android.view.View; - -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.FabActionParams; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.utils.ViewUtils; - -import java.util.ArrayList; - -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; - -class FloatingActionButtonCoordinator { - private static final String TAG = "FloatingActionButtonCoo"; - private static final int INITIAL_EXPENDED_FAB_ROTATION = -90; - private CoordinatorLayout parent; - private FabParams params; - private FloatingActionButton collapsedFab; - private FloatingActionButton expendedFab; - private final int actionSize; - private final int margin = (int) ViewUtils.convertDpToPixel(16); - private FloatingActionButtonAnimator fabAnimator; - private final ArrayList actions; - - FloatingActionButtonCoordinator(CoordinatorLayout parent) { - this.parent = parent; - actions = new ArrayList<>(); - actionSize = (int) ViewUtils.convertDpToPixel(40); - } - - public void add(final FabParams params) { - if (hasFab()) { - remove(new Runnable() { - @Override - public void run() { - add(params); - } - }); - return; - } - - this.params = params; - if (!params.isValid()) { - return; - } - createCollapsedFab(); - createExpendedFab(); - setStyle(); - fabAnimator = new FloatingActionButtonAnimator(collapsedFab, expendedFab); - fabAnimator.show(); - } - - void remove(@Nullable final Runnable onComplete) { - if (!hasFab()) { - if (onComplete != null) { - onComplete.run(); - } - return; - } - if (fabAnimator != null) { - fabAnimator.removeFabFromScreen(expendedFab, new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - removeAllViews(); - if (onComplete != null) { - onComplete.run(); - } - } - }); - fabAnimator.removeFabFromScreen(collapsedFab, null); - fabAnimator.removeActionsFromScreen(actions); - } - - } - - private boolean hasFab() { - return collapsedFab != null || expendedFab != null; - } - - private void removeAllViews() { - parent.removeView(collapsedFab); - parent.removeView(expendedFab); - collapsedFab = null; - expendedFab = null; - for (FloatingActionButton action : actions) { - ((CoordinatorLayout.LayoutParams) action.getLayoutParams()).setBehavior(null); - parent.removeView(action); - } - actions.clear(); - } - - private void createCollapsedFab() { - collapsedFab = createFab(params.collapsedIcon); - parent.addView(collapsedFab, createFabLayoutParams()); - collapsedFab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (params.hasExpendedState()) { - fabAnimator.hideCollapsed(); - fabAnimator.showExpended(); - showActions(); - } - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(params.collapsedId, params.navigatorEventId); - } - }); - } - - private void createExpendedFab() { - expendedFab = createFab(params.expendedIcon); - parent.addView(expendedFab, createFabLayoutParams()); - expendedFab.setVisibility(View.GONE); - expendedFab.setRotation(INITIAL_EXPENDED_FAB_ROTATION); - expendedFab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - fabAnimator.collapse(); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(params.expendedId, params.navigatorEventId); - } - }); - } - - private FloatingActionButton createFab(Drawable icon) { - FloatingActionButton fab = new FloatingActionButton(parent.getContext()); - fab.setId(ViewUtils.generateViewId()); - fab.setImageDrawable(icon); - return fab; - } - - private CoordinatorLayout.LayoutParams createFabLayoutParams() { - final CoordinatorLayout.LayoutParams lp = new CoordinatorLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - lp.gravity = Gravity.RIGHT | Gravity.BOTTOM; - lp.bottomMargin = margin; - lp.rightMargin = margin; - lp.topMargin = margin; - return lp; - } - - private void setStyle() { - collapsedFab.setBackgroundTintList(ColorStateList.valueOf(params.backgroundColor.getColor())); - expendedFab.setBackgroundTintList(ColorStateList.valueOf(params.backgroundColor.getColor())); - } - - private void showActions() { - if (actions.size() > 0) { - return; - } - - for (int i = 0; i < params.actions.size(); i++) { - FloatingActionButton action = createAction(i); - actions.add(action); - parent.addView(action); - } - } - - private FloatingActionButton createAction(int index) { - final FabActionParams actionParams = params.actions.get(index); - FloatingActionButton action = createFab(actionParams.icon); - action.setLayoutParams(createActionLayoutParams(index)); - action.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(actionParams.id, actionParams.navigatorEventId); - fabAnimator.collapse(); - } - }); - if (actionParams.backgroundColor.hasColor()) { - action.setBackgroundTintList(ColorStateList.valueOf(actionParams.backgroundColor.getColor())); - } - action.setSize(FloatingActionButton.SIZE_MINI); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - action.setCompatElevation(0); - } - return action; - } - - @NonNull - private CoordinatorLayout.LayoutParams createActionLayoutParams(int actionIndex) { - CoordinatorLayout.LayoutParams lp = new CoordinatorLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - lp.setAnchorId(expendedFab.getId()); - lp.anchorGravity = Gravity.CENTER_HORIZONTAL; - lp.setBehavior(new ActionBehaviour(expendedFab, (actionIndex + 1) * (actionSize + margin / 2))); - return lp; - } - - private static class ActionBehaviour extends CoordinatorLayout.Behavior { - private final int MAX_VALUE = 90; - private int dependencyId; - private float yStep; - - ActionBehaviour(View anchor, float yStep) { - this.yStep = yStep; - this.dependencyId = anchor.getId(); - } - - @Override - public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton child, View dependency) { - return dependency.getId() == dependencyId; - } - - @Override - public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child, View dependency) { - final View dependentView = parent.findViewById(dependencyId); - if (dependentView == null) { - return false; - } - final float dependentValue = dependency.getRotation(); - float fraction = calculateTransitionFraction(dependentValue); - child.setY(calculateY(dependentView, fraction)); - child.setAlpha(calculateAlpha(fraction)); - setVisibility(child); - return true; - } - - private void setVisibility(FloatingActionButton child) { - child.setVisibility(child.getAlpha() == 0 ? View.GONE : View.VISIBLE); - } - - private float calculateAlpha(float fraction) { - return 1 * fraction; - } - - private float calculateY(View dependentView, float fraction) { - return dependentView.getY() - yStep * fraction; - } - - @FloatRange(from=0.0, to=1.0) - private float calculateTransitionFraction(float dependentValue) { - return 1 - Math.abs(dependentValue / MAX_VALUE); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/LeftButton.java b/android/app/src/main/java/com/reactnativenavigation/views/LeftButton.java deleted file mode 100644 index 20b257b846c..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/LeftButton.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.graphics.Color; -import android.view.View; - -import com.balysv.materialmenu.MaterialMenuDrawable; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.utils.ViewUtils; - -class LeftButton extends MaterialMenuDrawable implements View.OnClickListener { - - private static int getColor(TitleBarButtonParams params) { - return params != null && params.color.hasColor() ? - params.color.getColor() : - Color.BLACK; - } - - private TitleBarLeftButtonParams params; - private final LeftButtonOnClickListener onClickListener; - private String navigatorEventId; - private final boolean overrideBackPressInJs; - - LeftButton(Context context, - TitleBarLeftButtonParams params, - LeftButtonOnClickListener onClickListener, - String navigatorEventId, - boolean overrideBackPressInJs) { - super(context, getColor(params), Stroke.THIN); - this.params = params; - this.onClickListener = onClickListener; - this.navigatorEventId = navigatorEventId; - this.overrideBackPressInJs = overrideBackPressInJs; - setInitialState(); - setColor(); - } - - void setIconState(TitleBarLeftButtonParams params) { - this.params = params; - setColor(); - animateIconState(params.iconState); - } - - void setCustomIcon(TitleBarLeftButtonParams params) { - this.params = params; - setColor(); - } - - @Override - public void onClick(View v) { - if (isBackButton()) { - handleBackButtonClick(); - } else if (isSideMenuButton()) { - onClickListener.onSideMenuButtonClick(); - } else { - sendClickEvent(); - } - } - - private void handleBackButtonClick() { - if (overrideBackPressInJs) { - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent("backPress", navigatorEventId); - } else { - onClickListener.onTitleBarBackButtonClick(); - } - } - - private void setInitialState() { - if (params != null) { - if (params.iconState != null) { - setIconState(params.iconState); - } - } else { - setVisible(false); - } - } - - private void setColor() { - if (!params.color.hasColor()) { - return; - } - if (params.hasDefaultIcon()) { - setColor(params.color.getColor()); - } else if (params.hasCustomIcon()) { - ViewUtils.tintDrawable(params.icon, params.color.getColor(), true); - } - } - - @Override - public void setColor(int color) { - if (params.hasDefaultIcon()) { - super.setColor(color); - } else { - ViewUtils.tintDrawable(params.icon, color, true ); - } - } - - private boolean isBackButton() { - return params.hasDefaultIcon() && getIconState() == IconState.ARROW; - } - - private boolean isSideMenuButton() { - return params.hasDefaultIcon() && getIconState() == IconState.BURGER; - } - - private void sendClickEvent() { - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(params.eventId, navigatorEventId); - } - - void updateNavigatorEventId(String navigatorEventId) { - this.navigatorEventId = navigatorEventId; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/LeftButtonOnClickListener.java b/android/app/src/main/java/com/reactnativenavigation/views/LeftButtonOnClickListener.java deleted file mode 100644 index 2ad93a55b13..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/LeftButtonOnClickListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.reactnativenavigation.views; - -public interface LeftButtonOnClickListener { - boolean onTitleBarBackButtonClick(); - - void onSideMenuButtonClick(); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/LightBox.java b/android/app/src/main/java/com/reactnativenavigation/views/LightBox.java deleted file mode 100644 index e41c78ede10..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/LightBox.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.reactnativenavigation.views; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.graphics.Color; -import android.os.Build; -import android.support.v4.view.animation.FastOutSlowInInterpolator; -import android.support.v7.app.AppCompatActivity; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.widget.RelativeLayout; - -import com.reactnativenavigation.R; -import com.reactnativenavigation.params.LightBoxParams; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.ViewUtils; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; - -public class LightBox extends Dialog implements DialogInterface.OnDismissListener { - - private Runnable onDismissListener; - private ContentView content; - private RelativeLayout lightBox; - private boolean cancelable; - - public LightBox(AppCompatActivity activity, Runnable onDismissListener, LightBoxParams params) { - super(activity, R.style.LightBox); - this.onDismissListener = onDismissListener; - this.cancelable = !params.overrideBackPress; - setOnDismissListener(this); - requestWindowFeature(Window.FEATURE_NO_TITLE); - createContent(activity, params); - setCancelable(cancelable); - getWindow().setWindowAnimations(android.R.style.Animation); - getWindow().setSoftInputMode(params.adjustSoftInput); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - } - } - - private void createContent(final Context context, LightBoxParams params) { - lightBox = new RelativeLayout(context); - lightBox.setAlpha(0); - content = new ContentView(context, params.screenId, params.navigationParams); - content.setAlpha(0); - RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - lp.addRule(RelativeLayout.CENTER_IN_PARENT, content.getId()); - lightBox.setBackgroundColor(params.backgroundColor.getColor()); - lightBox.addView(content, lp); - - if (params.tapBackgroundToDismiss) { - lightBox.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - hide(); - } - }); - } - - content.setOnDisplayListener(new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - content.getLayoutParams().height = content.getChildAt(0).getHeight(); - content.getLayoutParams().width = content.getChildAt(0).getWidth(); - content.setBackgroundColor(Color.TRANSPARENT); - ViewUtils.runOnPreDraw(content, new Runnable() { - @Override - public void run() { - animateShow(); - - } - }); - } - }); - setContentView(lightBox, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); - } - - @Override - public void show() { - super.show(); - } - - @Override - public void hide() { - animateHide(); - } - - @Override public void onBackPressed() { - if (cancelable) { - hide(); - } - } - - @Override - public void onDismiss(DialogInterface dialogInterface) { - onDismissListener.run(); - } - - public void destroy() { - if (content != null) { - content.unmountReactView(); - lightBox.removeAllViews(); - content = null; - } - dismiss(); - } - - private void animateShow() { - ObjectAnimator yTranslation = ObjectAnimator.ofFloat(content, View.TRANSLATION_Y, 80, 0).setDuration(400); - yTranslation.setInterpolator(new FastOutSlowInInterpolator()); - yTranslation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - content.setAlpha(1); - } - }); - - ObjectAnimator lightBoxAlpha = ObjectAnimator.ofFloat(lightBox, View.ALPHA, 0, 1).setDuration(70); - - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether(lightBoxAlpha, yTranslation); - animatorSet.start(); - } - - private void animateHide() { - ObjectAnimator alpha = ObjectAnimator.ofFloat(content, View.ALPHA, 0); - ObjectAnimator yTranslation = ObjectAnimator.ofFloat(content, View.TRANSLATION_Y, 60); - AnimatorSet contentAnimators = new AnimatorSet(); - contentAnimators.playTogether(alpha, yTranslation); - contentAnimators.setDuration(150); - - ObjectAnimator lightBoxAlpha = ObjectAnimator.ofFloat(lightBox, View.ALPHA, 0).setDuration(100); - - AnimatorSet allAnimators = new AnimatorSet(); - allAnimators.playSequentially(contentAnimators, lightBoxAlpha); - allAnimators.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - destroy(); - } - }); - allAnimators.start(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/Scrim.java b/android/app/src/main/java/com/reactnativenavigation/views/Scrim.java deleted file mode 100644 index 796bd3de38b..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/Scrim.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.view.View; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; - -import com.reactnativenavigation.params.StyleParams; - -import static com.reactnativenavigation.views.Scrim.State.Invisible; -import static com.reactnativenavigation.views.Scrim.State.Visible; - -public class Scrim extends View { - enum State {Visible, Invisible} - - private State state = Invisible; - private final float collapseThreshold; - private final static int ANIMATION_DURATION = 600; - private final Interpolator interpolator; - - public Scrim(Context context, StyleParams.Color color, float collapseThreshold) { - super(context); - this.collapseThreshold = collapseThreshold; - setBackgroundColor(color.getColor()); - setAlpha(0); - interpolator = new DecelerateInterpolator(); - } - - public void collapse(float collapse) { - if (shouldShowScrim(collapse)) { - showScrim(); - } else if (shouldHideScrim(collapse)) { - hideScrim(); - } - - } - - private boolean shouldShowScrim(float collapse) { - return Math.abs(collapse) >= collapseThreshold && state == Invisible; - } - - private boolean shouldHideScrim(float collapse) { - return Math.abs(collapse) < collapseThreshold && state == Visible; - } - - private void showScrim() { - state = Visible; - animate() - .alpha(1) - .setDuration(ANIMATION_DURATION) - .setInterpolator(interpolator); - } - - private void hideScrim() { - state = Invisible; - animate() - .alpha(0) - .setDuration(ANIMATION_DURATION) - .setInterpolator(interpolator); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/ScrollDirectionListener.java b/android/app/src/main/java/com/reactnativenavigation/views/ScrollDirectionListener.java deleted file mode 100644 index dbf753cd42f..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/ScrollDirectionListener.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.reactnativenavigation.views; - -import android.view.ViewGroup; -import android.view.ViewTreeObserver; - -public class ScrollDirectionListener implements ViewTreeObserver.OnScrollChangedListener { - public enum Direction { - Up, Down - } - - public interface OnScrollChanged { - void onScrollChanged(Direction direction); - } - - private final ViewGroup view; - private OnScrollChanged onChanged; - private int lastScrollY = -1; - - public ScrollDirectionListener(ViewGroup view, OnScrollChanged onChanged) { - this.view = view; - this.onChanged = onChanged; - } - - @Override - public void onScrollChanged() { - if (!view.getViewTreeObserver().isAlive()) { - return; - } - - final int scrollY = view.getScrollY(); - if (isScrollPositionChanged(scrollY) && !isTopOverscroll(scrollY) && !isBottomOverscroll(scrollY)) { - onChanged.onScrollChanged(getScrollDirection(scrollY)); - lastScrollY = scrollY; - } - } - - private Direction getScrollDirection(int scrollY) { - return scrollY > lastScrollY ? Direction.Down : Direction.Up; - } - - private boolean isBottomOverscroll(int scrollY) { - return scrollY >= (view.getChildAt(0).getHeight() - view.getHeight()); - } - - private boolean isTopOverscroll(int scrollY) { - return scrollY <= 0; - } - - private boolean isScrollPositionChanged(int scrollY) { - return scrollY != lastScrollY; - } - -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/SideMenu.java b/android/app/src/main/java/com/reactnativenavigation/views/SideMenu.java deleted file mode 100644 index 8ada9b67497..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/SideMenu.java +++ /dev/null @@ -1,184 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.support.annotation.Nullable; -import android.support.v4.widget.DrawerLayout; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.RelativeLayout; - -import com.facebook.react.bridge.Callback; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.BaseScreenParams; -import com.reactnativenavigation.params.SideMenuParams; -import com.reactnativenavigation.screens.NavigationType; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.ViewUtils; - -public class SideMenu extends DrawerLayout { - private SideMenuParams leftMenuParams; - private SideMenuParams rightMenuParams; - - public enum Side { - Left(Gravity.LEFT), Right(Gravity.RIGHT); - - int gravity; - - Side(int gravity) { - this.gravity = gravity; - } - - public static Side fromString(String side) { - return "left".equals(side.toLowerCase()) ? Left : Right; - } - } - - private ContentView leftSideMenuView; - private ContentView rightSideMenuView; - private RelativeLayout contentContainer; - private SimpleDrawerListener sideMenuListener; - - public RelativeLayout getContentContainer() { - return contentContainer; - } - - public void destroy() { - removeDrawerListener(sideMenuListener); - destroySideMenu(leftSideMenuView); - destroySideMenu(rightSideMenuView); - } - - private void destroySideMenu(ContentView sideMenuView) { - if (sideMenuView == null) { - return; - } - removeDrawerListener(sideMenuListener); - sideMenuView.unmountReactView(); - removeView(sideMenuView); - } - - public void setVisible(boolean visible, boolean animated, Side side) { - if (visible) { - openDrawer(animated, side); - } - - if (!visible) { - closeDrawer(animated, side); - } - } - - public void setEnabled(boolean enabled, Side side) { - if (enabled) { - setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, side.gravity); - } else { - setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, side.gravity); - } - } - - public void openDrawer(Side side) { - openDrawer(side.gravity); - } - - public void openDrawer(boolean animated, Side side) { - openDrawer(side.gravity, animated); - } - - public void toggleVisible(boolean animated, Side side) { - if (isDrawerOpen(side.gravity)) { - closeDrawer(animated, side); - } else { - openDrawer(animated, side); - } - } - - public void closeDrawer(boolean animated, Side side) { - closeDrawer(side.gravity, animated); - } - - public SideMenu(Context context, SideMenuParams leftMenuParams, SideMenuParams rightMenuParams) { - super(context); - this.leftMenuParams = leftMenuParams; - this.rightMenuParams = rightMenuParams; - createContentContainer(); - leftSideMenuView = createSideMenu(leftMenuParams); - rightSideMenuView = createSideMenu(rightMenuParams); - setStyle(leftMenuParams); - setStyle(rightMenuParams); - setScreenEventListener(); - } - - private void createContentContainer() { - LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - contentContainer = new RelativeLayout(getContext()); - contentContainer.setId(ViewUtils.generateViewId()); - addView(contentContainer, lp); - } - - private ContentView createSideMenu(@Nullable SideMenuParams params) { - if (params == null) { - return null; - } - ContentView sideMenuView = new ContentView(getContext(), params.screenId, params.navigationParams); - LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); - lp.gravity = params.side.gravity; - setSideMenuWidth(sideMenuView, params); - addView(sideMenuView, lp); - return sideMenuView; - } - - private void setSideMenuWidth(final ContentView sideMenuView, @Nullable final SideMenuParams params) { - sideMenuView.setOnDisplayListener(new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - final ViewGroup.LayoutParams lp = sideMenuView.getLayoutParams(); - if (params != null && params.fixedWidth > 0) { - lp.width = params.fixedWidth; - sideMenuView.setLayoutParams(lp); - } else { - NavigationApplication.instance.getUiManagerModule().measure(sideMenuView.getId(), new Callback() { - @Override - public void invoke(Object... args) { - lp.width = sideMenuView.getChildAt(0).getWidth(); - sideMenuView.setLayoutParams(lp); - } - }); - } - } - }); - } - - public void setScreenEventListener() { - sideMenuListener = new SimpleDrawerListener() { - @Override - public void onDrawerOpened(View drawerView) { - NavigationApplication.instance.getEventEmitter().sendWillAppearEvent(getVisibleDrawerScreenParams(), NavigationType.OpenSideMenu); - NavigationApplication.instance.getEventEmitter().sendDidAppearEvent(getVisibleDrawerScreenParams(), NavigationType.OpenSideMenu); - } - - @Override - public void onDrawerClosed(View drawerView) { - NavigationApplication.instance.getEventEmitter().sendWillDisappearEvent(getVisibleDrawerScreenParams((ContentView) drawerView), NavigationType.CloseSideMenu); - NavigationApplication.instance.getEventEmitter().sendDidDisappearEvent(getVisibleDrawerScreenParams((ContentView) drawerView), NavigationType.CloseSideMenu); - } - - private BaseScreenParams getVisibleDrawerScreenParams() { - return isDrawerOpen(Side.Left.gravity) ? leftMenuParams : rightMenuParams; - } - - private BaseScreenParams getVisibleDrawerScreenParams(ContentView drawerView) { - return drawerView == leftSideMenuView ? leftMenuParams : rightMenuParams; - } - }; - addDrawerListener(sideMenuListener); - } - - private void setStyle(SideMenuParams params) { - if (params == null) { - return; - } - if (params.disableOpenGesture) { - setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, params.side.gravity); - } - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/reactnativenavigation/views/SnackbarAndFabContainer.java b/android/app/src/main/java/com/reactnativenavigation/views/SnackbarAndFabContainer.java deleted file mode 100644 index 767bb5e954a..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/SnackbarAndFabContainer.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.support.design.widget.CoordinatorLayout; - -import com.reactnativenavigation.events.Event; -import com.reactnativenavigation.events.EventBus; -import com.reactnativenavigation.events.FabSetEvent; -import com.reactnativenavigation.events.ScreenChangedEvent; -import com.reactnativenavigation.events.Subscriber; -import com.reactnativenavigation.layouts.Layout; -import com.reactnativenavigation.params.FabParams; -import com.reactnativenavigation.params.SnackbarParams; - -public class SnackbarAndFabContainer extends CoordinatorLayout implements Snakbar.OnDismissListener, Subscriber{ - private Snakbar snakbar; - private FloatingActionButtonCoordinator fabCoordinator; - private Layout layout; - - public SnackbarAndFabContainer(Context context, Layout layout) { - super(context); - this.layout = layout; - fabCoordinator = new FloatingActionButtonCoordinator(this); - EventBus.instance.register(this); - } - - public void showSnackbar(final String navigatorEventId, final SnackbarParams params) { - snakbar = new Snakbar(this, navigatorEventId, params); - snakbar.show(); - } - - @Override - public void onDismiss(Snakbar snakbar) { - if (this.snakbar == snakbar) { - this.snakbar = null; - } - } - - public void destroy() { - EventBus.instance.unregister(this); - } - - @Override - public void onEvent(Event event) { - if (ScreenChangedEvent.TYPE.equals(event.getType())) { - onScreenChange(((ScreenChangedEvent) event).fabParams); - } - if (FabSetEvent.TYPE.equals(event.getType())) { - updateFab(((FabSetEvent) event).fabParams); - } - } - - private void onScreenChange(FabParams fabParams) { - dismissSnackbar(); - updateFab(fabParams); - } - - public void dismissSnackbar() { - if (snakbar != null) { - snakbar.dismiss(); - snakbar = null; - } - } - - private void updateFab(final FabParams fabParams) { - fabCoordinator.remove(new Runnable() { - @Override - public void run() { - if (fabParams != null) { - if (layout.getCurrentScreen().getScreenInstanceId().equals(fabParams.screenInstanceId)) { - fabCoordinator.add(fabParams); - } - } - } - }); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/Snakbar.java b/android/app/src/main/java/com/reactnativenavigation/views/Snakbar.java deleted file mode 100644 index 03054e32629..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/Snakbar.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.reactnativenavigation.views; - -import android.support.design.widget.Snackbar; -import android.text.Html; -import android.text.Spanned; -import android.view.View; - -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.SnackbarParams; - -class Snakbar { - private final OnDismissListener parent; - private final String navigatorEventId; - private final SnackbarParams params; - private Snackbar snackbar; - - interface OnDismissListener { - void onDismiss(Snakbar snakbar); - } - - public void show() { - snackbar.show(); - } - - void dismiss() { - snackbar.dismiss(); - } - - public View getView() { - return snackbar.getView(); - } - - Snakbar(OnDismissListener parent, String navigatorEventId, SnackbarParams params) { - this.parent = parent; - this.navigatorEventId = navigatorEventId; - this.params = params; - create(); - } - - private void create() { - snackbar = Snackbar.make((View) parent, getStyledText(), params.duration); - setAction(navigatorEventId, params, snackbar); - setStyle(snackbar, params); - setOnDismissListener(); - } - - private Spanned getStyledText() { - String styledText = "" + - params.text + - ""; - return Html.fromHtml(styledText); - } - - private void setAction(final String navigatorEventId, final SnackbarParams params, Snackbar snackbar) { - if (params.eventId != null) { - snackbar.setAction(params.buttonText, new View.OnClickListener() { - @Override - public void onClick(View v) { - NavigationApplication.instance.getEventEmitter().sendEvent(params.eventId); - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(params.eventId, navigatorEventId); - } - }); - } - } - - private void setStyle(Snackbar snackbar, SnackbarParams params) { - if (params.buttonColor.hasColor()) { - snackbar.setActionTextColor(params.buttonColor.getColor()); - } - if (params.backgroundColor.hasColor()) { - snackbar.getView().setBackgroundColor(params.backgroundColor.getColor()); - } - } - - private void setOnDismissListener() { - snackbar.getView().addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - - } - - @Override - public void onViewDetachedFromWindow(View v) { - parent.onDismiss(Snakbar.this); - } - }); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java b/android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java deleted file mode 100644 index 7b797f8bf37..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/TitleBar.java +++ /dev/null @@ -1,392 +0,0 @@ -package com.reactnativenavigation.views; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.app.Activity; -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.graphics.Typeface; -import android.support.annotation.Nullable; -import android.support.v7.widget.ActionMenuView; -import android.support.v7.widget.Toolbar; -import android.text.TextUtils; -import android.view.Menu; -import android.view.View; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.AccelerateInterpolator; -import android.widget.TextView; - -import com.reactnativenavigation.params.BaseScreenParams; -import com.reactnativenavigation.params.BaseTitleBarButtonParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.utils.ViewUtils; - -import java.util.List; - -public class TitleBar extends Toolbar { - private static final int TITLE_VISIBILITY_ANIMATION_DURATION = 320; - private LeftButton leftButton; - private ActionMenuView actionMenuView; - private List rightButtons; - - public TitleBar(Context context) { - super(context); - } - - @Override - public void onViewAdded(View child) { - super.onViewAdded(child); - if (child instanceof ActionMenuView) { - actionMenuView = (ActionMenuView) child; - } - } - - public void setRightButtons(List rightButtons, String navigatorEventId) { - this.rightButtons = rightButtons; - Menu menu = getMenu(); - menu.clear(); - if (rightButtons == null) { - return; - } - addButtonsToTitleBar(navigatorEventId, menu); - } - - public void setLeftButton(TitleBarLeftButtonParams leftButtonParams, - LeftButtonOnClickListener leftButtonOnClickListener, - String navigatorEventId, - boolean overrideBackPressInJs) { - if (shouldSetLeftButton(leftButtonParams)) { - createAndSetLeftButton(leftButtonParams, leftButtonOnClickListener, navigatorEventId, overrideBackPressInJs); - } else if (hasLeftButton()) { - if (leftButtonParams.hasDefaultIcon() || leftButtonParams.hasCustomIcon()) { - updateLeftButton(leftButtonParams); - } else { - removeLeftButton(); - } - } - } - - private void removeLeftButton() { - setNavigationIcon(null); - leftButton = null; - } - - public void setStyle(StyleParams params) { - setVisibility(params.titleBarHidden); - setTitleTextColor(params); - setTitleTextFont(params); - setTitleTextFontSize(params); - setTitleTextFontWeight(params); - setSubtitleTextColor(params); - setSubtitleFontSize(params); - setSubtitleFont(params); - colorOverflowButton(params); - setBackground(params); - centerTitle(params); - setTopPadding(params); - } - - public void setVisibility(boolean titleBarHidden) { - setVisibility(titleBarHidden ? GONE : VISIBLE); - } - - public void setTitle(String title, StyleParams styleParams) { - setTitle(title); - setTitleTextFont(styleParams); - centerTitle(styleParams); - } - - public void setSubtitle(CharSequence subtitle, StyleParams styleParams) { - super.setSubtitle(subtitle); - setSubtitleFontSize(styleParams); - setSubtitleFont(styleParams); - } - - private void setSubtitleFontSize(StyleParams params) { - TextView subtitleView = getSubtitleView(); - if (subtitleView != null && params.titleBarSubtitleFontSize > 0) { - subtitleView.setTextSize(params.titleBarSubtitleFontSize); - } - } - - private void setSubtitleFont(StyleParams params) { - if (params.titleBarSubtitleFontFamily.hasFont()) { - TextView subtitleView = getSubtitleView(); - if (subtitleView != null) { - subtitleView.setTypeface(params.titleBarSubtitleFontFamily.get()); - } - } - } - - private void centerTitle(final StyleParams params) { - final View titleView = getTitleView(); - if (titleView == null) { - return; - } - ViewUtils.runOnPreDraw(titleView, new Runnable() { - @Override - public void run() { - if (params.titleBarTitleTextCentered) { - titleView.setX(ViewUtils.getWindowWidth((Activity) getContext()) / 2 - titleView.getWidth() / 2); - } - } - }); - } - - private void setTopPadding(final StyleParams params) { - setPadding(0, (int) ViewUtils.convertDpToPixel(params.titleBarTopPadding), 0,0); - } - - private void colorOverflowButton(StyleParams params) { - Drawable overflowIcon = actionMenuView.getOverflowIcon(); - if (shouldColorOverflowButton(params, overflowIcon)) { - ViewUtils.tintDrawable(overflowIcon, params.titleBarButtonColor.getColor(), true); - } - } - - protected void setBackground(StyleParams params) { - setTranslucent(params); - } - - protected void setTranslucent(StyleParams params) { - if (params.topBarTranslucent) { - setBackground(new TranslucentDrawable()); - } - } - - private boolean shouldColorOverflowButton(StyleParams params, Drawable overflowIcon) { - return overflowIcon != null && params.titleBarButtonColor.hasColor(); - } - - protected void setTitleTextColor(StyleParams params) { - if (params.titleBarTitleColor.hasColor()) { - setTitleTextColor(params.titleBarTitleColor.getColor()); - } - } - - protected void setTitleTextFont(StyleParams params) { - if (!params.titleBarTitleFont.hasFont()) { - return; - } - View titleView = getTitleView(); - if (titleView instanceof TextView) { - ((TextView) titleView).setTypeface(params.titleBarTitleFont.get()); - } - } - - protected void setTitleTextFontSize(StyleParams params) { - if (params.titleBarTitleFontSize > 0) { - View titleView = getTitleView(); - if (titleView instanceof TextView) { - ((TextView) titleView).setTextSize(((float) params.titleBarTitleFontSize)); - } - } - } - - protected void setTitleTextFontWeight(StyleParams params) { - if (params.titleBarTitleFontBold) { - View titleView = getTitleView(); - if (titleView instanceof TextView) { - ((TextView) titleView).setTypeface(((TextView) titleView).getTypeface(), Typeface.BOLD); - } - } - } - - protected void setSubtitleTextColor(StyleParams params) { - if (params.titleBarSubtitleColor.hasColor()) { - setSubtitleTextColor(params.titleBarSubtitleColor.getColor()); - } - } - - private void addButtonsToTitleBar(String navigatorEventId, Menu menu) { - for (int i = 0; i < rightButtons.size(); i++) { - final TitleBarButton button = new TitleBarButton(menu, this, rightButtons.get(i), navigatorEventId); - addButtonInReverseOrder(rightButtons, i, button); - } - } - - protected void addButtonInReverseOrder(List buttons, int i, TitleBarButton button) { - final int index = buttons.size() - i - 1; - button.addToMenu(index); - } - - private boolean hasLeftButton() { - return leftButton != null; - } - - private void updateLeftButton(TitleBarLeftButtonParams leftButtonParams) { - if (leftButtonParams.hasDefaultIcon()) { - leftButton.setIconState(leftButtonParams); - setNavigationIcon(leftButton); - } else if (leftButtonParams.hasCustomIcon()) { - leftButton.setCustomIcon(leftButtonParams); - setNavigationIcon(leftButtonParams.icon); - } - } - - private boolean shouldSetLeftButton(TitleBarLeftButtonParams leftButtonParams) { - return leftButton == null && leftButtonParams != null && (leftButtonParams.hasDefaultIcon() || leftButtonParams.hasCustomIcon()); - } - - private void createAndSetLeftButton(TitleBarLeftButtonParams leftButtonParams, - LeftButtonOnClickListener leftButtonOnClickListener, - String navigatorEventId, - boolean overrideBackPressInJs) { - leftButton = new LeftButton(getContext(), leftButtonParams, leftButtonOnClickListener, navigatorEventId, - overrideBackPressInJs); - setNavigationOnClickListener(leftButton); - - if (leftButtonParams.hasCustomIcon()) { - setNavigationIcon(leftButtonParams.icon); - } else { - setNavigationIcon(leftButton); - } - } - - public void hide() { - hide(null); - } - - public void hide(@Nullable final Runnable onHidden) { - animate() - .alpha(0) - .setDuration(200) - .setInterpolator(new AccelerateInterpolator()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onHidden != null) { - onHidden.run(); - } - } - }); - } - - public void show() { - this.show(null); - } - - public void show(final @Nullable Runnable onDisplayed) { - setAlpha(0); - animate() - .alpha(1) - .setDuration(200) - .setInterpolator(new AccelerateDecelerateInterpolator()) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onDisplayed != null) { - onDisplayed.run(); - } - } - }); - } - - public void showTitle() { - animateTitle(1); - } - - public void hideTitle() { - animateTitle(0); - } - - private void animateTitle(int alpha) { - View titleView = getTitleView(); - if (titleView != null) { - titleView.animate() - .alpha(alpha) - .setDuration(TITLE_VISIBILITY_ANIMATION_DURATION); - } - } - - @Nullable - protected View getTitleView() { - return ViewUtils.findChildByClass(this, TextView.class, new ViewUtils.Matcher() { - @Override - public boolean match(TextView child) { - return child.getText().equals(getTitle()); - } - }); - } - - @Nullable - private TextView getSubtitleView() { - if (TextUtils.isEmpty(getSubtitle())) return null; - return ViewUtils.findChildByClass(this, TextView.class, new ViewUtils.Matcher() { - @Override - public boolean match(TextView child) { - return child.getText().equals(getSubtitle()); - } - }); - } - - public void setButtonColor(StyleParams.Color titleBarButtonColor) { - if (!titleBarButtonColor.hasColor()) { - return; - } - updateButtonColor(titleBarButtonColor); - setLeftButtonColor(titleBarButtonColor); - setButtonsIconColor(); - setButtonTextColor(); - } - - private void setLeftButtonColor(StyleParams.Color titleBarButtonColor) { - if (leftButton != null) { - leftButton.setColor(titleBarButtonColor.getColor()); - } - } - - private void updateButtonColor(StyleParams.Color titleBarButtonColor) { - if (rightButtons != null) { - for (TitleBarButtonParams rightButton : rightButtons) { - rightButton.color = titleBarButtonColor; - } - } - } - - private void setButtonTextColor() { - final ActionMenuView buttonsContainer = ViewUtils.findChildByClass(this, ActionMenuView.class); - if (buttonsContainer != null) { - for (int i = 0; i < buttonsContainer.getChildCount(); i++) { - if (buttonsContainer.getChildAt(i) instanceof TextView) { - ((TextView) buttonsContainer.getChildAt(i)).setTextColor(getButton(i).getColor().getColor()); - } - } - } - } - - private void setButtonsIconColor() { - final Menu menu = getMenu(); - for (int i = 0; i < menu.size(); i++) { - if (menu.getItem(i).getIcon() != null) { - ViewUtils.tintDrawable(menu.getItem(i).getIcon(), - getButton(i).getColor().getColor(), - getButton(i).enabled); - } - } - } - - BaseTitleBarButtonParams getButton(int index) { - return rightButtons.get(rightButtons.size() - index - 1); - } - - public void onViewPagerScreenChanged(BaseScreenParams screenParams) { - if (hasLeftButton()) { - leftButton.updateNavigatorEventId(screenParams.getNavigatorEventId()); - } - } - - public void destroy() { - unmountCustomButtons(); - } - - private void unmountCustomButtons() { - for (int i = 0; i < actionMenuView.getChildCount(); i++) { - if (actionMenuView.getChildAt(i) instanceof TitleBarButtonComponent) { - ((ContentView) actionMenuView.getChildAt(i)).unmountReactView(); - } - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/TitleBarBackground.java b/android/app/src/main/java/com/reactnativenavigation/views/TitleBarBackground.java deleted file mode 100644 index 98ca2c5e061..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/TitleBarBackground.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.reactnativenavigation.views; - -import android.graphics.drawable.Drawable; -import android.graphics.drawable.TransitionDrawable; - -public class TitleBarBackground extends TransitionDrawable { - private static final int DURATION = 200; - - private enum DrawableType {Translucent, Solid} - - private DrawableType displayedDrawable = DrawableType.Translucent; - - public TitleBarBackground(Drawable... drawables) { - super(drawables); - setCrossFadeEnabled(true); - } - - public void showTranslucentBackground() { - if (displayedDrawable == DrawableType.Translucent) { - return; - } - displayedDrawable = DrawableType.Translucent; - reverseTransition(DURATION); - } - - public void showSolidBackground() { - if (displayedDrawable == DrawableType.Solid) { - return; - } - displayedDrawable = DrawableType.Solid; - startTransition(DURATION); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/TitleBarButton.java b/android/app/src/main/java/com/reactnativenavigation/views/TitleBarButton.java deleted file mode 100644 index 61384948e39..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/TitleBarButton.java +++ /dev/null @@ -1,152 +0,0 @@ -package com.reactnativenavigation.views; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.widget.ActionMenuView; -import android.text.SpannableStringBuilder; -import android.text.TextUtils; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.utils.TypefaceSpan; -import com.reactnativenavigation.utils.ViewUtils; - -import java.util.ArrayList; - -class TitleBarButton implements MenuItem.OnMenuItemClickListener { - - protected final Menu menu; - protected final ViewGroup parent; - private TitleBarButtonParams buttonParams; - @Nullable protected String navigatorEventId; - - TitleBarButton(Menu menu, ViewGroup parent, TitleBarButtonParams buttonParams, @Nullable String navigatorEventId) { - this.menu = menu; - this.parent = parent; - this.buttonParams = buttonParams; - this.navigatorEventId = navigatorEventId; - } - - MenuItem addToMenu(int index) { - MenuItem item = createMenuItem(index); - item.setShowAsAction(buttonParams.showAsAction.action); - item.setEnabled(buttonParams.enabled); - if (buttonParams.hasComponent()) { - item.setActionView(new TitleBarButtonComponent(parent.getContext(), buttonParams.componentName, buttonParams.componentProps)); - } - setIcon(item, index); - setColor(); - setFont(); - item.setOnMenuItemClickListener(this); - return item; - } - - private MenuItem createMenuItem(int index) { - if (!buttonParams.hasFont() || TextUtils.isEmpty(buttonParams.label)) { - return menu.add(Menu.NONE, Menu.NONE, index, buttonParams.label); - } - TypefaceSpan span = new TypefaceSpan(buttonParams.font.get()); - SpannableStringBuilder title = new SpannableStringBuilder(buttonParams.label); - title.setSpan(span, 0, title.length(), 0); - return menu.add(Menu.NONE, Menu.NONE, index, title); - } - - private void setIcon(MenuItem item, int index) { - if (hasIcon()) { - item.setIcon(buttonParams.icon); - if (TextUtils.isEmpty(buttonParams.label)) { - dontShowLabelOnLongPress(index); - } - } - } - - private void dontShowLabelOnLongPress(final int index) { - ViewUtils.runOnPreDraw(parent, new Runnable() { - @Override - public void run() { - ActionMenuView actionMenuView = ViewUtils.findChildByClass(parent, ActionMenuView.class); - if (actionMenuView != null && actionMenuView.getChildAt(index) != null) { - actionMenuView.getChildAt(index).setOnLongClickListener(null); - } - } - }); - } - - private void setColor() { - if (!hasColor() || disableIconTint()) { - return; - } - - if (hasIcon()) { - setIconColor(); - } else { - setTextColor(); - } - } - - private void setIconColor() { - ViewUtils.tintDrawable(buttonParams.icon, buttonParams.color.getColor(), buttonParams.enabled); - } - - private void setTextColor() { - ViewUtils.runOnPreDraw(parent, new Runnable() { - @Override - public void run() { - ArrayList outViews = findActualTextViewInMenuByLabel(); - setTextColorForFoundButtonViews(outViews); - } - }); - } - - private void setFont() { - if (!buttonParams.hasFont()) { - return; - } - ArrayList buttons = findActualTextViewInMenuByLabel(); - setTextFontForFoundButtonViews(buttons); - } - - @NonNull - private ArrayList findActualTextViewInMenuByLabel() { - ArrayList outViews = new ArrayList<>(); - parent.findViewsWithText(outViews, buttonParams.label, View.FIND_VIEWS_WITH_TEXT); - return outViews; - } - - private void setTextColorForFoundButtonViews(ArrayList buttons) { - for (View button : buttons) { - ((TextView) button).setTextColor(buttonParams.getColor().getColor()); - } - } - - private void setTextFontForFoundButtonViews(ArrayList buttons) { - for (View button : buttons) { - if (buttonParams.hasFont()) { - ((TextView) button).setTypeface(buttonParams.font.get()); - } - } - } - - private boolean hasIcon() { - return buttonParams.icon != null; - } - - private boolean hasColor() { - return buttonParams.color.hasColor(); - } - - private boolean disableIconTint() { - return buttonParams.disableIconTint; - } - - @Override - public boolean onMenuItemClick(MenuItem item) { - NavigationApplication.instance.getEventEmitter().sendNavigatorEvent(buttonParams.eventId, navigatorEventId); - return true; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/TitleBarButtonComponent.java b/android/app/src/main/java/com/reactnativenavigation/views/TitleBarButtonComponent.java deleted file mode 100644 index 45287acc39f..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/TitleBarButtonComponent.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.os.Bundle; -import android.widget.FrameLayout; - -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.views.utils.Constants; -import com.reactnativenavigation.views.utils.ViewMeasurer; - -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; - -public class TitleBarButtonComponent extends ContentView { - - public TitleBarButtonComponent(Context context, String componentName, Bundle passProps) { - super(context, componentName, NavigationParams.EMPTY, passProps); - setLayoutParams(new FrameLayout.LayoutParams(WRAP_CONTENT, Constants.TOOLBAR_BUTTON_SIZE)); - setViewMeasurer(new ViewMeasurer() { - @Override - public int getMeasuredWidth(int widthMeasureSpec) { - return getChildCount() > 0 ? getChildAt(0).getWidth() : 0; - } - }); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/TitleBarMenuButton.java b/android/app/src/main/java/com/reactnativenavigation/views/TitleBarMenuButton.java deleted file mode 100644 index 5d134217464..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/TitleBarMenuButton.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.reactnativenavigation.views; - -public class TitleBarMenuButton { - - public TitleBarMenuButton() { - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java b/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java deleted file mode 100644 index 9b284ad67e4..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/TopBar.java +++ /dev/null @@ -1,280 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.graphics.Color; -import android.os.Build; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.AppBarLayout; -import android.support.v4.util.Pair; -import android.support.v7.app.ActionBar; -import android.view.Gravity; -import android.view.ViewGroup; -import android.view.ViewOutlineProvider; -import android.widget.FrameLayout; - -import com.facebook.react.bridge.Callback; -import com.reactnativenavigation.animation.VisibilityAnimator; -import com.reactnativenavigation.params.BaseScreenParams; -import com.reactnativenavigation.params.ContextualMenuParams; -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.params.TitleBarButtonParams; -import com.reactnativenavigation.params.TitleBarLeftButtonParams; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.ViewUtils; - -import java.util.List; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; - -public class TopBar extends AppBarLayout { - protected TitleBar titleBar; - private ContextualMenu contextualMenu; - protected FrameLayout titleBarAndContextualMenuContainer; - protected TopTabs topTabs; - private VisibilityAnimator visibilityAnimator; - @Nullable - private Pair reactView; - private ViewOutlineProvider outlineProvider; - - public TopBar(Context context) { - super(context); - setId(ViewUtils.generateViewId()); - createTopBarVisibilityAnimator(); - createLayout(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - outlineProvider = getOutlineProvider(); - } - } - - private void createTopBarVisibilityAnimator() { - ViewUtils.runOnPreDraw(this, new Runnable() { - @Override - public void run() { - visibilityAnimator = new VisibilityAnimator(TopBar.this, - VisibilityAnimator.HideDirection.Up, - getHeight()); - } - }); - } - - protected void createLayout() { - titleBarAndContextualMenuContainer = new FrameLayout(getContext()); - addView(titleBarAndContextualMenuContainer); - } - - public void addTitleBarAndSetButtons(List rightButtons, - TitleBarLeftButtonParams leftButton, - LeftButtonOnClickListener leftButtonOnClickListener, - String navigatorEventId, boolean overrideBackPressInJs, - StyleParams styleParams) { - titleBar = createTitleBar(); - addTitleBar(styleParams); - addButtons(rightButtons, leftButton, leftButtonOnClickListener, navigatorEventId, overrideBackPressInJs); - } - - protected TitleBar createTitleBar() { - return new TitleBar(getContext()); - } - - protected void addTitleBar(StyleParams styleParams) { - final int titleBarHeight = styleParams.titleBarHeight > 0 - ? (int) ViewUtils.convertDpToPixel(styleParams.titleBarHeight) - : MATCH_PARENT; - - ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(MATCH_PARENT, titleBarHeight); - - titleBarAndContextualMenuContainer.addView(titleBar, lp); - } - - private void addButtons(List rightButtons, TitleBarLeftButtonParams leftButton, LeftButtonOnClickListener leftButtonOnClickListener, String navigatorEventId, boolean overrideBackPressInJs) { - titleBar.setRightButtons(rightButtons, navigatorEventId); - titleBar.setLeftButton(leftButton, leftButtonOnClickListener, navigatorEventId, overrideBackPressInJs); - } - - public void setTitle(String title, StyleParams styleParams) { - titleBar.setTitle(title, styleParams); - } - - public void setSubtitle(String subtitle, StyleParams styleParams) { - titleBar.setSubtitle(subtitle, styleParams); - } - - public void setReactView(@NonNull StyleParams styleParams) { - if (styleParams.hasTopBarCustomComponent()) { - if (isReactViewAlreadySetAndUnchanged(styleParams)) { - return; - } - unmountReactView(); - reactView = new Pair<>(styleParams.topBarReactView, createReactView(styleParams)); - int height = styleParams.hasCustomTitleBarHeight() ? (int) ViewUtils.convertDpToPixel(styleParams.titleBarHeight) : ViewUtils.getToolBarHeight(); - if ("fill".equals(styleParams.topBarReactViewAlignment)) { - addReactViewFill(reactView.second, height); - } else { - addCenteredReactView(reactView.second, height); - } - } else { - unmountReactView(); - } - } - - private void unmountReactView() { - if (reactView == null) return; - titleBar.removeView(reactView.second); - reactView.second.unmountReactView(); - reactView = null; - } - - private boolean isReactViewAlreadySetAndUnchanged(@NonNull StyleParams styleParams) { - return reactView != null && styleParams.topBarReactView.equals(reactView.first); - } - - private ContentView createReactView(StyleParams styleParams) { - return new ContentView(getContext(), - styleParams.topBarReactView, - NavigationParams.EMPTY, - styleParams.topBarReactViewInitialProps - ); - } - - private void addReactViewFill(ContentView view, int height) { - view.setLayoutParams(new LayoutParams(MATCH_PARENT, height)); - titleBar.addView(view); - } - - private void addCenteredReactView(final ContentView view, int height) { - titleBar.addView(view, new LayoutParams(WRAP_CONTENT, height)); - view.setOnDisplayListener(new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - view.getLayoutParams().width = (int) (float) view.getChildAt(0).getMeasuredWidth(); - ((ActionBar.LayoutParams) view.getLayoutParams()).gravity = Gravity.CENTER; - view.requestLayout(); - } - }); - } - - public void setButtonColor(StyleParams styleParams) { - titleBar.setButtonColor(styleParams.titleBarButtonColor); - } - - public void setStyle(StyleParams styleParams) { - if (styleParams.topBarBorderColor.hasColor()) { - setBackground(new TopBarBorder(styleParams)); - } else if (styleParams.topBarColor.hasColor()) { - setBackgroundColor(styleParams.topBarColor.getColor()); - } - if (styleParams.topBarTransparent) { - setTransparent(); - } - titleBar.setStyle(styleParams); - setReactView(styleParams); - setTopTabsStyle(styleParams); - setElevationEnabled(styleParams.topBarElevationShadowEnabled); - } - - private void setTransparent() { - setBackgroundColor(Color.TRANSPARENT); - setElevationEnabled(false); - } - - private void setElevationEnabled (boolean enabled) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - setOutlineProvider(enabled ? outlineProvider : null); - } - } - - public void setTitleBarRightButtons(String navigatorEventId, List titleBarButtons) { - titleBar.setRightButtons(titleBarButtons, navigatorEventId); - } - - public TopTabs initTabs(StyleParams styleParams) { - topTabs = new TopTabs(getContext()); - - final int topTabsHeight = styleParams.topTabsHeight > 0 - ? (int) ViewUtils.convertDpToPixel(styleParams.topTabsHeight) - : MATCH_PARENT; - - addView(topTabs, new ViewGroup.LayoutParams(MATCH_PARENT, topTabsHeight)); - return topTabs; - } - - public void setTitleBarLeftButton(String navigatorEventId, - LeftButtonOnClickListener leftButtonOnClickListener, - TitleBarLeftButtonParams titleBarLeftButtonParams, - boolean overrideBackPressInJs) { - titleBar.setLeftButton(titleBarLeftButtonParams, leftButtonOnClickListener, navigatorEventId, - overrideBackPressInJs); - } - - private void setTopTabsStyle(StyleParams style) { - if (topTabs == null) { - return; - } - topTabs.setTopTabsTextColor(style); - topTabs.setSelectedTabIndicatorStyle(style); - topTabs.setScrollable(style); - topTabs.setTopTabsTextFontFamily(style); - } - - public void showContextualMenu(final ContextualMenuParams params, StyleParams styleParams, Callback onButtonClicked) { - final ContextualMenu menuToRemove = contextualMenu != null ? contextualMenu : null; - contextualMenu = new ContextualMenu(getContext(), params, styleParams, onButtonClicked); - titleBarAndContextualMenuContainer.addView(contextualMenu, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); - ViewUtils.runOnPreDraw(contextualMenu, new Runnable() { - @Override - public void run() { - titleBar.hide(); - contextualMenu.show(new Runnable() { - @Override - public void run() { - if (menuToRemove != null) { - titleBarAndContextualMenuContainer.removeView(menuToRemove); - } - } - }); - } - }); - } - - public void onContextualMenuHidden() { - contextualMenu = null; - titleBar.show(); - } - - public void dismissContextualMenu() { - if (contextualMenu != null) { - contextualMenu.dismiss(); - contextualMenu = null; - titleBar.show(); - } - } - - public void destroy() { - if (reactView != null) { - reactView.second.unmountReactView(); - reactView = null; - } - titleBar.destroy(); - } - - public void onViewPagerScreenChanged(BaseScreenParams screenParams) { - titleBar.onViewPagerScreenChanged(screenParams); - } - - public void setVisible(boolean visible, boolean animate) { - if (visible) { - titleBar.setVisibility(false); - visibilityAnimator.setVisible(true, animate, null); - } else { - visibilityAnimator.setVisible(false, animate, new Runnable() { - @Override - public void run() { - titleBar.setVisibility(true); - } - }); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/TopBarBorder.java b/android/app/src/main/java/com/reactnativenavigation/views/TopBarBorder.java deleted file mode 100644 index d74966150a8..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/TopBarBorder.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.reactnativenavigation.views; - -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Point; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.shapes.RectShape; -import android.graphics.drawable.shapes.Shape; - -import com.reactnativenavigation.params.StyleParams; - -class TopBarBorder extends ShapeDrawable { - private StyleParams.Color backgroundColor; - private final Paint pathPaint; - private Border border; - - private class Border { - private Path path; - int width; - int height; - - Border(int width, int height) { - this.width = width; - this.height = height; - path = createPath(); - } - - private Path createPath() { - Point a = new Point(0, height); - Point b = new Point(width, height); - Path path = new Path(); - path.moveTo(a.x, a.y); - path.lineTo(b.x, b.y); - return path; - } - - boolean dimensionsChanged(int width, int height) { - return this.width != width || this.height != height; - } - } - - TopBarBorder(StyleParams styleParams) { - super(new RectShape()); - backgroundColor = styleParams.topBarColor; - pathPaint = createPathPaint(styleParams.topBarBorderColor, styleParams.topBarBorderWidth); - } - - private Paint createPathPaint(StyleParams.Color color, float strokeWidth) { - Paint res = new Paint(); - res.setStyle(Paint.Style.STROKE); - res.setColor(color.getColor()); - res.setStrokeWidth(strokeWidth); - return res; - } - - @Override - protected void onDraw(Shape shape, Canvas canvas, Paint paint) { - paint.setColor(backgroundColor.getColor(Color.WHITE)); - super.onDraw(shape, canvas, paint); - createBorder(canvas); - canvas.drawPath(border.path, pathPaint); - } - - private void createBorder(Canvas canvas) { - if (border == null || border.dimensionsChanged(canvas.getWidth(), canvas.getHeight())) { - border = new Border(canvas.getWidth(), canvas.getHeight()); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/TopTabs.java b/android/app/src/main/java/com/reactnativenavigation/views/TopTabs.java deleted file mode 100644 index 456b2f9bcb4..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/TopTabs.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.reactnativenavigation.views; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Typeface; -import android.support.design.widget.TabLayout; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.views.utils.TopTabsIconColorHelper; - -public class TopTabs extends TabLayout { - - public TopTabs(Context context) { - super(context); - } - - void setSelectedTabIndicatorStyle(StyleParams style) { - if (style.selectedTopTabIndicatorColor.hasColor()) { - setSelectedTabIndicatorColor(style.selectedTopTabIndicatorColor.getColor()); - } - - if (style.selectedTopTabIndicatorHeight >= 0) { - setSelectedTabIndicatorHeight(style.selectedTopTabIndicatorHeight); - } - } - - void setTopTabsTextColor(StyleParams style) { - ColorStateList originalTabColors = getTabTextColors(); - int selectedTabColor = originalTabColors != null ? originalTabColors.getColorForState(TabLayout.SELECTED_STATE_SET, -1) : -1; - int tabTextColor = originalTabColors != null ? originalTabColors.getColorForState(TabLayout.EMPTY_STATE_SET, -1) : -1; - - if (style.topTabTextColor.hasColor()) { - tabTextColor = style.topTabTextColor.getColor(); - } - - if (style.selectedTopTabTextColor.hasColor()) { - selectedTabColor = style.selectedTopTabTextColor.getColor(); - } - - setTabTextColors(tabTextColor, selectedTabColor); - } - - void setTopTabsTextFontFamily(StyleParams style) { - if (style.topTabTextFontFamily.hasFont()) { - ViewGroup viewGroup = (ViewGroup) this.getChildAt(0); - - for (int tab = 0; tab < viewGroup.getChildCount(); tab++) { - ViewGroup tabViewGroup = (ViewGroup) viewGroup.getChildAt(tab); - - for (int i = 0; i < tabViewGroup.getChildCount(); i++) { - View tabViewChild = tabViewGroup.getChildAt(i); - if (tabViewChild instanceof TextView) { - ((TextView) tabViewChild).setTypeface( - style.topTabTextFontFamily.get(), Typeface.NORMAL); - } - } - } - } - } - - void setScrollable(StyleParams style) { - if (style.topTabsScrollable) { - setTabMode(TabLayout.MODE_SCROLLABLE); - } else { - setTabMode(TabLayout.MODE_FIXED); - } - } - - public void setTopTabsIconColor(StyleParams style) { - new TopTabsIconColorHelper(this, style).colorIcons(getSelectedIconColor(), getUnselectedIconColor()); - } - - private int getSelectedIconColor() { - ColorStateList originalTabColors = getTabTextColors(); - return originalTabColors != null ? originalTabColors.getColorForState(TabLayout.SELECTED_STATE_SET, -1) : -1; - } - - private int getUnselectedIconColor() { - ColorStateList originalTabColors = getTabTextColors(); - return originalTabColors != null ? originalTabColors.getColorForState(TabLayout.SELECTED_STATE_SET, -1) : -1; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/TranslucentDrawable.java b/android/app/src/main/java/com/reactnativenavigation/views/TranslucentDrawable.java deleted file mode 100644 index a6f73a604d5..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/TranslucentDrawable.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.reactnativenavigation.views; - -import android.graphics.Color; -import android.graphics.LinearGradient; -import android.graphics.Shader; -import android.graphics.drawable.PaintDrawable; -import android.graphics.drawable.ShapeDrawable; -import android.graphics.drawable.shapes.RectShape; - -public class TranslucentDrawable extends PaintDrawable { - - public TranslucentDrawable() { - setShape(new RectShape()); - createShader(); - } - - private void createShader() { - ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() { - @Override - public Shader resize(int width, int height) { - double angleInRadians = Math.toRadians(90); - - int x1 = (int) (Math.cos(angleInRadians) * width); - int y1 = (int) (Math.sin(angleInRadians) * height); - int[] colors = new int[]{Color.argb(90, 0, 0, 0), Color.argb(15, 0, 0, 0), Color.TRANSPARENT}; - float[] positions = {0, 0.78f, 1}; - LinearGradient lg = new LinearGradient(0, 0, x1, y1, - colors, - positions, - Shader.TileMode.REPEAT); - return lg; - } - }; - setShaderFactory(sf); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseAmount.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseAmount.java deleted file mode 100644 index e8f4c1b2883..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseAmount.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -public class CollapseAmount { - final static CollapseAmount None = new CollapseAmount(); - - private CollapseAmount() {} - - private Float amount; - private CollapseCalculator.Direction direction; - - CollapseAmount(float amount) { - this.amount = amount; - } - - public CollapseAmount(CollapseCalculator.Direction direction) { - this.direction = direction; - } - - boolean canCollapse() { - return amount != null || this != None; - } - - boolean hasExactAmount() { - return amount != null; - } - - boolean collapseToTop() { - return direction == CollapseCalculator.Direction.Up; - } - - boolean collapseToBottom() { - return direction == CollapseCalculator.Direction.Down; - } - - public float get() { - return amount; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseCalculator.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseCalculator.java deleted file mode 100644 index db194987887..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapseCalculator.java +++ /dev/null @@ -1,269 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.ViewConfiguration; -import android.widget.ScrollView; - -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseBehaviour; -import com.reactnativenavigation.views.collapsingToolbar.behaviours.TitleBarHideOnScrollBehaviour; - -public class CollapseCalculator { - private static final int FLING_DISTANCE_PIXELS_THRESHOLD = 200; - - public enum Direction { - Up, Down, None - } - - private float collapse; - private MotionEvent previousTouchEvent; - private float touchDownY = -1; - private float previousCollapseY = -1; - private boolean isExpended; - private boolean isCollapsed = true; - private boolean canCollapse = true; - private boolean canExpend = false; - private CollapsingView view; - private CollapseBehaviour collapseBehaviour; - protected ScrollView scrollView; - private GestureDetector flingDetector; - private OnFlingListener flingListener; - private int scrollY = 0; - private float totalCollapse = 0; - private float totalCollapseDeltaSinceTouchDown = 0; - private final int scaledTouchSlop; - private final int minimumFlingVelocity; - - public CollapseCalculator(final CollapsingView collapsingView, CollapseBehaviour collapseBehaviour) { - this.view = collapsingView; - this.collapseBehaviour = collapseBehaviour; - ViewConfiguration vc = ViewConfiguration.get(NavigationApplication.instance); - scaledTouchSlop = vc.getScaledTouchSlop(); - minimumFlingVelocity = vc.getScaledMinimumFlingVelocity(); - setFlingDetector(); - } - - private void setFlingDetector() { - if (collapseBehaviour.shouldCollapseOnFling()) { - flingDetector = - new GestureDetector(NavigationApplication.instance, new GestureDetector.SimpleOnGestureListener() { - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, final float velocityY) { - final Direction direction = getScrollDirection(e1, e2); - final float diff = Math.abs(e2.getRawY() - e1.getRawY()); - - if (Math.abs(velocityY) < minimumFlingVelocity || diff < FLING_DISTANCE_PIXELS_THRESHOLD) { - Log.w("FLING", "Consuming fling v: [" + velocityY + "] dy: [" + diff + "]"); - return true; - } - - if (canCollapse && totalCollapse != 0) { - flingListener.onFling(new CollapseAmount(direction)); - if (direction == Direction.Up) { - view.asView().postOnAnimation(new Runnable() { - @Override - public void run() { - Log.v("FLING", "v: [" + velocityY + "] dy: [" + diff + "]"); - scrollView.fling((int) Math.abs(velocityY)); - } - }); - } - return true; - } - - return true; - } - - private Direction getScrollDirection(MotionEvent e1, MotionEvent e2) { - if (e1.getRawY() == e2.getRawY()) { - return Direction.None; - } - return e1.getRawY() - e2.getRawY() > 0 ? Direction.Up : Direction.Down; - } - }); - } - } - - void setScrollView(ScrollView scrollView) { - this.scrollView = scrollView; - } - - void setFlingListener(OnFlingListener flingListener) { - this.flingListener = flingListener; - } - - @NonNull - CollapseAmount calculate(MotionEvent event) { - updateInitialTouchY(event); - final boolean isFling = flingDetector.onTouchEvent(event); - CollapseAmount touchUpCollapse = shouldCollapseOnTouchUp(event, isFling); - if (touchUpCollapse != CollapseAmount.None) { - previousTouchEvent = MotionEvent.obtain(event); - return touchUpCollapse; - } - - if (!isMoveEvent(event)) { - previousTouchEvent = MotionEvent.obtain(event); - return CollapseAmount.None; - } - - final Direction direction = calculateScrollDirection(event.getRawY()); - if (shouldCollapseAfterMoveEvent(direction)) { - return calculateCollapse(event); - } else { - previousCollapseY = -1; - previousTouchEvent = MotionEvent.obtain(event); - return CollapseAmount.None; - } - } - - private CollapseAmount shouldCollapseOnTouchUp(MotionEvent event, boolean isFling) { - if (isTouchUp(event) && collapseBehaviour.shouldCollapseOnTouchUp() && !isFling) { - final float visibilityPercentage = view.getCurrentCollapseValue() / view.getFinalCollapseValue(); - Direction direction = visibilityPercentage >= 0.5f ? Direction.Up : Direction.Down; - if (canCollapse(direction) && totalCollapse != 0) { - return new CollapseAmount(direction); - } - } - return CollapseAmount.None; - } - - private boolean shouldCollapseAfterMoveEvent(Direction direction) { - if (collapseBehaviour instanceof TitleBarHideOnScrollBehaviour && !isScrolling()) { - return false; - } - return canCollapse(direction); - } - - private boolean canCollapse(Direction direction) { - if (view == null) { - return false; - } - checkCollapseLimits(); - return (isNotCollapsedOrExpended() || - (canCollapse && isExpendedAndScrollingUp(direction)) || - (canExpend && isCollapsedAndScrollingDown(direction) && collapseBehaviour.canExpend(scrollView.getScrollY())) - ); - } - - private boolean isScrolling() { - final int currentScrollY = scrollView.getScrollY(); - final boolean isScrolling = currentScrollY != scrollY; - scrollY = currentScrollY; - return isScrolling; - } - - private Direction calculateScrollDirection(float y) { - if (y == (previousCollapseY == -1 ? touchDownY : previousCollapseY)) { - return Direction.None; - } - if (previousTouchEvent == null) { - return Direction.None; - } - return y < previousTouchEvent.getRawY() ? - Direction.Up : - Direction.Down; - } - - private void checkCollapseLimits() { - float currentCollapse = view.getCurrentCollapseValue(); - float finalExpendedTranslation = 0; - isExpended = isExpended(currentCollapse, finalExpendedTranslation); - isCollapsed = isCollapsed(currentCollapse, view.getFinalCollapseValue()); - canCollapse = calculateCanCollapse(currentCollapse, finalExpendedTranslation, view.getFinalCollapseValue()); - canExpend = calculateCanExpend(currentCollapse, finalExpendedTranslation, view.getFinalCollapseValue()); - } - - private boolean calculateCanCollapse(float currentTopBarTranslation, float finalExpendedTranslation, float finalCollapsedTranslation) { - return currentTopBarTranslation > finalCollapsedTranslation && - currentTopBarTranslation <= finalExpendedTranslation; - } - - private boolean calculateCanExpend(float currentTopBarTranslation, float finalExpendedTranslation, float finalCollapsedTranslation) { - return currentTopBarTranslation >= finalCollapsedTranslation && - currentTopBarTranslation < finalExpendedTranslation; - } - - private boolean isCollapsedAndScrollingDown(Direction direction) { - return isCollapsed && direction == Direction.Down; - } - - private boolean isExpendedAndScrollingUp(Direction direction) { - return isExpended && direction == Direction.Up; - } - - private boolean isNotCollapsedOrExpended() { - return canExpend && canCollapse; - } - - private boolean isCollapsed(float currentTopBarTranslation, float finalCollapsedTranslation) { - return currentTopBarTranslation == finalCollapsedTranslation; - } - - private boolean isExpended(float currentTopBarTranslation, float finalExpendedTranslation) { - return currentTopBarTranslation == finalExpendedTranslation; - } - - private CollapseAmount calculateCollapse(MotionEvent event) { - float y = event.getRawY(); - if (previousCollapseY == -1) { - previousCollapseY = y; - } - collapse = calculateCollapse(y); - totalCollapse += collapse; - totalCollapseDeltaSinceTouchDown += Math.abs(y - previousCollapseY); - previousCollapseY = y; - previousTouchEvent = MotionEvent.obtain(event); - return totalCollapseDeltaSinceTouchDown < scaledTouchSlop ? CollapseAmount.None : new CollapseAmount(collapse); - } - - private float calculateCollapse(float y) { - float translation = y - previousCollapseY + view.getCurrentCollapseValue(); - if (translation < view.getFinalCollapseValue()) { - translation = view.getFinalCollapseValue(); - } - final float expendedTranslation = 0; - if (translation > expendedTranslation) { - translation = expendedTranslation; - } - return translation; - } - - - private void updateInitialTouchY(MotionEvent event) { - if (isTouchDown(previousTouchEvent) && isMoveEvent(event)) { - saveInitialTouchY(previousTouchEvent); - } else if (isTouchUp(event) && isMoveEvent(previousTouchEvent)) { - clearInitialTouchY(); - } - } - - private boolean isMoveEvent(@Nullable MotionEvent event) { - return event != null && event.getActionMasked() == MotionEvent.ACTION_MOVE; - } - - private boolean isTouchDown(@Nullable MotionEvent event) { - return event != null && event.getActionMasked() == MotionEvent.ACTION_DOWN; - } - - private boolean isTouchUp(@Nullable MotionEvent event) { - return event != null && event.getActionMasked() == MotionEvent.ACTION_UP; - } - - private void saveInitialTouchY(MotionEvent event) { - totalCollapse = 0; - totalCollapseDeltaSinceTouchDown = 0; - touchDownY = event.getRawY(); - scrollY = scrollView.getScrollY(); - previousCollapseY = touchDownY; - } - - private void clearInitialTouchY() { - previousCollapseY = -1; - collapse = 0; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingReactHeaderMeasurer.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingReactHeaderMeasurer.java deleted file mode 100644 index c248c1980f6..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingReactHeaderMeasurer.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.view.ViewGroup; - -import com.reactnativenavigation.views.utils.ViewMeasurer; - -class CollapsingReactHeaderMeasurer extends ViewMeasurer { - private ViewGroup header; - - CollapsingReactHeaderMeasurer(ViewGroup header) { - this.header = header; - } - - @Override - public int getMeasuredHeight(int heightMeasureSpec) { - return hasChildren() ? getFirstChildHeightAndTopMargin() : super.getMeasuredHeight(heightMeasureSpec); - } - - private int getFirstChildHeightAndTopMargin() { - return header.getChildAt(0).getHeight() + header.getChildAt(0).getTop(); - } - - private boolean hasChildren() { - return header.getChildCount() > 0; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTextView.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTextView.java deleted file mode 100644 index fecfb08eb99..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTextView.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.support.annotation.CheckResult; -import android.support.annotation.FloatRange; -import android.support.v4.widget.TextViewCompat; -import android.support.v7.widget.TintTypedArray; -import android.text.TextPaint; -import android.text.TextUtils; -import android.util.Log; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.reactnativenavigation.R; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.utils.Point; - -import static android.R.attr.y; - -public class CollapsingTextView extends FrameLayout { - private static final float TEXT_SCALE_FACTOR = 1.75f; - private static final float INTERPOLATOR_EASING_FACTOR = 0.5f; - - private final int collapsedHeight; - private TextView dummy; - private CharSequence textToDraw; - private CharSequence expendedTextToDraw; - private String originalText; - private TextPaint paint; - private float initialY = -1; - private float currentY; - private float collapseY; - private float collapseFraction; - private Interpolator scaleInterpolator; - private float expendedTextSize; - private float collapsedTextSize; - - public CollapsingTextView(Context context, int collapsedHeight) { - super(context); - this.collapsedHeight = collapsedHeight; - setWillNotDraw(false); - createDummyTextView(context); - createTextPaint(); - scaleInterpolator = new DecelerateInterpolator(INTERPOLATOR_EASING_FACTOR); - setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); - } - - @SuppressLint("PrivateResource") - private void createDummyTextView(Context context) { - final TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), null, - R.styleable.Toolbar, R.attr.toolbarStyle, 0); - int titleTextAppearance = - a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0); - a.recycle(); - - dummy = new TextView(context); - dummy.setSingleLine(); - dummy.setEllipsize(TextUtils.TruncateAt.END); - TextViewCompat.setTextAppearance(dummy, titleTextAppearance); - collapsedTextSize = dummy.getTextSize(); - expendedTextSize = collapsedTextSize * TEXT_SCALE_FACTOR; - dummy.setTextSize(ViewUtils.convertPixelToSp(expendedTextSize)); - dummy.setVisibility(INVISIBLE); - addView(dummy, new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); - } - - private void createTextPaint() { - paint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG); - paint.setColor(Color.WHITE); - paint.setTextSize(expendedTextSize); - } - - public void setText(String text) { - this.originalText = text; - dummy.setText(text); - } - - public void setTextColor(StyleParams params) { - if (params.titleBarTitleColor.hasColor()) { - paint.setColor(params.titleBarTitleColor.getColor()); - } - } - - public void collapseBy(float translation) { - collapseFraction = calculateFraction(translation); - currentY = linearInterpolation(initialY, collapseY, collapseFraction); - invalidate(); - } - - /* - * A value of {@code 0.0} indicates that the layout is fully expanded. - * A value of {@code 1.0} indicates that the layout is fully collapsed. - */ - @FloatRange(from = 0.0, to = 1.0) - private float calculateFraction(float translation) { - return Math.abs(translation / (getMeasuredHeight() - collapsedHeight)); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (initialY == -1) { - calculateTextPosition(canvas); - } - paint.setTextSize(linearInterpolation(expendedTextSize, collapsedTextSize, collapseFraction)); - calculateTextToDraw(); - canvas.drawText(textToDraw, 0, textToDraw.length(), 0, currentY, paint); - } - - private void calculateTextToDraw() { - if (currentY == collapseY) { - textToDraw = calculateText(); - } else { - if (expendedTextToDraw == null) { - expendedTextToDraw = calculateText(); - } - textToDraw = expendedTextToDraw; - } - } - - private void calculateTextPosition(Canvas canvas) { - currentY = initialY = ViewUtils.getStatusBarHeight() + canvas.getHeight() - dummy.getMeasuredHeight(); - float bottomMargin = ViewUtils.convertDpToPixel(10); - collapseY = ViewUtils.getStatusBarHeight() + bottomMargin; - } - - private float linearInterpolation(float from, float to, float fraction) { - fraction = scaleInterpolator.getInterpolation(fraction); - return from + (fraction * (to - from)); - } - - @CheckResult - private String calculateText() { - return (String) TextUtils.ellipsize(originalText, paint, - getWidth(), TextUtils.TruncateAt.END); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTitleBar.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTitleBar.java deleted file mode 100644 index c6d0559b594..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTitleBar.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.view.MotionEvent; -import android.view.View; - -import com.reactnativenavigation.params.CollapsingTopBarParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.TitleBar; -import com.reactnativenavigation.views.TitleBarBackground; -import com.reactnativenavigation.views.TranslucentDrawable; - -public class CollapsingTitleBar extends TitleBar implements View.OnTouchListener { - private CollapsingTextView title; - private int collapsedHeight; - private final ScrollListener scrollListener; - private final CollapsingTopBarParams params; - private TitleBarBackground titleBarBackground; - - public CollapsingTitleBar(Context context, int collapsedHeight, ScrollListener scrollListener, CollapsingTopBarParams params) { - super(context); - this.collapsedHeight = collapsedHeight; - this.scrollListener = scrollListener; - this.params = params; - addCollapsingTitle(); - setOnTouchListener(this); - setInitialTitleViewVisibility(); - } - - private void setInitialTitleViewVisibility() { - ViewUtils.runOnPreDraw(this, new Runnable() { - @Override - public void run() { - View titleView = getTitleView(); - if (titleView == null) { - return; - } - if (params.showTitleWhenExpended) { - titleView.setAlpha(1); - } else if (params.showTitleWhenCollapsed) { - titleView.setAlpha(0); - } - } - }); - - } - - @Override - public void hideTitle() { - if (!params.showTitleWhenExpended) { - super.hideTitle(); - } - titleBarBackground.showTranslucentBackground(); - } - - @Override - public void showTitle() { - super.showTitle(); - titleBarBackground.showSolidBackground(); - } - - private void addCollapsingTitle() { - if (params.hasBackgroundImage()) { - title = new CollapsingTextView(getContext(), collapsedHeight); - addView(title); - } - } - - @Override - public void setTitle(CharSequence title) { - if (params.hasBackgroundImage()) { - this.title.setText((String) title); - } else { - super.setTitle(title); - } - } - - @Override - protected void setTitleTextColor(StyleParams params) { - if (this.params.hasBackgroundImage()) { - title.setTextColor(params); - } else { - super.setTitleTextColor(params); - } - } - - @Override - protected void setSubtitleTextColor(StyleParams params) { - if (this.params.hasReactView()) { - super.setSubtitleTextColor(params); - } - } - - @Override - protected void setBackground(StyleParams params) { - if (titleBarBackground == null) { - titleBarBackground = createBackground(params, - params.collapsingTopBarParams.expendedTitleBarColor, - params.collapsingTopBarParams.scrimColor); - setBackground(titleBarBackground); - } - } - - private TitleBarBackground createBackground(StyleParams styleParams, StyleParams.Color expendedColor, StyleParams.Color collapsedColor) { - final Drawable expendedDrawable = styleParams.topBarTranslucent ? new TranslucentDrawable() : new ColorDrawable(expendedColor.getColor(Color.TRANSPARENT)); - final Drawable collapsedDrawable = new ColorDrawable(collapsedColor.getColor(Color.TRANSPARENT)); - return new TitleBarBackground(expendedDrawable, collapsedDrawable); - } - - public void collapse(CollapseAmount amount) { - if (amount.hasExactAmount()) { - collapse(amount.get()); - } - } - - private void collapse(float collapse) { - if (params.hasBackgroundImage()) { - title.setTranslationY(0); - title.collapseBy(collapse); - } - setTranslationY(-collapse); - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - return scrollListener.onTouch(event); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBar.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBar.java deleted file mode 100644 index 99a0df1eb6b..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBar.java +++ /dev/null @@ -1,199 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.content.Context; -import android.content.res.TypedArray; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ScrollView; - -import com.reactnativenavigation.params.CollapsingTopBarParams; -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.TitleBar; -import com.reactnativenavigation.views.TopBar; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; - -public class CollapsingTopBar extends TopBar implements CollapsingView { - private CollapsingTopBarBackground collapsingTopBarBackground; - private @Nullable CollapsingTopBarReactHeader header; - private ScrollListener scrollListener; - private float finalCollapsedTranslation; - private final StyleParams styleParams; - private final CollapsingTopBarParams params; - private final ViewCollapser viewCollapser; - private final int topBarHeight; - - @Override - public void destroy() { - if (params.hasReactView()) { - assert header != null; - header.unmountReactView(); - } - } - - public CollapsingTopBar(Context context, final StyleParams params) { - super(context); - styleParams = params; - this.params = params.collapsingTopBarParams; - topBarHeight = calculateTopBarHeight(); - createBackgroundImage(); - calculateFinalCollapsedTranslation(); - viewCollapser = new ViewCollapser(this); - } - - private void calculateFinalCollapsedTranslation() { - ViewUtils.runOnPreDraw(this, new Runnable() { - @Override - public void run() { - if (params.hasBackgroundImage() || params.hasReactView()) { - finalCollapsedTranslation = getCollapsedHeight() - getHeight(); - if (styleParams.topBarCollapseOnScroll) { - finalCollapsedTranslation += titleBar.getHeight(); - } - } else { - finalCollapsedTranslation = -titleBar.getHeight(); - } - } - }); - } - - public void setScrollListener(ScrollListener scrollListener) { - this.scrollListener = scrollListener; - } - - private void createBackgroundImage() { - if (params.hasBackgroundImage()) { - collapsingTopBarBackground = new CollapsingTopBarBackground(getContext(), params); - LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, (int) CollapsingTopBarBackground.MAX_HEIGHT); - titleBarAndContextualMenuContainer.addView(collapsingTopBarBackground, lp); - } - } - - private void createReactHeader(CollapsingTopBarParams params) { - if (params.hasReactView()) { - header = new CollapsingTopBarReactHeader(getContext(), - params, - new NavigationParams(Bundle.EMPTY), - scrollListener, - new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - calculateFinalCollapsedTranslation(); - assert header != null; - header.setOnDisplayListener(null); - } - }); - titleBarAndContextualMenuContainer.addView(header, new LayoutParams(MATCH_PARENT, WRAP_CONTENT)); - header.setOnHiddenListener(new CollapsingTopBarReactHeaderAnimator.OnHiddenListener() { - @Override - public void onHidden() { - titleBar.showTitle(); - } - }); - header.setOnVisibleListener(new CollapsingTopBarReactHeaderAnimator.OnVisibleListener() { - @Override - public void onVisible() { - titleBar.hideTitle(); - } - }); - } - } - - @Override - protected TitleBar createTitleBar() { - if (params.hasBackgroundImage() || params.hasReactView()) { - createReactHeader(params); - return new CollapsingTitleBar(getContext(), - getCollapsedHeight(), - scrollListener, - params); - } else { - return super.createTitleBar(); - } - } - - @Override - protected void addTitleBar(StyleParams styleParams) { - if (params.hasReactView()) { - titleBarAndContextualMenuContainer.addView(titleBar, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); - } else { - super.addTitleBar(styleParams); - } - } - - @Override - public void collapse(CollapseAmount amount) { - viewCollapser.collapse(amount); - if (titleBar instanceof CollapsingTitleBar) { - ((CollapsingTitleBar) titleBar).collapse(amount); - } - if (collapsingTopBarBackground != null) { - collapsingTopBarBackground.collapse(amount.get()); - } - if (header != null) { - header.collapse(amount.get()); - } - } - - @Override - public void fling(CollapseAmount amount) { - if (titleBar instanceof CollapsingTitleBar) { - if (header != null) { - viewCollapser.fling(amount, (CollapsingTitleBar) titleBar, header); - } else { - viewCollapser.fling(amount, (CollapsingTitleBar) titleBar); - } - } else { - viewCollapser.collapse(amount); - } - } - - public void onScrollViewAdded(ScrollView scrollView) { - scrollListener.onScrollViewAdded(scrollView); - } - - @Override - public float getFinalCollapseValue() { - return finalCollapsedTranslation; - } - - public int getCollapsedHeight() { - if (topTabs != null) { - return topTabs.getHeight(); - } else if (params.hasBackgroundImage()) { - return topBarHeight; - } else if (params.hasReactView()) { - return topBarHeight; - } else { - return titleBar.getHeight(); - } - } - - private int calculateTopBarHeight() { - int[] attrs = new int[] {android.R.attr.actionBarSize}; - TypedArray ta = getContext().obtainStyledAttributes(attrs); - final int result = ta.getDimensionPixelSize(0, -1); - ta.recycle(); - return result; - } - - @Override - public float getCurrentCollapseValue() { - return getTranslationY(); - } - - @Override - public View asView() { - return this; - } - - public int getTitleBarHeight() { - return titleBar.getHeight(); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarBackground.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarBackground.java deleted file mode 100644 index 89abf3af213..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarBackground.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.content.Context; -import android.widget.FrameLayout; -import android.widget.ImageView; - -import com.facebook.drawee.view.SimpleDraweeView; -import com.reactnativenavigation.params.CollapsingTopBarParams; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.Scrim; - -import static android.widget.FrameLayout.LayoutParams.MATCH_PARENT; - -public class CollapsingTopBarBackground extends FrameLayout { - public static final float MAX_HEIGHT = ViewUtils.convertDpToPixel(256); - private final CollapsingTopBarParams params; - private SimpleDraweeView backdrop; - private Scrim scrim; - - public CollapsingTopBarBackground(Context context, CollapsingTopBarParams params) { - super(context); - this.params = params; - setFitsSystemWindows(true); - createBackDropImage(); - createScrim(); - setWillNotDraw(false); - } - - private void createBackDropImage() { - backdrop = new SimpleDraweeView(getContext()); - setImageSource(); - backdrop.setScaleType(ImageView.ScaleType.CENTER_CROP); - backdrop.setFitsSystemWindows(true); - addView(backdrop, new LayoutParams(MATCH_PARENT, MATCH_PARENT)); - } - - private void setImageSource() { - if (params.imageUri != null) { - backdrop.setImageURI(params.imageUri); - } - } - - private void createScrim() { - scrim = new Scrim(getContext(), params.scrimColor, MAX_HEIGHT / 2); - addView(scrim); - } - - public void collapse(float collapse) { - scrim.collapse(collapse); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarReactHeader.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarReactHeader.java deleted file mode 100644 index 5548158dd07..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarReactHeader.java +++ /dev/null @@ -1,154 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.content.Context; -import android.support.v4.view.MotionEventCompat; -import android.view.MotionEvent; -import android.view.ViewConfiguration; - -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.uimanager.JSTouchDispatcher; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.events.EventDispatcher; -import com.reactnativenavigation.NavigationApplication; -import com.reactnativenavigation.params.CollapsingTopBarParams; -import com.reactnativenavigation.params.NavigationParams; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.ContentView; - -public class CollapsingTopBarReactHeader extends ContentView implements CollapsingTopBarReactHeaderAnimator.OnVisibleListener, CollapsingTopBarReactHeaderAnimator.OnHiddenListener, Screen.OnDisplayListener { - private ScrollListener listener; - private Screen.OnDisplayListener onDisplayListener; - private boolean mIsScrolling; - private int mTouchSlop; - private int touchDown = -1; - private final JSTouchDispatcher mJSTouchDispatcher = new JSTouchDispatcher(this); - private CollapsingTopBarReactHeaderAnimator visibilityAnimator; - private CollapsingTopBarReactHeaderAnimator.OnVisibleListener onVisibleListener; - private CollapsingTopBarReactHeaderAnimator.OnHiddenListener onHiddenListener; - - public void setOnVisibleListener(CollapsingTopBarReactHeaderAnimator.OnVisibleListener onVisibleListener) { - this.onVisibleListener = onVisibleListener; - } - - public void setOnHiddenListener(CollapsingTopBarReactHeaderAnimator.OnHiddenListener onHiddenListener) { - this.onHiddenListener = onHiddenListener; - } - - public CollapsingTopBarReactHeader(Context context, CollapsingTopBarParams params, NavigationParams navigationParams, ScrollListener scrollListener, Screen.OnDisplayListener onDisplayListener) { - super(context, params.reactViewId, navigationParams); - listener = scrollListener; - this.onDisplayListener = onDisplayListener; - ViewConfiguration vc = ViewConfiguration.get(context); - mTouchSlop = vc.getScaledTouchSlop(); - setViewMeasurer(new CollapsingReactHeaderMeasurer(this)); - setOnDisplayListener(this); - } - - @Override - public void onDisplay() { - createVisibilityAnimator(); - onDisplayListener.onDisplay(); - } - - private void createVisibilityAnimator() { - ViewUtils.runOnPreDraw(this, new Runnable() { - @Override - public void run() { - final CollapsingTopBarReactHeader header = CollapsingTopBarReactHeader.this; - float height = getHeight(); - visibilityAnimator = new CollapsingTopBarReactHeaderAnimator(header, height * 0.6f, height * 0.60f); - visibilityAnimator.setOnHiddenListener(header); - visibilityAnimator.setOnVisibleListener(header); - } - }); - } - - public void collapse(float amount) { - visibilityAnimator.collapse(amount); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - final int action = MotionEventCompat.getActionMasked(ev); - switch (action) { - case MotionEvent.ACTION_CANCEL: - releaseScroll(ev); - break; - case MotionEvent.ACTION_UP: - releaseScroll(ev); - break; - case MotionEvent.ACTION_DOWN: - onTouchDown(ev); - break; - case MotionEvent.ACTION_MOVE: { - if (mIsScrolling) { - return true; - } - if (calculateDistanceY(ev) > mTouchSlop) { - mIsScrolling = true; - return true; - } - break; - } - default: - break; - } - return false; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - listener.onTouch(ev); - int action = ev.getActionMasked(); - switch (action) { - case MotionEvent.ACTION_UP: - releaseScroll(ev); - break; - case MotionEvent.ACTION_MOVE: - - break; - default: - break; - } - return super.onTouchEvent(ev); - } - - private void onTouchDown(MotionEvent ev) { - listener.onTouch(ev); - if (touchDown == -1) { - touchDown = (int) ev.getRawY(); - } - dispatchTouchEventToJs(ev); - } - - private int calculateDistanceY(MotionEvent ev) { - return (int) Math.abs(ev.getRawY() - touchDown); - } - - private void releaseScroll(MotionEvent ev) { - mIsScrolling = false; - touchDown = -1; - dispatchTouchEventToJs(ev); - } - - private void dispatchTouchEventToJs(MotionEvent event) { - ReactContext reactContext = NavigationApplication.instance.getReactGateway().getReactInstanceManager().getCurrentReactContext(); - EventDispatcher eventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher(); - mJSTouchDispatcher.handleTouchEvent(event, eventDispatcher); - } - - @Override - public void onVisible() { - if (onVisibleListener != null) { - onVisibleListener.onVisible(); - } - } - - @Override - public void onHidden() { - if (onHiddenListener != null) { - onHiddenListener.onHidden(); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarReactHeaderAnimator.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarReactHeaderAnimator.java deleted file mode 100644 index c62158f4242..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingTopBarReactHeaderAnimator.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.util.Log; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; - -import static com.reactnativenavigation.views.collapsingToolbar.CollapsingTopBarReactHeaderAnimator.State.Invisible; -import static com.reactnativenavigation.views.collapsingToolbar.CollapsingTopBarReactHeaderAnimator.State.Visible; - -class CollapsingTopBarReactHeaderAnimator { - interface OnVisibleListener { - void onVisible(); - } - interface OnHiddenListener { - void onHidden(); - } - enum State {Visible, Invisible} - - private State state = Invisible; - private CollapsingTopBarReactHeader header; - private final float hideThreshold; - private float showThreshold; - private final static int ANIMATION_DURATION = 360; - private final Interpolator interpolator = new DecelerateInterpolator(); - private OnVisibleListener onVisibleListener; - private OnHiddenListener onHiddenListener; - - void setOnVisibleListener(OnVisibleListener onVisibleListener) { - this.onVisibleListener = onVisibleListener; - } - - void setOnHiddenListener(OnHiddenListener onHiddenListener) { - this.onHiddenListener = onHiddenListener; - } - - CollapsingTopBarReactHeaderAnimator(CollapsingTopBarReactHeader header, float hideThreshold, float showThreshold) { - this.header = header; - this.hideThreshold = hideThreshold; - this.showThreshold = showThreshold; - } - - public void collapse(float collapse) { - if (shouldShow(collapse)) { - show(); - } else if (shouldHide(collapse)) { - hide(); - } - } - - private boolean shouldShow(float collapse) { - Log.i("shouldShow", "collapse: " + collapse + "[" + showThreshold + "]"); - return Math.abs(collapse) < showThreshold && state == Invisible; - } - - private boolean shouldHide(float collapse) { - Log.i("shouldHide", "collapse: " + collapse + "[" + hideThreshold + "]"); - return Math.abs(collapse) >= hideThreshold && state == Visible; - } - - private void show() { - if (state == Invisible && onVisibleListener != null) { - onVisibleListener.onVisible(); - } - state = State.Visible; - header.animate() - .alpha(1) - .setDuration(ANIMATION_DURATION) - .setInterpolator(interpolator); - } - - private void hide() { - if (state == Visible && onHiddenListener != null) { - onHiddenListener.onHidden(); - } - state = State.Invisible; - header.animate() - .alpha(0) - .setDuration(ANIMATION_DURATION) - .setInterpolator(interpolator); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingView.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingView.java deleted file mode 100644 index 1bfde32e1d2..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingView.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.view.View; - -public interface CollapsingView { - float getFinalCollapseValue(); - - float getCurrentCollapseValue(); - - View asView(); - - void collapse(CollapseAmount amount); - - void fling(CollapseAmount amount); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewMeasurer.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewMeasurer.java deleted file mode 100644 index ea820fc5afd..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewMeasurer.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.utils.ViewMeasurer; - -public class CollapsingViewMeasurer extends ViewMeasurer { - int screenHeight; - int bottomTabsHeight = 0; - CollapsingTopBar topBar; - protected StyleParams styleParams; - - public CollapsingViewMeasurer(final CollapsingTopBar topBar, final Screen collapsingSingleScreen, StyleParams styleParams) { - this.topBar = topBar; - this.styleParams = styleParams; - bottomTabsHeight = (int) ViewUtils.convertDpToPixel(56); - ViewUtils.runOnPreDraw(collapsingSingleScreen, new Runnable() { - @Override - public void run() { - screenHeight = collapsingSingleScreen.getHeight(); - } - }); - } - - public float getFinalCollapseValue() { - return topBar.getFinalCollapseValue(); - } - - @Override - public int getMeasuredHeight(int heightMeasureSpec) { - int height = screenHeight - topBar.getCollapsedHeight(); - if (styleParams.bottomTabsHidden) { - height += bottomTabsHeight; - } - return height; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewPager.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewPager.java deleted file mode 100644 index 9db3e49a62c..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewPager.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.content.Context; -import android.support.v4.view.ViewPager; -import android.view.View; - -public class CollapsingViewPager extends ViewPager implements CollapsingView { - CollapsingViewMeasurer viewMeasurer; - ViewCollapser viewCollapser; - - public CollapsingViewPager(Context context) { - super(context); - viewCollapser = new ViewCollapser(this); - } - - public void setViewMeasurer(CollapsingViewMeasurer viewMeasurer) { - this.viewMeasurer = viewMeasurer; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - setMeasuredDimension(viewMeasurer.getMeasuredWidth(widthMeasureSpec), - viewMeasurer.getMeasuredHeight(heightMeasureSpec)); - } - - @Override - public float getFinalCollapseValue() { - return viewMeasurer.getFinalCollapseValue(); - } - - @Override - public float getCurrentCollapseValue() { - return getTranslationY(); - } - - @Override - public View asView() { - return this; - } - - @Override - public void collapse(CollapseAmount amount) { - viewCollapser.collapse(amount); - } - - @Override - public void fling(CollapseAmount amount) { - viewCollapser.fling(amount); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewPagerContentViewMeasurer.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewPagerContentViewMeasurer.java deleted file mode 100644 index 16b9c993ea4..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/CollapsingViewPagerContentViewMeasurer.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import com.reactnativenavigation.layouts.BottomTabsLayout; -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.ViewUtils; - -public class CollapsingViewPagerContentViewMeasurer extends CollapsingViewMeasurer { - private int titleBarHeight; - private boolean layoutHasBottomTabs; - - public CollapsingViewPagerContentViewMeasurer(final CollapsingTopBar topBar, final Screen screen, StyleParams styleParams) { - super(topBar, screen, styleParams); - ViewUtils.runOnPreDraw(screen, new Runnable() { - @Override - public void run() { - layoutHasBottomTabs = screen.getParent() instanceof BottomTabsLayout; - } - }); - ViewUtils.runOnPreDraw(topBar, new Runnable() { - @Override - public void run() { - titleBarHeight = topBar.getTitleBarHeight(); - } - }); - } - - @Override - public int getMeasuredHeight(int heightMeasureSpec) { - int height = screenHeight - topBar.getCollapsedHeight(); - if (hasBottomTabs() && drawScreenUnderBottomTabs()) { - height -= bottomTabsHeight; - } - if (!styleParams.titleBarHideOnScroll) { - height -= titleBarHeight; - } - return height; - } - - private boolean drawScreenUnderBottomTabs() { - return !styleParams.drawScreenAboveBottomTabs; - } - - private boolean hasBottomTabs() { - return layoutHasBottomTabs && !styleParams.bottomTabsHidden; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnFlingListener.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnFlingListener.java deleted file mode 100644 index 62a459df3ff..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnFlingListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -interface OnFlingListener { - void onFling(CollapseAmount amount); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnScrollListener.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnScrollListener.java deleted file mode 100644 index 9930d533793..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnScrollListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.view.MotionEvent; - -public interface OnScrollListener extends OnFlingListener { - void onScroll(MotionEvent event, CollapseAmount amount); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnScrollViewAddedListener.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnScrollViewAddedListener.java deleted file mode 100644 index 2448b2b9f5e..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/OnScrollViewAddedListener.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.widget.ScrollView; - -public interface OnScrollViewAddedListener { - void onScrollViewAdded(ScrollView scrollView); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollListener.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollListener.java deleted file mode 100644 index 05b21f69f9c..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollListener.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.view.MotionEvent; -import android.widget.ScrollView; - -import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseBehaviour; -import com.reactnativenavigation.views.collapsingToolbar.behaviours.CollapseTopBarBehaviour; - - -public class ScrollListener { - private CollapseCalculator collapseCalculator; - private OnScrollListener scrollListener; - private CollapseBehaviour collapseBehaviour; - - public ScrollListener(CollapseCalculator collapseCalculator, OnScrollListener scrollListener, - CollapseBehaviour collapseBehaviour) { - this.collapseCalculator = collapseCalculator; - this.scrollListener = scrollListener; - this.collapseBehaviour = collapseBehaviour; - collapseCalculator.setFlingListener(scrollListener); - } - - void onScrollViewAdded(ScrollView scrollView) { - collapseCalculator.setScrollView(scrollView); - } - - boolean onTouch(MotionEvent event) { - CollapseAmount amount = collapseCalculator.calculate(event); - if (amount.canCollapse()) { - scrollListener.onScroll(event, amount); - return collapseBehaviour instanceof CollapseTopBarBehaviour; - } - return false; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollViewDelegate.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollViewDelegate.java deleted file mode 100644 index 7d874d827d0..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ScrollViewDelegate.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.view.MotionEvent; -import android.view.View; -import android.widget.ScrollView; - -public class ScrollViewDelegate implements View.OnTouchListener { - private ScrollView scrollView; - private ScrollListener listener; - - public ScrollViewDelegate(ScrollListener scrollListener) { - listener = scrollListener; - } - - public boolean hasScrollView() { - return scrollView != null; - } - - public ScrollView getScrollView() { - return scrollView; - } - - public void onScrollViewAdded(ScrollView scrollView) { - this.scrollView = scrollView; - listener.onScrollViewAdded(this.scrollView); - } - - public void onScrollViewRemoved() { - this.scrollView = null; - } - - public boolean didInterceptTouchEvent(MotionEvent ev) { - return listener.onTouch(ev); - } - - @Override - public boolean onTouch(View view, MotionEvent event) { - scrollView.onTouchEvent(event); - return this.listener.onTouch(event); - } - - public void destroy() { - scrollView = null; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ViewCollapser.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ViewCollapser.java deleted file mode 100644 index 47d00f8c207..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/ViewCollapser.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; -import android.support.annotation.NonNull; -import android.view.View; -import android.view.ViewPropertyAnimator; -import android.view.animation.DecelerateInterpolator; - -public class ViewCollapser { - private static final int DURATION = 160; - private static final int FLING_DURATION = 160; - private CollapsingView view; - - private final ValueAnimator.AnimatorUpdateListener LISTENER = - new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - } - }; - private ViewPropertyAnimator animator; - private ObjectAnimator flingAnimator; - - public ViewCollapser(CollapsingView view) { - this.view = view; - } - - public void collapse(CollapseAmount amount) { - if (amount.collapseToTop()) { - collapseView(true, view.getFinalCollapseValue()); - } else if (amount.collapseToBottom()) { - collapseView(true, 0); - } else { - collapse(amount.get()); - } - } - - private void collapseView(boolean animate, float translation) { - if (animate) { - animate(translation); - } else { - collapse(translation); - } - } - - public void collapse(float amount) { - cancelAnimator(); - view.asView().setTranslationY(amount); - } - - private void animate(final float translation) { - animator = view.asView().animate() - .translationY(translation) - .setDuration(DURATION) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationCancel(Animator animation) { - animator = null; - } - - @Override - public void onAnimationEnd(Animator animation) { - animator = null; - } - }); - animator.start(); - } - - void fling(final CollapseAmount amount, final CollapsingTitleBar titleBar, @NonNull final CollapsingTopBarReactHeader header) { - fling(amount, new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - titleBar.collapse(new CollapseAmount((Float) animation.getAnimatedValue())); - header.collapse((Float) animation.getAnimatedValue()); - } - }); - } - - void fling(final CollapseAmount amount, final CollapsingTitleBar titleBar) { - fling(amount, new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - titleBar.collapse(new CollapseAmount((Float) animation.getAnimatedValue())); - } - }); - } - - public void fling(CollapseAmount amount) { - fling(amount, LISTENER); - } - - private void fling(final CollapseAmount amount, @NonNull final ValueAnimator.AnimatorUpdateListener updateListener) { - cancelAnimator(); - final float translation = amount.collapseToTop() ? view.getFinalCollapseValue() : 0; - flingAnimator = ObjectAnimator.ofFloat(view.asView(), View.TRANSLATION_Y, translation); - flingAnimator.setDuration(FLING_DURATION); - flingAnimator.setInterpolator(new DecelerateInterpolator()); - flingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - updateListener.onAnimationUpdate(animation); - } - }); - flingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - updateListener.onAnimationUpdate(animation); - } - }); - flingAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationCancel(Animator animation) { - flingAnimator = null; - } - @Override - public void onAnimationEnd(Animator animation) { - flingAnimator = null; - } - }); - flingAnimator.start(); - - } - - private void cancelAnimator() { - if (animator != null) { - animator.cancel(); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseBehaviour.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseBehaviour.java deleted file mode 100644 index 85605f52748..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseBehaviour.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar.behaviours; - -public interface CollapseBehaviour { - boolean shouldCollapseOnFling(); - - boolean shouldCollapseOnTouchUp(); - - boolean canExpend(int scrollY); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseTitleBarBehaviour.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseTitleBarBehaviour.java deleted file mode 100644 index 27ff602ebc1..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseTitleBarBehaviour.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar.behaviours; - -public class CollapseTitleBarBehaviour implements CollapseBehaviour { - @Override - public boolean shouldCollapseOnFling() { - return true; - } - - @Override - public boolean shouldCollapseOnTouchUp() { - return true; - } - - @Override - public boolean canExpend(int scrollY) { - return true; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseTopBarBehaviour.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseTopBarBehaviour.java deleted file mode 100644 index 179ab978ee8..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/CollapseTopBarBehaviour.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar.behaviours; - -public class CollapseTopBarBehaviour implements CollapseBehaviour { - @Override - public boolean shouldCollapseOnFling() { - return true; - } - - @Override - public boolean shouldCollapseOnTouchUp() { - return false; - } - - @Override - public boolean canExpend(int scrollY) { - return scrollY == 0; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/TitleBarHideOnScrollBehaviour.java b/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/TitleBarHideOnScrollBehaviour.java deleted file mode 100644 index 049570277c7..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/collapsingToolbar/behaviours/TitleBarHideOnScrollBehaviour.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.reactnativenavigation.views.collapsingToolbar.behaviours; - -public class TitleBarHideOnScrollBehaviour implements CollapseBehaviour { - @Override - public boolean shouldCollapseOnFling() { - return true; - } - - @Override - public boolean shouldCollapseOnTouchUp() { - return true; - } - - @Override - public boolean canExpend(int scrollY) { - return true; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/managers/SharedElementTransitionManager.java b/android/app/src/main/java/com/reactnativenavigation/views/managers/SharedElementTransitionManager.java deleted file mode 100644 index 625f5e675ce..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/managers/SharedElementTransitionManager.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.reactnativenavigation.views.managers; - -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.ViewGroupManager; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.reactnativenavigation.views.sharedElementTransition.SharedElementTransition; - -public class SharedElementTransitionManager extends ViewGroupManager { - - @Override - public String getName() { - return "SharedElementTransition"; - } - - @Override - protected SharedElementTransition createViewInstance(ThemedReactContext reactContext) { - return new SharedElementTransition(reactContext); - } - - @ReactProp(name = "sharedElementId") - public void setSharedElementId(SharedElementTransition elementTransition, String key) { - elementTransition.registerSharedElementTransition(key); - } - - @ReactProp(name = "duration") - public void setDuration(SharedElementTransition view, int duration) { - view.paramsParser.setDuration(duration); - } - - @ReactProp(name = "hideDuration") - public void setHideDuration(SharedElementTransition view, int duration) { - view.paramsParser.setHideDuration(duration); - } - - @ReactProp(name = "showDuration") - public void setShowDuration(SharedElementTransition view, int duration) { - view.paramsParser.setShowDuration(duration); - } - - @ReactProp(name = "showInterpolation") - public void setShowInterpolation(SharedElementTransition view, ReadableMap interpolation) { - view.paramsParser.setShowInterpolation(interpolation); - } - - @ReactProp(name = "hideInterpolation") - public void setHideInterpolation(SharedElementTransition view, ReadableMap interpolation) { - view.paramsParser.setHideInterpolation(interpolation); - } - - @ReactProp(name = "animateClipBounds") - public void setAnimateClipBounds(SharedElementTransition view, boolean animateClipBounds) { - view.paramsParser.animateClipBounds = animateClipBounds; - } - - @Override - protected void onAfterUpdateTransaction(SharedElementTransition view) { - view.showTransitionParams = view.paramsParser.parseShowTransitionParams(); - view.hideTransitionParams = view.paramsParser.parseHideTransitionParams(); - } - - @Override - public boolean needsCustomLayoutForChildren() { - return true; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/AnimatorValuesResolver.java b/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/AnimatorValuesResolver.java deleted file mode 100644 index 04e53e49404..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/AnimatorValuesResolver.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.reactnativenavigation.views.sharedElementTransition; - -import android.graphics.Rect; -import android.text.style.ForegroundColorSpan; -import android.widget.TextView; - -import com.facebook.drawee.drawable.ScalingUtils; -import com.facebook.drawee.generic.GenericDraweeHierarchy; -import com.facebook.drawee.view.DraweeView; -import com.facebook.react.views.image.ReactImageView; -import com.reactnativenavigation.params.InterpolationParams; -import com.reactnativenavigation.params.PathInterpolationParams; -import com.reactnativenavigation.params.parsers.SharedElementTransitionParams; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.utils.Point; - -class AnimatorValuesResolver { - - final Point fromXy; - final Point toXy; - final float startScaleX; - final float endScaleX; - final float startScaleY; - final float endScaleY; - int dx; - int dy; - int startX; - int startY; - int endX; - int endY; - float controlX1; - float controlY1; - float controlX2; - float controlY2; - int startColor; - int endColor; - Rect startDrawingRect = new Rect(); - Rect endDrawingRect = new Rect(); - final Rect fromBounds; - final Rect toBounds; - final ScalingUtils.ScaleType fromScaleType; - final ScalingUtils.ScaleType toScaleType; - - AnimatorValuesResolver(SharedElementTransition from, SharedElementTransition to, SharedElementTransitionParams params) { - fromXy = ViewUtils.getLocationOnScreen(from.getSharedView()); - toXy = ViewUtils.getLocationOnScreen(to.getSharedView()); - startScaleX = calculateStartScaleX(from, to); - endScaleX = calculateEndScaleX(from, to); - startScaleY = calculateStartScaleY(from, to); - endScaleY = calculateEndScaleY(from, to); - calculateColor(from, to); - calculate(params.interpolation); - fromBounds = calculateBounds(from); - toBounds = calculateBounds(to); - fromScaleType = getScaleType(from); - toScaleType = getScaleType(to); - calculateDrawingReacts(from, to); - } - - private ScalingUtils.ScaleType getScaleType(SharedElementTransition view) { - if (view.getSharedView() instanceof ReactImageView) { - return ((DraweeView) view.getSharedView()).getHierarchy().getActualImageScaleType(); - } - return null; - } - - private Rect calculateBounds(SharedElementTransition view) { - if (view.getSharedView() instanceof ReactImageView) { - return new Rect(0, 0, view.getSharedView().getWidth(), view.getSharedView().getHeight()); - } - return null; - } - - protected float calculateEndScaleY(SharedElementTransition from, SharedElementTransition to) { - return 1; - } - - protected float calculateStartScaleY(SharedElementTransition from, SharedElementTransition to) { - return ((float) from.getHeight()) / to.getHeight(); - } - - protected float calculateEndScaleX(SharedElementTransition from, SharedElementTransition to) { - return 1; - } - - protected float calculateStartScaleX(SharedElementTransition from, SharedElementTransition to) { - return ((float) from.getWidth()) / to.getWidth(); - } - - private void calculate(InterpolationParams interpolation) { - calculateDeltas(); - calculateStartPoint(); - calculateEndPoint(); - if (interpolation instanceof PathInterpolationParams) { - calculateControlPoints((PathInterpolationParams) interpolation); - } - } - - protected void calculateDeltas() { - dx = fromXy.x - toXy.x; - dy = fromXy.y - toXy.y; - } - - protected void calculateEndPoint() { - endX = 0; - endY = 0; - } - - protected void calculateStartPoint() { - startX = dx; - startY = dy; - } - - protected void calculateControlPoints(PathInterpolationParams interpolation) { - controlX1 = dx * interpolation.p1.x; - controlY1 = dy * interpolation.p1.y; - controlX2 = dx * interpolation.p2.x; - controlY2 = dy * interpolation.p2.y; - } - - private void calculateColor(SharedElementTransition from, SharedElementTransition to) { - if (from.getSharedView() instanceof TextView && to.getSharedView() instanceof TextView) { - ForegroundColorSpan[] startColorForegroundColorSpans = ViewUtils.getForegroundColorSpans((TextView) from.getSharedView()); - if (startColorForegroundColorSpans.length > 0) { - startColor = startColorForegroundColorSpans[0].getForegroundColor(); - } - ForegroundColorSpan[] endColorForegroundColorSpans = ViewUtils.getForegroundColorSpans((TextView) to.getSharedView()); - if (endColorForegroundColorSpans.length > 0) { - endColor = endColorForegroundColorSpans[0].getForegroundColor(); - } - } - } - - private void calculateDrawingReacts(SharedElementTransition from, SharedElementTransition to) { - from.getDrawingRect(startDrawingRect); - to.getDrawingRect(endDrawingRect); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/ControlPoint.java b/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/ControlPoint.java deleted file mode 100644 index 837e4471841..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/ControlPoint.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.reactnativenavigation.views.sharedElementTransition; - -import android.support.annotation.Nullable; - -public class ControlPoint { - public final float x; - public final float y; - - public ControlPoint(@Nullable Float x, float defaultX, Float y, float defaultY) { - this.x = x == null ? defaultX : x; - this.y = y == null ? defaultY : y; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/ReversedAnimatorValuesResolver.java b/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/ReversedAnimatorValuesResolver.java deleted file mode 100644 index 4c0d3720704..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/ReversedAnimatorValuesResolver.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.reactnativenavigation.views.sharedElementTransition; - -import com.reactnativenavigation.params.PathInterpolationParams; -import com.reactnativenavigation.params.parsers.SharedElementTransitionParams; - -class ReversedAnimatorValuesResolver extends AnimatorValuesResolver { - - ReversedAnimatorValuesResolver(SharedElementTransition from, SharedElementTransition to, SharedElementTransitionParams params) { - super(from, to, params); - } - - @Override - protected void calculateControlPoints(PathInterpolationParams interpolation) { - controlX1 = dx * interpolation.p1.x; - controlY1 = dy * interpolation.p1.y; - controlX2 = dx * interpolation.p2.x; - controlY2 = dy * interpolation.p2.y; - } - - @Override - protected float calculateEndScaleY(SharedElementTransition from, SharedElementTransition to) { - return ((float) to.getHeight()) / from.getHeight(); - } - - @Override - protected float calculateStartScaleY(SharedElementTransition from, SharedElementTransition to) { - return 1; - } - - @Override - protected float calculateEndScaleX(SharedElementTransition from, SharedElementTransition to) { - return ((float) to.getWidth()) / from.getWidth(); - } - - @Override - protected float calculateStartScaleX(SharedElementTransition from, SharedElementTransition to) { - return 1; - } - - @Override - protected void calculateEndPoint() { - endX = dx; - endY = dy; - } - - @Override - protected void calculateStartPoint() { - startX = 0; - startY = 0; - } - - @Override - protected void calculateDeltas() { - dx = toXy.x - fromXy.x; - dy = toXy.y - fromXy.y; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElementAnimatorCreator.java b/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElementAnimatorCreator.java deleted file mode 100644 index 91662b1e692..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElementAnimatorCreator.java +++ /dev/null @@ -1,178 +0,0 @@ -package com.reactnativenavigation.views.sharedElementTransition; - -import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.support.annotation.NonNull; -import android.view.View; - -import com.facebook.drawee.drawable.ScalingUtils; -import com.facebook.drawee.generic.GenericDraweeHierarchy; -import com.facebook.drawee.view.DraweeView; -import com.reactnativenavigation.params.InterpolationParams; -import com.reactnativenavigation.params.PathInterpolationParams; -import com.reactnativenavigation.params.parsers.SharedElementTransitionParams; -import com.reactnativenavigation.views.utils.AnimatorPath; -import com.reactnativenavigation.views.utils.ClipBoundsEvaluator; -import com.reactnativenavigation.views.utils.ColorUtils; -import com.reactnativenavigation.views.utils.LabColorEvaluator; -import com.reactnativenavigation.views.utils.PathEvaluator; - -import java.util.ArrayList; -import java.util.List; - -import static android.animation.ObjectAnimator.ofFloat; - -class SharedElementAnimatorCreator { - private final SharedElementTransition from; - private final SharedElementTransition to; - - SharedElementAnimatorCreator(SharedElementTransition from, SharedElementTransition to) { - this.from = from; - this.to = to; - } - - List createShow() { - return create(new AnimatorValuesResolver(from, to, to.showTransitionParams), to.showTransitionParams); - } - - List createHide() { - return create(new ReversedAnimatorValuesResolver(to, from, to.hideTransitionParams), to.hideTransitionParams); - } - - @NonNull - private List create(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - List result = new ArrayList<>(); - if (shouldAddCurvedMotionAnimator(resolver, params.interpolation)) { - result.add(createCurvedMotionAnimator(resolver, params)); - } else { - if (shouldAddLinearMotionXAnimator(resolver)) { - result.add(createXAnimator(resolver, params)); - } - if (shouldAddLinearMotionYAnimator(resolver)) { - result.add(createYAnimator(resolver, params)); - } - } - if (shouldAddScaleXAnimator(resolver, params)) { - result.add(createScaleXAnimator(resolver, params)); - } - if (shouldAddScaleYAnimator(resolver, params)) { - result.add(createScaleYAnimator(resolver, params)); - } - if (shouldAddColorAnimator(resolver)) { - result.add(createColorAnimator(resolver, params.duration)); - } - if (shouldAddImageClipBoundsAnimator(params)) { - result.add(createImageClipBoundsAnimator(resolver, params)); - result.add(createImageTransformAnimator(resolver, params)); - } - return result; - } - - private boolean shouldAddScaleYAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - return resolver.startScaleY != resolver.endScaleY && !params.animateClipBounds; - } - - private boolean shouldAddScaleXAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - return resolver.startScaleX != resolver.endScaleX && !params.animateClipBounds; - } - - private boolean shouldAddLinearMotionXAnimator(AnimatorValuesResolver resolver) { - return resolver.dx != 0; - } - - private boolean shouldAddLinearMotionYAnimator(AnimatorValuesResolver resolver) { - return resolver.dy != 0; - } - - private boolean shouldAddCurvedMotionAnimator(AnimatorValuesResolver resolver, InterpolationParams interpolation) { - return interpolation instanceof PathInterpolationParams && (resolver.dx != 0 || resolver.dy != 0); - } - - private boolean shouldAddColorAnimator(AnimatorValuesResolver resolver) { - return resolver.startColor != resolver.endColor; - } - - private boolean shouldAddImageClipBoundsAnimator(SharedElementTransitionParams params) { - return params.animateClipBounds; - } - - private ObjectAnimator createCurvedMotionAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - AnimatorPath path = new AnimatorPath(); - path.moveTo(resolver.startX, resolver.startY); - path.curveTo(resolver.controlX1, resolver.controlY1, resolver.controlX2, resolver.controlY2, resolver.endX, resolver.endY); - ObjectAnimator animator = ObjectAnimator.ofObject( - to, - "curvedMotion", - new PathEvaluator(), - path.getPoints().toArray()); - animator.setInterpolator(params.interpolation.easing.getInterpolator()); - animator.setDuration(params.duration); - return animator; - } - - private ObjectAnimator createXAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - ObjectAnimator animator = ofFloat(to.getSharedView(), View.TRANSLATION_X, resolver.startX, resolver.endX) - .setDuration(params.duration); - animator.setInterpolator(params.interpolation.easing.getInterpolator()); - return animator; - } - - private ObjectAnimator createYAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - ObjectAnimator animator = ofFloat(to.getSharedView(), View.TRANSLATION_Y, resolver.startY, resolver.endY) - .setDuration(params.duration); - animator.setInterpolator(params.interpolation.easing.getInterpolator()); - return animator; - } - - private ObjectAnimator createScaleXAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - to.getSharedView().setPivotX(0); - ObjectAnimator animator = - ofFloat(to.getSharedView(), View.SCALE_X, resolver.startScaleX, resolver.endScaleX) - .setDuration(params.duration); - animator.setInterpolator(params.interpolation.easing.getInterpolator()); - return animator; - } - - private ObjectAnimator createScaleYAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - to.getSharedView().setPivotY(0); - ObjectAnimator animator = - ofFloat(to.getSharedView(), View.SCALE_Y, resolver.startScaleY, resolver.endScaleY) - .setDuration(params.duration); - animator.setInterpolator(params.interpolation.easing.getInterpolator()); - return animator; - } - - private ObjectAnimator createColorAnimator(AnimatorValuesResolver resolver, int duration) { - return ObjectAnimator.ofObject( - to, - "textColor", - new LabColorEvaluator(), - ColorUtils.colorToLAB(resolver.startColor), - ColorUtils.colorToLAB(resolver.endColor)) - .setDuration(duration); - } - - private ObjectAnimator createImageClipBoundsAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - ObjectAnimator animator = ObjectAnimator.ofObject( - to, - "clipBounds", - new ClipBoundsEvaluator(), - resolver.startDrawingRect, - resolver.endDrawingRect) - .setDuration(params.duration); - animator.setInterpolator(params.interpolation.easing.getInterpolator()); - return animator; - } - private Animator createImageTransformAnimator(AnimatorValuesResolver resolver, SharedElementTransitionParams params) { - ScalingUtils.InterpolatingScaleType ist = new ScalingUtils.InterpolatingScaleType( - resolver.fromScaleType, - resolver.toScaleType, - resolver.fromBounds, - resolver.toBounds - ); - ((DraweeView) to.getSharedView()).getHierarchy().setActualImageScaleType(ist); - ObjectAnimator animator = ObjectAnimator.ofFloat(to, "matrixTransform", 0, 1).setDuration(params.duration); - animator.setInterpolator(params.interpolation.easing.getInterpolator()); - return animator; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElementTransition.java b/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElementTransition.java deleted file mode 100644 index 83fda67afc5..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElementTransition.java +++ /dev/null @@ -1,179 +0,0 @@ -package com.reactnativenavigation.views.sharedElementTransition; - -import android.content.Context; -import android.graphics.Rect; -import android.os.Build; -import android.support.annotation.Keep; -import android.text.SpannableString; -import android.text.SpannedString; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewManager; -import android.widget.FrameLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.facebook.drawee.drawable.ScalingUtils; -import com.facebook.drawee.generic.GenericDraweeHierarchy; -import com.facebook.drawee.view.DraweeView; -import com.facebook.react.views.image.ReactImageView; -import com.reactnativenavigation.params.parsers.SharedElementParamsParser; -import com.reactnativenavigation.params.parsers.SharedElementTransitionParams; -import com.reactnativenavigation.react.ReactViewHacks; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.Task; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.utils.ColorUtils; -import com.reactnativenavigation.views.utils.PathPoint; -import com.reactnativenavigation.views.utils.Point; - -public class SharedElementTransition extends FrameLayout { - public ViewGroup.LayoutParams childLayoutParams; - - public SharedElementParamsParser paramsParser = new SharedElementParamsParser(); - public SharedElementTransitionParams showTransitionParams; - public SharedElementTransitionParams hideTransitionParams; - private View child; - private int childLeft; - private int childTop; - private int childWidth = -1; - private int childHeight = -1; - private SpannableString spannableText; - private SpannedString spannedText; - - public View getSharedView() { - return child; - } - - public SharedElementTransition(Context context) { - super(context); - } - - public void registerSharedElementTransition(final String key) { - ViewUtils.runOnPreDraw(this, new Runnable() { - @Override - public void run() { - ViewUtils.performOnParentScreen(SharedElementTransition.this, new Task() { - @Override - public void run(Screen screen) { - screen.registerSharedElement(SharedElementTransition.this, key); - } - }); - } - }); - } - - @Override - public void onViewAdded(final View child) { - if (child instanceof ReactImageView && this.child == null) { - ReactViewHacks.disableReactImageViewRemoteImageFadeInAnimation((ReactImageView) child); - } - this.child = child; - if (child instanceof TextView) { - saveTextViewSpannedText((TextView) child); - } - super.onViewAdded(child); - } - - private void saveTextViewSpannedText(final TextView view) { - ViewUtils.runOnPreDraw(view, new Runnable() { - @Override - public void run() { - if (spannableText == null) { - spannedText = new SpannedString(view.getText()); - } - if (spannableText == null) { - spannableText = new SpannableString(spannedText); - } - } - }); - } - - @Keep - public void setCurvedMotion(PathPoint xy) { - child.setTranslationX(xy.mX); - child.setTranslationY(xy.mY); - } - - @Keep - public void setTextColor(double[] color) { - if (child instanceof TextView) { - ViewUtils.setSpanColor(spannableText, ColorUtils.labToColor(color)); - ((TextView) child).setText(spannableText); - } - } - - @Keep - public void setClipBounds(Rect clipBounds) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - child.setClipBounds(clipBounds); - } - } - - @Keep - public void setMatrixTransform(float value) { - GenericDraweeHierarchy hierarchy = ((DraweeView) child).getHierarchy(); - ((ScalingUtils.InterpolatingScaleType) hierarchy.getActualImageScaleType()).setValue(value); - child.invalidate(); - } - - public void attachChildToScreen() { - ViewUtils.performOnParentScreen(this, new Task() { - @Override - public void run(Screen screen) { - saveChildParams(child); - Point childLocationInScreen = ViewUtils.getLocationOnScreen(child); - - RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(childWidth, childHeight); - removeView(child); - lp.leftMargin = childLocationInScreen.x; - lp.topMargin = childLocationInScreen.y; - - screen.addView(child, lp); - } - - private void saveChildParams(final View child) { - childLayoutParams = child.getLayoutParams(); - childLeft = child.getLeft(); - childTop = child.getTop(); - if (childWidth == -1) { - childWidth = child.getWidth(); - } - if (childHeight == -1) { - childHeight = child.getHeight(); - } - } - }); - } - - public void attachChildToSelf() { - ((ViewManager) child.getParent()).removeView(child); - child.setLeft(childLeft); - child.setTop(childTop); - restoreTextViewSpannedText(); - addView(child, new LayoutParams(childLayoutParams)); - } - - private void restoreTextViewSpannedText() { - if (child instanceof TextView) { - ((TextView) child).setText(spannedText); - spannedText = null; - spannableText = null; - } - } - - public void show() { - setVisibility(VISIBLE); - ViewUtils.runOnPreDraw(child, new Runnable() { - @Override - public void run() { - child.setAlpha(1); - } - }); - } - - public void hide() { - setVisibility(INVISIBLE); - child.setAlpha(0); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElements.java b/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElements.java deleted file mode 100644 index 39976948909..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElements.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.reactnativenavigation.views.sharedElementTransition; - -import android.view.View; - -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.utils.ViewVisibilityChecker; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -public class SharedElements { - // These need to be weak references or better yet - clear them in `onViewRemoved` - Map toElements; - private Map fromElements; - - public void setFromElements(Map fromElements) { - this.fromElements.clear(); - for (String fromElementKey : fromElements.keySet()) { - if (toElements.containsKey(fromElementKey)) { - this.fromElements.put(fromElementKey, fromElements.get(fromElementKey)); - } - } - } - - public void setToElements(Map toElements) { - this.toElements.clear(); - for (String toElementKey : toElements.keySet()) { - if (fromElements.containsKey(toElementKey)) { - this.toElements.put(toElementKey, toElements.get(toElementKey)); - } - } - } - - public Map getToElements() { - return toElements; - } - - SharedElementTransition getFromElement(String key) { - return fromElements.get(key); - } - - SharedElementTransition getToElement(String key) { - return toElements.get(key); - } - - public void addToElement(SharedElementTransition sharedElement, String key) { - toElements.put(key, sharedElement); - } - - public SharedElements() { - toElements = new HashMap<>(); - this.fromElements = new HashMap<>(); - } - - void performWhenChildViewsAreDrawn(final Runnable onReady) { - final AtomicInteger latch = new AtomicInteger(toElements.size()); - for (SharedElementTransition toElement : toElements.values()) { - ViewUtils.runOnPreDraw(toElement.getSharedView(), new Runnable() { - @Override - public void run() { - if (latch.decrementAndGet() == 0) { - onReady.run(); - } - } - }); - } - } - - void attachChildViewsToScreen() { - for (SharedElementTransition toElement : toElements.values()) { - toElement.attachChildToScreen(); - } - } - - void hideToElements() { - for (SharedElementTransition toElement : toElements.values()) { - toElement.hide(); - } - } - - void showToElements(final Runnable onReady) { - final AtomicInteger latch = new AtomicInteger(toElements.size()); - for (final SharedElementTransition toElement : toElements.values()) { - toElement.show(); - ViewUtils.runOnPreDraw(toElement, new Runnable() { - @Override - public void run() { - if (latch.decrementAndGet() == 0) { - onReady.run(); - } - } - }); - } - } - - void onShowAnimationEnd() { - for (SharedElementTransition toElement : toElements.values()) { - toElement.attachChildToSelf(); - } - } - - void hideFromElements() { - for (final SharedElementTransition fromElement : fromElements.values()) { - fromElement.post(new Runnable() { - @Override - public void run() { - fromElement.setVisibility(View.INVISIBLE); - } - }); - } - } - - void showToElements() { - for (SharedElementTransition toElement : toElements.values()) { - toElement.setVisibility(View.VISIBLE); - } - } - - void onHideAnimationStart() { - for (SharedElementTransition fromElement : fromElements.values()) { - fromElement.attachChildToScreen(); - fromElement.getSharedView().setAlpha(1); - } - } - - public void destroy() { - toElements.clear(); - fromElements.clear(); - } - - public void removeHiddenElements() { - Iterator iterator = toElements.keySet().iterator(); - while (iterator.hasNext()) { - String key = iterator.next(); - if (!ViewVisibilityChecker.check(toElements.get(key))) { - iterator.remove(); - fromElements.get(key).show(); - } - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElementsAnimator.java b/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElementsAnimator.java deleted file mode 100644 index 5a8de4a7cbc..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/sharedElementTransition/SharedElementsAnimator.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.reactnativenavigation.views.sharedElementTransition; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; - -import java.util.ArrayList; -import java.util.List; - -public class SharedElementsAnimator { - private final SharedElements sharedElements; - - public SharedElementsAnimator(SharedElements sharedElements) { - this.sharedElements = sharedElements; - } - - public void show(final Runnable onAnimationStart, final Runnable onAnimationEnd) { - sharedElements.hideToElements(); - sharedElements.performWhenChildViewsAreDrawn(new Runnable() { - @Override - public void run() { - final AnimatorSet animatorSet = createShowAnimators(); - sharedElements.attachChildViewsToScreen(); - sharedElements.showToElements(new Runnable() { - @Override - public void run() { - sharedElements.hideFromElements(); - animatorSet.start(); - } - }); - } - - private AnimatorSet createShowAnimators() { - final AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether(createTransitionAnimators()); - animatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - onAnimationStart.run(); - } - - @Override - public void onAnimationEnd(Animator animation) { - sharedElements.onShowAnimationEnd(); - onAnimationEnd.run(); - } - - @Override - public void onAnimationCancel(Animator animation) { - sharedElements.onShowAnimationEnd(); - } - }); - return animatorSet; - } - - private List createTransitionAnimators() { - List result = new ArrayList<>(); - for (String key : sharedElements.toElements.keySet()) { - SharedElementTransition toElement = sharedElements.getToElement(key); - SharedElementTransition fromElement = sharedElements.getFromElement(key); - result.addAll(new SharedElementAnimatorCreator(fromElement, toElement).createShow()); - } - return result; - } - }); - } - - public void hide(final Runnable onAnimationStart, final Runnable onAnimationEnd) { - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether(createHideTransitionAnimators()); - animatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - onAnimationStart.run(); - } - - @Override - public void onAnimationEnd(Animator animation) { - sharedElements.showToElements(); - onAnimationEnd.run(); - } - }); - sharedElements.onHideAnimationStart(); - animatorSet.start(); - } - - private List createHideTransitionAnimators() { - List result = new ArrayList<>(); - for (String key : sharedElements.toElements.keySet()) { - result.addAll(new SharedElementAnimatorCreator(sharedElements.getToElement(key), sharedElements.getFromElement(key)).createHide()); - } - return result; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/slidingOverlay/OverlayViewMeasurer.java b/android/app/src/main/java/com/reactnativenavigation/views/slidingOverlay/OverlayViewMeasurer.java deleted file mode 100644 index f7786e6fe77..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/slidingOverlay/OverlayViewMeasurer.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.reactnativenavigation.views.slidingOverlay; - -import android.view.View; - -import com.reactnativenavigation.views.ContentView; -import com.reactnativenavigation.views.utils.ViewMeasurer; - -public class OverlayViewMeasurer extends ViewMeasurer { - private final ContentView view; - - public OverlayViewMeasurer(ContentView view) { - this.view = view; - } - - @Override - public int getMeasuredHeight(int heightMeasureSpec) { - View view = this.view.getChildAt(0); - if (view != null) { - return view.getMeasuredHeight(); - } - - return super.getMeasuredHeight(heightMeasureSpec); - } -} \ No newline at end of file diff --git a/android/app/src/main/java/com/reactnativenavigation/views/slidingOverlay/SlidingOverlay.java b/android/app/src/main/java/com/reactnativenavigation/views/slidingOverlay/SlidingOverlay.java deleted file mode 100644 index d7a6bde4b2b..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/slidingOverlay/SlidingOverlay.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.reactnativenavigation.views.slidingOverlay; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.view.View; -import android.widget.RelativeLayout; - -import com.reactnativenavigation.animation.PeekingAnimator; -import com.reactnativenavigation.params.SlidingOverlayParams; -import com.reactnativenavigation.params.SlidingOverlayParams.Position; -import com.reactnativenavigation.screens.Screen; -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.ContentView; -import com.reactnativenavigation.views.utils.ViewMeasurer; - -public class SlidingOverlay { - - private enum VisibilityState { - Hidden, AnimateHide, Shown, AnimateShow - } - - private ContentView view = null; - private final RelativeLayout parent; - private final SlidingOverlayParams params; - - private SlidingListener listener; - private VisibilityState visibilityState = VisibilityState.Hidden; - - public interface SlidingListener { - void onSlidingOverlayGone(); - void onSlidingOverlayShown(); - } - - public SlidingOverlay(RelativeLayout parent, SlidingOverlayParams params) { - this.parent = parent; - this.params = params; - } - - public void setSlidingListener(SlidingListener listener) { - this.listener = listener; - } - - public Integer getAutoDismissTimerSec() { - return params.autoDismissTimerSec; - } - - public void show() { - view = createSlidingOverlayView(params); - parent.addView(view); - - view.setOnDisplayListener(new Screen.OnDisplayListener() { - @Override - public void onDisplay() { - final PeekingAnimator animator = new PeekingAnimator(view, params.position, true); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationCancel(Animator animator) { - onSlidingOverlayShown(view); - } - - @Override - public void onAnimationEnd(Animator animator) { - onSlidingOverlayShown(view); - } - }); - - view.setVisibility(View.VISIBLE); - visibilityState = VisibilityState.AnimateShow; - animator.animate(); - } - }); - } - - public void hide() { - final PeekingAnimator animator = new PeekingAnimator(view, params.position, false); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationCancel(Animator animator) { - onSlidingOverlayEnd(view); - } - - @Override - public void onAnimationEnd(Animator animator) { - onSlidingOverlayEnd(view); - } - }); - - visibilityState = VisibilityState.AnimateHide; - animator.animate(); - } - - public void destroy() { - visibilityState = VisibilityState.Hidden; - view.unmountReactView(); - parent.removeView(view); - } - - public boolean isShowing() { - return VisibilityState.AnimateShow == visibilityState; - } - - public boolean isVisible() { - return VisibilityState.Shown == visibilityState; - } - - public boolean isHiding() { - return VisibilityState.AnimateHide == visibilityState; - } - - protected ContentView createSlidingOverlayView(SlidingOverlayParams params) { - final RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); - lp.addRule(params.position == Position.Top ? RelativeLayout.ALIGN_PARENT_TOP : RelativeLayout.ALIGN_PARENT_BOTTOM); - - final ContentView view = new ContentView(parent.getContext(), params.screenInstanceId, params.navigationParams); - view.setViewMeasurer(new OverlayViewMeasurer(view)); - view.setLayoutParams(lp); - view.setVisibility(View.INVISIBLE); - return view; - } - - protected void onSlidingOverlayShown(ContentView view) { - visibilityState = VisibilityState.Shown; - if (listener != null) { - listener.onSlidingOverlayShown(); - } - } - - protected void onSlidingOverlayEnd(ContentView view) { - destroy(); - - if (listener != null) { - listener.onSlidingOverlayGone(); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/slidingOverlay/SlidingOverlaysQueue.java b/android/app/src/main/java/com/reactnativenavigation/views/slidingOverlay/SlidingOverlaysQueue.java deleted file mode 100644 index f60901f6b5d..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/slidingOverlay/SlidingOverlaysQueue.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.reactnativenavigation.views.slidingOverlay; - -import com.reactnativenavigation.NavigationApplication; - -import java.util.LinkedList; -import java.util.Queue; -import java.util.Timer; -import java.util.TimerTask; - -public class SlidingOverlaysQueue implements SlidingOverlay.SlidingListener{ - - private static final int SHORT_SUSTAIN_DURATION = 500; - - protected Timer autoDismissTimer = null; - protected boolean pendingHide; - protected Queue queue = new LinkedList<>(); - - public void add(final SlidingOverlay slidingOverlay) { - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - queue.add(slidingOverlay); - if (queue.size() == 1) { - dispatchNextSlidingOverlay(); - } - else { - SlidingOverlay currentOverlay = queue.peek(); - if (currentOverlay != null && currentOverlay.isVisible()) { - if (autoDismissTimer != null) { - autoDismissTimer.cancel(); - autoDismissTimer = null; - } - currentOverlay.hide(); - } - } - } - }); - } - - public void remove() { - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - SlidingOverlay currentOverlay = queue.peek(); - - if(currentOverlay == null) { - return; - } - - if (currentOverlay.isShowing()) { - pendingHide = true; - } - else if (currentOverlay.isVisible()) { - cancelTimer(); - currentOverlay.hide(); - } - } - }); - } - - @Override - public void onSlidingOverlayShown() { - Integer autoDismissTimerSec = queue.peek() == null ? null : queue.peek().getAutoDismissTimerSec(); - - if (autoDismissTimerSec != null || pendingHide || queue.size() > 1) { - int autoDismissDuration = autoDismissTimerSec != null - ? autoDismissTimerSec * 1000 - : SHORT_SUSTAIN_DURATION; - pendingHide = false; - - autoDismissTimer = new Timer(); - autoDismissTimer.schedule(new TimerTask() { - @Override - public void run() { - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - if(queue.peek() != null) { - queue.peek().hide(); - } - } - }); - } - }, autoDismissDuration); - } - } - - @Override - public void onSlidingOverlayGone() { - queue.poll(); - dispatchNextSlidingOverlay(); - } - - public void destroy() { - SlidingOverlay currentOverlay = queue.poll(); - while (!queue.isEmpty()) { - queue.poll(); - } - - if (currentOverlay != null) { - cancelTimer(); - currentOverlay.setSlidingListener(null); - currentOverlay.destroy(); - } - } - - protected void dispatchNextSlidingOverlay() { - NavigationApplication.instance.runOnMainThread(new Runnable() { - @Override - public void run() { - final SlidingOverlay nextSlidingOverlay = queue.peek(); - if (nextSlidingOverlay != null) { - nextSlidingOverlay.setSlidingListener(SlidingOverlaysQueue.this); - nextSlidingOverlay.show(); - } - } - }); - } - - protected void cancelTimer() { - if (autoDismissTimer != null) { - autoDismissTimer.cancel(); - autoDismissTimer = null; - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/AnimatorPath.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/AnimatorPath.java deleted file mode 100644 index 48ea1379555..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/AnimatorPath.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.reactnativenavigation.views.utils; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * A simple Path object that holds information about the points along - * a path. The API allows you to specify a move location (which essentially - * jumps from the previous point in the path to the new one), a line location - * (which creates a line segment from the previous location) and a curve - * location (which creates a B�zier curve from the previous location). - */ -public class AnimatorPath { - - // The points in the path - ArrayList mPoints = new ArrayList(); - /** - * Move from the current path point to the new one - * specified by x and y. This will create a discontinuity if this point is - * neither the first point in the path nor the same as the previous point - * in the path. - */ - public void moveTo(float x, float y) { - mPoints.add(PathPoint.moveTo(x, y)); - } - /** - * Create a straight line from the current path point to the new one - * specified by x and y. - */ - public void lineTo(float x, float y) { - mPoints.add(PathPoint.lineTo(x, y)); - } - /** - * Create a quadratic B�zier curve from the current path point to the new one - * specified by x and y. The curve uses the current path location as the first anchor - * point, the control points (c0X, c0Y) and (c1X, c1Y), and (x, y) as the end anchor. - */ - public void curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) { - mPoints.add(PathPoint.curveTo(c0X, c0Y, c1X, c1Y, x, y)); - } - /** - * Returns a Collection of PathPoint objects that describe all points in the path. - */ - public Collection getPoints() { - return mPoints; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/ClipBoundsEvaluator.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/ClipBoundsEvaluator.java deleted file mode 100644 index 5fe2227e47c..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/ClipBoundsEvaluator.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.reactnativenavigation.views.utils; - -import android.animation.TypeEvaluator; -import android.graphics.Rect; - -public class ClipBoundsEvaluator implements TypeEvaluator { - private int fromWidth; - private int fromHeight; - private int toWidth; - private int toHeight; - private final Rect result = new Rect(); - - @Override - public Rect evaluate(float ratio, Rect from, Rect to) { - sync(from, to); - - if (toHeight == fromHeight ) { - result.bottom = toHeight; - } else { - if (toHeight > fromHeight) { - result.bottom = (int) (toHeight - (toHeight - fromHeight) * (1 - ratio)); - } else { - result.bottom = (int) (toHeight + (fromHeight - toHeight) * (1 - ratio)); - } - } - - if (toWidth == fromWidth) { - result.right = toWidth; - } else { - if (toWidth > fromWidth) { - result.right = (int) (toWidth - (toWidth - fromWidth) * (1 - ratio)); - } else { - result.right = (int) (toWidth + (fromWidth - toWidth) * (1 - ratio)); - } - } - return result; - } - - private void sync(Rect from, Rect to) { - fromWidth = from.right; - fromHeight = from.bottom; - toWidth = to.right; - toHeight = to.bottom; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/ColorUtils.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/ColorUtils.java deleted file mode 100644 index 86509fe68ea..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/ColorUtils.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.reactnativenavigation.views.utils; - -public class ColorUtils { - public static double[] colorToLAB(int color) { - final double[] result = new double[3]; - android.support.v4.graphics.ColorUtils.colorToLAB(color, result); - return result; - } - - public static int labToColor(double[] lab) { - return android.support.v4.graphics.ColorUtils.LABToColor(lab[0], lab[1], lab[2]); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/Constants.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/Constants.java deleted file mode 100644 index 4838115ff01..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/Constants.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.reactnativenavigation.views.utils; - -import com.reactnativenavigation.utils.ViewUtils; - -public class Constants { - public static final int BOTTOM_TABS_HEIGHT = (int) ViewUtils.convertDpToPixel(56); - public static final int TOOLBAR_BUTTON_SIZE = (int) ViewUtils.convertDpToPixel(48); -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/LabColorEvaluator.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/LabColorEvaluator.java deleted file mode 100644 index 4e134a9d1e7..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/LabColorEvaluator.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.reactnativenavigation.views.utils; - -import android.animation.TypeEvaluator; -import android.support.v4.graphics.ColorUtils; - -public class LabColorEvaluator implements TypeEvaluator { - private final double[] color = new double[3]; - - @Override - public double[] evaluate(float ratio, double[] from, double[] to) { - ColorUtils.blendLAB(from, to, ratio, color); - return color; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/PathEvaluator.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/PathEvaluator.java deleted file mode 100644 index 19a0bdf05f1..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/PathEvaluator.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.reactnativenavigation.views.utils; - -import android.animation.TypeEvaluator; - -/** - * This evaluator interpolates between two PathPoint values given the value t, the - * proportion traveled between those points. The value of the interpolation depends - * on the operation specified by the endValue (the operation for the interval between - * PathPoints is always specified by the end point of that interval). - */ -public class PathEvaluator implements TypeEvaluator { - @Override - public PathPoint evaluate(float t, PathPoint startValue, PathPoint endValue) { - float x, y; - if (endValue.mOperation == PathPoint.CURVE) { - float oneMinusT = 1 - t; - x = oneMinusT * oneMinusT * oneMinusT * startValue.mX + - 3 * oneMinusT * oneMinusT * t * endValue.mControl0X + - 3 * oneMinusT * t * t * endValue.mControl1X + - t * t * t * endValue.mX; - y = oneMinusT * oneMinusT * oneMinusT * startValue.mY + - 3 * oneMinusT * oneMinusT * t * endValue.mControl0Y + - 3 * oneMinusT * t * t * endValue.mControl1Y + - t * t * t * endValue.mY; - } else if (endValue.mOperation == PathPoint.LINE) { - x = startValue.mX + t * (endValue.mX - startValue.mX); - y = startValue.mY + t * (endValue.mY - startValue.mY); - } else { - x = endValue.mX; - y = endValue.mY; - } - return PathPoint.moveTo(x, y); - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/PathPoint.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/PathPoint.java deleted file mode 100644 index b9e7f62b5d9..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/PathPoint.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.reactnativenavigation.views.utils; - -/** - * A class that holds information about a location and how the path should get to that - * location from the previous path location (if any). Any PathPoint holds the information for - * its location as well as the instructions on how to traverse the preceding interval from the - * previous location. - */ -public class PathPoint { - /** - * The possible path operations that describe how to move from a preceding PathPoint to the - * location described by this PathPoint. - */ - public static final int MOVE = 0; - public static final int LINE = 1; - public static final int CURVE = 2; - /** - * The location of this PathPoint - */ - public float mX; - public float mY; - - /** - * The first control point, if any, for a PathPoint of type CURVE - */ - float mControl0X, mControl0Y; - /** - * The second control point, if any, for a PathPoint of type CURVE - */ - float mControl1X, mControl1Y; - /** - * The motion described by the path to get from the previous PathPoint in an AnimatorPath - * to the location of this PathPoint. This can be one of MOVE, LINE, or CURVE. - */ - int mOperation; - /** - * Line/Move constructor - */ - private PathPoint(int operation, float x, float y) { - mOperation = operation; - mX = x; - mY = y; - } - /** - * Curve constructor - */ - private PathPoint(float c0X, float c0Y, float c1X, float c1Y, float x, float y) { - mControl0X = c0X; - mControl0Y = c0Y; - mControl1X = c1X; - mControl1Y = c1Y; - mX = x; - mY = y; - mOperation = CURVE; - } - /** - * Constructs and returns a PathPoint object that describes a line to the given xy location. - */ - public static PathPoint lineTo(float x, float y) { - return new PathPoint(LINE, x, y); - } - /** - * Constructs and returns a PathPoint object that describes a curve to the given xy location - * with the control points at c0 and c1. - */ - public static PathPoint curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) { - return new PathPoint(c0X, c0Y, c1X, c1Y, x, y); - } - - /** - * Constructs and returns a PathPoint object that describes a discontinuous move to the given - * xy location. - */ - public static PathPoint moveTo(float x, float y) { - return new PathPoint(MOVE, x, y); - } -} - diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/Point.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/Point.java deleted file mode 100644 index 22823f8cda6..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/Point.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.reactnativenavigation.views.utils; - -public class Point { - public int x; - public int y; - - public Point(int x, int y) { - this.x = x; - this.y = y; - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/ScrollViewDetector.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/ScrollViewDetector.java deleted file mode 100644 index 5f9cdc4ae55..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/ScrollViewDetector.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.reactnativenavigation.views.utils; - -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.widget.ScrollView; - -import com.reactnativenavigation.utils.ViewUtils; -import com.reactnativenavigation.views.ContentView; -import com.reactnativenavigation.views.collapsingToolbar.OnScrollViewAddedListener; -import com.reactnativenavigation.views.collapsingToolbar.ScrollViewDelegate; - -public class ScrollViewDetector { - private static final boolean SCROLLVIEW_FOUND = true; - private static final boolean SCROLLVIEW_NOT_FOUND = false; - private OnScrollViewAddedListener scrollViewAddedListener; - private ScrollViewDelegate scrollViewDelegate; - private View.OnAttachStateChangeListener scrollViewStateChangeListener; - private ViewTreeObserver.OnGlobalLayoutListener scrollViewDetectorListener; - - public ScrollViewDetector(ContentView contentView, OnScrollViewAddedListener onScrollViewAddedListener, - ScrollViewDelegate scrollViewDelegate) { - this.scrollViewAddedListener = onScrollViewAddedListener; - this.scrollViewDelegate = scrollViewDelegate; - scrollViewStateChangeListener = createScrollViewStateChangeListener(contentView, scrollViewDelegate); - } - - private StateChangeListenerAdapter createScrollViewStateChangeListener(final ContentView contentView, final ScrollViewDelegate scrollViewDelegate) { - return new StateChangeListenerAdapter() { - @Override - public void onViewDetachedFromWindow(View scrollView) { - scrollViewDelegate.getScrollView().removeOnAttachStateChangeListener(this); - scrollViewDelegate.onScrollViewRemoved(); - detectScrollView(scrollViewDelegate, contentView); - } - }; - } - - private void detectScrollView(final ScrollViewDelegate scrollViewDelegate, final ContentView contentView) { - scrollViewDetectorListener = new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - if (!scrollViewDelegate.hasScrollView()) { - if (findScrollView(contentView) && contentView.getViewTreeObserver().isAlive()) { - contentView.getViewTreeObserver().removeOnGlobalLayoutListener(scrollViewDetectorListener); - } - } - } - }; - contentView.getViewTreeObserver().addOnGlobalLayoutListener(scrollViewDetectorListener); - } - - public boolean findScrollView(View child) { - if (child instanceof ScrollView) { - onScrollViewFound((ScrollView) child); - return SCROLLVIEW_FOUND; - } else if (child instanceof ViewGroup) { - Object maybeScrollView = ViewUtils.findChildByClass((ViewGroup) child, ScrollView.class); - if (maybeScrollView instanceof ScrollView) { - onScrollViewFound((ScrollView) maybeScrollView); - return SCROLLVIEW_FOUND; - } - } - return SCROLLVIEW_NOT_FOUND; - } - - private void onScrollViewFound(final ScrollView scrollView) { - if (scrollViewDelegate != null && !scrollViewDelegate.hasScrollView()) { - scrollViewDelegate.onScrollViewAdded(scrollView); - scrollViewAddedListener.onScrollViewAdded(scrollView); - scrollView.addOnAttachStateChangeListener(scrollViewStateChangeListener); - } - } - - public void destroy() { - if (scrollViewDelegate.getScrollView() != null) { - scrollViewDelegate.getScrollView().removeOnAttachStateChangeListener(scrollViewStateChangeListener); - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/StateChangeListenerAdapter.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/StateChangeListenerAdapter.java deleted file mode 100644 index fcb1bfa1de8..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/StateChangeListenerAdapter.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.reactnativenavigation.views.utils; - -import android.view.View; - -class StateChangeListenerAdapter implements View.OnAttachStateChangeListener { - @Override - public void onViewAttachedToWindow(View view) { - - } - - @Override - public void onViewDetachedFromWindow(View view) { - - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/TopTabsIconColorHelper.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/TopTabsIconColorHelper.java deleted file mode 100644 index fb91e2b93ef..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/TopTabsIconColorHelper.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.reactnativenavigation.views.utils; - -import android.content.res.ColorStateList; -import android.graphics.drawable.Drawable; -import android.support.v4.graphics.drawable.DrawableCompat; - -import com.reactnativenavigation.params.StyleParams; -import com.reactnativenavigation.views.TopTabs; - -public class TopTabsIconColorHelper { - private final TopTabs topTabs; - private final StyleParams styleParams; - - public TopTabsIconColorHelper(TopTabs topTabs, StyleParams styleParams) { - this.topTabs = topTabs; - this.styleParams = styleParams; - } - - public void colorIcons(int selectedIconColor, int unselectedIconColor) { - ColorStateList colorStateList = getIconColorStateList(styleParams, selectedIconColor, unselectedIconColor); - colorIcons(colorStateList); - } - - private ColorStateList getIconColorStateList(StyleParams style, int selectedIconColor, int unselectedIconColor) { - int selectedColor = selectedIconColor; - int unselectedColor = unselectedIconColor; - if (style.topTabIconColor.hasColor()) { - unselectedColor = style.topTabIconColor.getColor(); - } - if (style.selectedTopTabIconColor.hasColor()) { - selectedColor = style.selectedTopTabIconColor.getColor(); - } - return createColorStateList(selectedColor, unselectedColor); - } - - private ColorStateList createColorStateList(int selectedColor, int unselectedIconColor) { - int[][] states = new int[][] { - new int[]{android.R.attr.state_pressed}, - new int[]{android.R.attr.state_selected}, - new int[]{android.R.attr.state_enabled}, - new int[]{android.R.attr.state_focused, android.R.attr.state_pressed}, - new int[]{-android.R.attr.state_enabled}, - new int[]{} - }; - int[] colors = new int[]{ - selectedColor, - selectedColor, - unselectedIconColor, - unselectedIconColor, - unselectedIconColor, - unselectedIconColor - }; - return new ColorStateList(states, colors); - } - - private void colorIcons(ColorStateList colorStateList) { - for (int i = 0; i < topTabs.getTabCount(); i++) { - Drawable icon = topTabs.getTabAt(i).getIcon(); - if (icon != null) { - icon = DrawableCompat.wrap(icon); - DrawableCompat.setTintList(icon, colorStateList); - } - } - } -} diff --git a/android/app/src/main/java/com/reactnativenavigation/views/utils/ViewMeasurer.java b/android/app/src/main/java/com/reactnativenavigation/views/utils/ViewMeasurer.java deleted file mode 100644 index 4ef92bf6375..00000000000 --- a/android/app/src/main/java/com/reactnativenavigation/views/utils/ViewMeasurer.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.reactnativenavigation.views.utils; - -import static android.view.View.MeasureSpec; - -public class ViewMeasurer { - - public int getMeasuredHeight(int heightMeasureSpec) { - return MeasureSpec.getSize(heightMeasureSpec); - } - - public int getMeasuredWidth(int widthMeasureSpec) { - return MeasureSpec.getSize(widthMeasureSpec); - } -} diff --git a/android/app/src/main/res/anim/lightbox_enter.xml b/android/app/src/main/res/anim/lightbox_enter.xml deleted file mode 100644 index f0bada716ba..00000000000 --- a/android/app/src/main/res/anim/lightbox_enter.xml +++ /dev/null @@ -1,3 +0,0 @@ - - diff --git a/android/app/src/main/res/anim/no_animation.xml b/android/app/src/main/res/anim/no_animation.xml deleted file mode 100644 index 15144d88ecf..00000000000 --- a/android/app/src/main/res/anim/no_animation.xml +++ /dev/null @@ -1,6 +0,0 @@ - - \ No newline at end of file diff --git a/android/app/src/main/res/anim/pop.xml b/android/app/src/main/res/anim/pop.xml deleted file mode 100644 index 680f937372d..00000000000 --- a/android/app/src/main/res/anim/pop.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/anim/slide_down.xml b/android/app/src/main/res/anim/slide_down.xml deleted file mode 100644 index 0fe35cd47df..00000000000 --- a/android/app/src/main/res/anim/slide_down.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/anim/slide_in_right.xml b/android/app/src/main/res/anim/slide_in_right.xml deleted file mode 100644 index 70769db07da..00000000000 --- a/android/app/src/main/res/anim/slide_in_right.xml +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/android/app/src/main/res/anim/slide_out_right.xml b/android/app/src/main/res/anim/slide_out_right.xml deleted file mode 100644 index 70769db07da..00000000000 --- a/android/app/src/main/res/anim/slide_out_right.xml +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/android/app/src/main/res/anim/slide_up.xml b/android/app/src/main/res/anim/slide_up.xml deleted file mode 100644 index 6c803d6c621..00000000000 --- a/android/app/src/main/res/anim/slide_up.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/android/app/src/main/res/drawable-hdpi/ic_action_name.png b/android/app/src/main/res/drawable-hdpi/ic_action_name.png deleted file mode 100644 index 407fb1be686..00000000000 Binary files a/android/app/src/main/res/drawable-hdpi/ic_action_name.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-hdpi/search.png b/android/app/src/main/res/drawable-hdpi/search.png deleted file mode 100644 index 407fb1be686..00000000000 Binary files a/android/app/src/main/res/drawable-hdpi/search.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_action_name.png b/android/app/src/main/res/drawable-mdpi/ic_action_name.png deleted file mode 100644 index 55c36f9ce84..00000000000 Binary files a/android/app/src/main/res/drawable-mdpi/ic_action_name.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-mdpi/search.png b/android/app/src/main/res/drawable-mdpi/search.png deleted file mode 100644 index 55c36f9ce84..00000000000 Binary files a/android/app/src/main/res/drawable-mdpi/search.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_action_name.png b/android/app/src/main/res/drawable-xhdpi/ic_action_name.png deleted file mode 100644 index 2d270ff6135..00000000000 Binary files a/android/app/src/main/res/drawable-xhdpi/ic_action_name.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-xhdpi/search.png b/android/app/src/main/res/drawable-xhdpi/search.png deleted file mode 100644 index 2d270ff6135..00000000000 Binary files a/android/app/src/main/res/drawable-xhdpi/search.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_action_name.png b/android/app/src/main/res/drawable-xxhdpi/ic_action_name.png deleted file mode 100644 index d0d4d59ed3b..00000000000 Binary files a/android/app/src/main/res/drawable-xxhdpi/ic_action_name.png and /dev/null differ diff --git a/android/app/src/main/res/drawable-xxhdpi/search.png b/android/app/src/main/res/drawable-xxhdpi/search.png deleted file mode 100644 index d0d4d59ed3b..00000000000 Binary files a/android/app/src/main/res/drawable-xxhdpi/search.png and /dev/null differ diff --git a/android/app/src/main/res/menu/search_item.xml b/android/app/src/main/res/menu/search_item.xml deleted file mode 100644 index 3587a70296d..00000000000 --- a/android/app/src/main/res/menu/search_item.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/android/app/src/main/res/menu/stub.xml b/android/app/src/main/res/menu/stub.xml deleted file mode 100644 index fe187c0cf47..00000000000 --- a/android/app/src/main/res/menu/stub.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/android/app/src/main/res/values/config.xml b/android/app/src/main/res/values/config.xml deleted file mode 100644 index d2edca4138f..00000000000 --- a/android/app/src/main/res/values/config.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 250 - \ No newline at end of file diff --git a/android/app/src/main/res/values/ids.xml b/android/app/src/main/res/values/ids.xml deleted file mode 100644 index 6d5071f8741..00000000000 --- a/android/app/src/main/res/values/ids.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml deleted file mode 100644 index d56d40ca0f4..00000000000 --- a/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/android/app/src/test/java/com/reactnativenavigation/EnvironmentTest.java b/android/app/src/test/java/com/reactnativenavigation/EnvironmentTest.java deleted file mode 100644 index 41750f972c1..00000000000 --- a/android/app/src/test/java/com/reactnativenavigation/EnvironmentTest.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.reactnativenavigation; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -import static org.assertj.core.api.Java6Assertions.assertThat; - -@RunWith(RobolectricTestRunner.class) -public class EnvironmentTest { - @Test - public void assertJ() { - assertThat(1 + 2).isEqualTo(3).isGreaterThan(2).isLessThan(4).isNotNegative().isPositive().isNotZero(); - } -} diff --git a/android/app/src/test/resources/robolectric.properties b/android/app/src/test/resources/robolectric.properties deleted file mode 100644 index 069fdfd9dbe..00000000000 --- a/android/app/src/test/resources/robolectric.properties +++ /dev/null @@ -1,2 +0,0 @@ -manifest: src/main/AndroidManifest.xml -sdk: 23 diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index f3bd7d318d3..00000000000 --- a/android/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -// 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.2' - - // 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 deleted file mode 100644 index 1fd964e90b1..00000000000 --- a/android/gradle.properties +++ /dev/null @@ -1,20 +0,0 @@ -# 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.properties b/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 7fb4cf5de7a..00000000000 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Mon Sep 12 16:05:44 IDT 2016 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-bin.zip diff --git a/android/gradlew b/android/gradlew deleted file mode 100755 index 27309d92314..00000000000 --- a/android/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# 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\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# 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 -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -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" -a "$nonstop" = "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"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # 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/prepare-robolectric.gradle b/android/prepare-robolectric.gradle deleted file mode 100644 index 5644885ce3c..00000000000 --- a/android/prepare-robolectric.gradle +++ /dev/null @@ -1,34 +0,0 @@ -def robolectricDependenciesFolder = rootProject.buildDir.path + "/robolectric-dependencies" - -configurations.create('robolectricRuntime') - -dependencies { - robolectricRuntime "org.ccil.cowan.tagsoup:tagsoup:1.2" - robolectricRuntime "org.robolectric:android-all:6.0.0_r1-robolectric-0" - robolectricRuntime "org.robolectric:shadows-core-v23:3.1.4" - robolectricRuntime "org.json:json:20080701" -} - -rootProject.task(type: Copy, overwrite: true, "downloadRobolectricDependencies") { - println "downloadRobolectricDependencies " + robolectricDependenciesFolder - from configurations.robolectricRuntime - into robolectricDependenciesFolder -} - -project.afterEvaluate { - tasks.all { - if (it.name.startsWith("test")) { - it.dependsOn(rootProject.tasks.findByName("downloadRobolectricDependencies")) - } - } -} - -android { - testOptions { - unitTests.all { - systemProperty 'robolectric.offline', 'true' - systemProperty 'robolectric.dependency.dir', robolectricDependenciesFolder - } - } -} - diff --git a/autolink/fixtures/rn77/AppDelegate.mm.template b/autolink/fixtures/rn77/AppDelegate.mm.template new file mode 100644 index 00000000000..b85dd4ad8df --- /dev/null +++ b/autolink/fixtures/rn77/AppDelegate.mm.template @@ -0,0 +1,36 @@ +#import "AppDelegate.h" + +#import + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.moduleName = @"app"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = @{}; + + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ +#if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; +#else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +#endif +} + +/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. +- (BOOL)concurrentRootEnabled +{ + return true; +} + +@end \ No newline at end of file diff --git a/autolink/fixtures/rn77/AppDelegate.swift.template b/autolink/fixtures/rn77/AppDelegate.swift.template new file mode 100644 index 00000000000..1b0c273a58a --- /dev/null +++ b/autolink/fixtures/rn77/AppDelegate.swift.template @@ -0,0 +1,30 @@ +import UIKit +import React +import React_RCTAppDelegate +import ReactAppDependencyProvider + +@main +class AppDelegate: RCTAppDelegate { + override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + self.moduleName = "app" + self.dependencyProvider = RCTAppDependencyProvider() + + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = [:] + + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + override func sourceURL(for bridge: RCTBridge) -> URL? { + self.bundleURL() + } + + override func bundleURL() -> URL? { +#if DEBUG + RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") +#else + Bundle.main.url(forResource: "main", withExtension: "jsbundle") +#endif + } +} \ No newline at end of file diff --git a/autolink/fixtures/rn77/MainActivity.kt.template b/autolink/fixtures/rn77/MainActivity.kt.template new file mode 100644 index 00000000000..853728d56a1 --- /dev/null +++ b/autolink/fixtures/rn77/MainActivity.kt.template @@ -0,0 +1,22 @@ +package com.app + +import com.facebook.react.ReactActivity +import com.facebook.react.ReactActivityDelegate +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled +import com.facebook.react.defaults.DefaultReactActivityDelegate + +class MainActivity : ReactActivity() { + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + override fun getMainComponentName(): String = "rn770" + + /** + * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] + * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] + */ + override fun createReactActivityDelegate(): ReactActivityDelegate = + DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) +} diff --git a/autolink/fixtures/rn77/MainApplication.kt.template b/autolink/fixtures/rn77/MainApplication.kt.template new file mode 100644 index 00000000000..9e7449efca7 --- /dev/null +++ b/autolink/fixtures/rn77/MainApplication.kt.template @@ -0,0 +1,44 @@ +package com.app + +import android.app.Application +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.react.soloader.OpenSourceMergedSoMapping +import com.facebook.soloader.SoLoader + +class MainApplication : Application(), ReactApplication { + + override val reactNativeHost: ReactNativeHost = + object : DefaultReactNativeHost(this) { + override fun getPackages(): List = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } + + override fun getJSMainModuleName(): String = "index" + + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(applicationContext, reactNativeHost) + + override fun onCreate() { + super.onCreate() + SoLoader.init(this, OpenSourceMergedSoMapping) + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + load() + } + } +} diff --git a/autolink/fixtures/rn77/build.gradle.template b/autolink/fixtures/rn77/build.gradle.template new file mode 100644 index 00000000000..9766946918e --- /dev/null +++ b/autolink/fixtures/rn77/build.gradle.template @@ -0,0 +1,21 @@ +buildscript { + ext { + buildToolsVersion = "35.0.0" + minSdkVersion = 24 + compileSdkVersion = 35 + targetSdkVersion = 35 + ndkVersion = "27.1.12297006" + kotlinVersion = "2.0.21" + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle") + classpath("com.facebook.react:react-native-gradle-plugin") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") + } +} + +apply plugin: "com.facebook.react.rootproject" diff --git a/autolink/postlink.sh b/autolink/postlink.sh new file mode 100644 index 00000000000..fd28fcac25c --- /dev/null +++ b/autolink/postlink.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -e + +echo "RNN postlink !!!!!!!!!!!!!!!!!" \ No newline at end of file diff --git a/autolink/postlink/__helpers__/fixtures.js b/autolink/postlink/__helpers__/fixtures.js new file mode 100644 index 00000000000..db8f05be2ff --- /dev/null +++ b/autolink/postlink/__helpers__/fixtures.js @@ -0,0 +1,24 @@ +const prepareFixtureDuplicate = ({ rnVersion, userFixtureFileName, patchedFixtureFileName }) => { + const fs = require('node:fs'); + const path = require('node:path'); + const os = require('node:os'); + + const userFixtureRelPath = _getRelativeFixturePath(rnVersion, userFixtureFileName); + + const userFixturePath = path.resolve(userFixtureRelPath); + const patchedFixturePath = path.resolve(os.tmpdir(), patchedFixtureFileName); + fs.copyFileSync(userFixturePath, patchedFixturePath); + + return patchedFixturePath; +}; + +const _getRelativeFixturePath = (rnVersion, fixtureFileName) => { + const path = require('node:path'); + return path.join('autolink', 'fixtures', `rn${rnVersion}`, fixtureFileName); +}; + +module.exports = { + prepareFixtureDuplicate, + prepareFixtureDuplicate77: ({ userFixtureFileName, patchedFixtureFileName }) => + prepareFixtureDuplicate({ rnVersion: '77', userFixtureFileName, patchedFixtureFileName }), +}; diff --git a/autolink/postlink/__mocks__/log.js b/autolink/postlink/__mocks__/log.js new file mode 100644 index 00000000000..1a4e22482ed --- /dev/null +++ b/autolink/postlink/__mocks__/log.js @@ -0,0 +1,11 @@ +module.exports = { + log: console.log, + logn: console.log, + warn: console.log, + warnn: console.log, + info: console.log, + infon: console.log, + debug: console.log, + debugn: console.log, + errorn: console.log, +}; diff --git a/autolink/postlink/__snapshots__/activityLinker.test.js.snap b/autolink/postlink/__snapshots__/activityLinker.test.js.snap new file mode 100644 index 00000000000..b6d8fedef60 --- /dev/null +++ b/autolink/postlink/__snapshots__/activityLinker.test.js.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`activityLinker should work for RN 0.77 1`] = ` +"package com.app + +import com.reactnativenavigation.NavigationActivity +import com.facebook.react.ReactActivityDelegate +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled +import com.facebook.react.defaults.DefaultReactActivityDelegate + +class MainActivity : NavigationActivity() { + + + + +} +" +`; diff --git a/autolink/postlink/__snapshots__/appDelegateLinker.test.js.snap b/autolink/postlink/__snapshots__/appDelegateLinker.test.js.snap new file mode 100644 index 00000000000..0331cedf2d4 --- /dev/null +++ b/autolink/postlink/__snapshots__/appDelegateLinker.test.js.snap @@ -0,0 +1,70 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`appDelegateLinker should work for RN 0.77 with Objective-C 1`] = ` +"#import "AppDelegate.h" +#import + +#import + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ +#if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; +#else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +#endif +} + +/// This method controls whether the \`concurrentRoot\`feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: \`true\` if the \`concurrentRoot\` feature is enabled. Otherwise, it returns \`false\`. +- (BOOL)concurrentRootEnabled +{ + return true; +} + +@end " +`; + +exports[`appDelegateLinker should work for RN 0.77 with Swift 1`] = ` +"import UIKit +import React +import ReactNativeNavigation +import ReactAppDependencyProvider + +@main +class AppDelegate: RNNAppDelegate { + override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + self.moduleName = "app" + self.dependencyProvider = RCTAppDependencyProvider() + + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = [:] + + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + override func sourceURL(for bridge: RCTBridge) -> URL? { + self.bundleURL() + } + + override func bundleURL() -> URL? { +#if DEBUG + RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") +#else + Bundle.main.url(forResource: "main", withExtension: "jsbundle") +#endif + } +} " +`; diff --git a/autolink/postlink/__snapshots__/applicationLinker.test.js.snap b/autolink/postlink/__snapshots__/applicationLinker.test.js.snap new file mode 100644 index 00000000000..282f1e5fc7c --- /dev/null +++ b/autolink/postlink/__snapshots__/applicationLinker.test.js.snap @@ -0,0 +1,47 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`applicationLinker should work for RN 0.77 1`] = ` +"package com.app + +import android.app.Application +import com.facebook.react.PackageList +import com.reactnativenavigation.NavigationApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.defaults.DefaultReactNativeHost +import com.reactnativenavigation.react.NavigationReactNativeHost +import com.facebook.react.soloader.OpenSourceMergedSoMapping +import com.facebook.soloader.SoLoader + +class MainApplication : NavigationApplication() { + + override val reactNativeHost: ReactNativeHost = + object : NavigationReactNativeHost(this) { + override fun getPackages(): List = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } + + override fun getJSMainModuleName(): String = "index" + + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(applicationContext, reactNativeHost) + + override fun onCreate() { + super.onCreate() + + + } +} +" +`; diff --git a/autolink/postlink/__snapshots__/gradleLinker.test.js.snap b/autolink/postlink/__snapshots__/gradleLinker.test.js.snap new file mode 100644 index 00000000000..5e035fbe6b3 --- /dev/null +++ b/autolink/postlink/__snapshots__/gradleLinker.test.js.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`gradleLinker should work for RN 0.77 1`] = ` +"buildscript { + ext { + RNNKotlinVersion = "2.0.21" + buildToolsVersion = "35.0.0" + minSdkVersion = 24 + compileSdkVersion = 35 + targetSdkVersion = 35 + ndkVersion = "27.1.12297006" + kotlinVersion = "2.0.21" + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle") + classpath("com.facebook.react:react-native-gradle-plugin") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin") + } +} + +apply plugin: "com.facebook.react.rootproject" +" +`; diff --git a/autolink/postlink/activityLinker.js b/autolink/postlink/activityLinker.js new file mode 100644 index 00000000000..d1c1cd1b5d6 --- /dev/null +++ b/autolink/postlink/activityLinker.js @@ -0,0 +1,120 @@ +// @ts-check +var path = require('./path'); +var fs = require('fs'); +var { errorn, warnn, logn, infon, debugn } = require('./log'); + +class ActivityLinker { + constructor() { + this.activityPath = path.mainActivityKotlin + this.extendNavigationActivitySuccess = false; + this.removeGetMainComponentNameSuccess = false; + this.removeCreateReactActivityDelegate = false; + } + + link() { + if (!this.activityPath) { + errorn( + ' MainActivity.kt not found! Does the file exist in the correct folder?\n Please check the manual installation docs:\n https://wix.github.io/react-native-navigation/docs/installing#2-update-mainactivityjava' + ); + return; + } + + logn('Linking MainActivity...'); + + var activityContent = fs.readFileSync(this.activityPath, 'utf8'); + + try { + activityContent = this._extendNavigationActivity(activityContent); + this.extendNavigationActivitySuccess = true; + } catch (e) { + errorn(' ' + e.message); + } + + try { + activityContent = this._removeGetMainComponentName(activityContent); + this.removeGetMainComponentNameSuccess = true; + } catch (e) { + errorn(' ' + e.message); + } + + activityContent = this._removeCreateReactActivityDelegate(activityContent); + + fs.writeFileSync(this.activityPath, activityContent); + if (this.extendNavigationActivitySuccess && this.removeGetMainComponentNameSuccess) { + infon('MainActivity.kt linked successfully!\n'); + } else if (!this.extendNavigationActivitySuccess && !this.removeGetMainComponentNameSuccess) { + errorn( + 'MainActivity.kt was not linked. Please check the logs above for more information and proceed with manual linking of the MainActivity file in Android:\nhttps://wix.github.io/react-native-navigation/docs/installing#2-update-mainactivityjava' + ); + } else { + warnn( + 'MainActivity.kt was only partially linked. Please check the logs above for more information and proceed with manual linking for the failed steps:\nhttps://wix.github.io/react-native-navigation/docs/installing#2-update-mainactivityjava' + ); + } + } + + _removeGetMainComponentName(contents) { + var match = /(\/\*\*[\s\S]*?\*\/\s*)?override\s+fun\s+getMainComponentName\s*\(\s*\)\s*:\s*String\s*(\{\s*return[\s\S]*?\}|=[\s\S]*?)/.exec( + contents + ); + if (match) { + debugn(' Removing getMainComponentName function'); + return contents.replace( + /(\/\*\*[\s\S]*?\*\/\s*)?override\s+fun\s+getMainComponentName\s*\(\s*\)\s*:\s*String\s*(\{\s*return[\s\S]*?\}|=[\s\S]*?(?=\n\s*(?:\/\*\*|override|fun|\}|$)))/, + '' + ); + } + warnn(' getMainComponentName function was not found.'); + return contents; + } + + _extendNavigationActivity(activityContent) { + if (this._hasAlreadyExtendNavigationActivity(activityContent)) { + warnn(' MainActivity already extends NavigationActivity'); + return activityContent; + } + + if (this._doesActivityExtendReactActivity(activityContent)) { + debugn(' Extending NavigationActivity'); + return activityContent + .replace(/:\s*ReactActivity\(\)\s*/, ': NavigationActivity() ') + .replace( + 'import com.facebook.react.ReactActivity', + 'import com.reactnativenavigation.NavigationActivity' + ); + } + + throw new Error( + 'MainActivity was not successfully replaced. Please check the documentation and proceed manually.' + ); + } + + _doesActivityExtendReactActivity(activityContent) { + return /class\s+MainActivity\s*:\s*ReactActivity\(\)\s*/.test(activityContent); + } + + _hasAlreadyExtendNavigationActivity(activityContent) { + return /class\s+MainActivity\s*:\s*NavigationActivity\(\)\s*/.test(activityContent); + } + + _removeCreateReactActivityDelegate(activityContent) { + if (this._hasCreateReactActivityDelegate(activityContent)) { + debugn(' Removing createReactActivityDelegate function'); + return activityContent.replace( + /(\/\*\*[\s\S]*?\*\/\s*)?override\s+fun\s+createReactActivityDelegate\s*\(\s*\)\s*:\s*ReactActivityDelegate\s*(\{\s*return[\s\S]*?\}|=[\s\S]*?(?=\n\s*(?:\/\*\*|override|fun|\}|$)))/, + '' + ); + } else { + warnn(' createReactActivityDelegate is already not defined in MainActivity'); + return activityContent; + } + } + + _hasCreateReactActivityDelegate(activityContent) { + return /(\/\*\*[\s\S]*?\*\/\s*)?override\s+fun\s+createReactActivityDelegate\s*\(\s*\)\s*:\s*ReactActivityDelegate\s*(\{\s*return[\s\S]*?\}|=[\s\S]*?)/.test( + activityContent + ); + } +} + +module.exports = ActivityLinker; diff --git a/autolink/postlink/activityLinker.test.js b/autolink/postlink/activityLinker.test.js new file mode 100644 index 00000000000..d601aca09b2 --- /dev/null +++ b/autolink/postlink/activityLinker.test.js @@ -0,0 +1,27 @@ +import fs from 'node:fs'; +import * as mockHelpers from './__helpers__/fixtures'; + +jest.mock('./log'); + +describe('activityLinker', () => { + it('should work for RN 0.77', () => { + jest.mock('./path', () => { + const mainActivityPath = mockHelpers.prepareFixtureDuplicate77({ + rnVersion: '77', + userFixtureFileName: 'MainActivity.kt.template', + patchedFixtureFileName: 'rnn-tests_MainActivity.kt', + }); + + return { + mainActivityKotlin: mainActivityPath, + }; + }); + + const ActivityLinker = require('./activityLinker'); + const linker = new ActivityLinker(); + linker.link(); + + const mainActivityContent = fs.readFileSync(linker.activityPath, 'utf8'); + expect(mainActivityContent).toMatchSnapshot(); + }); +}); diff --git a/autolink/postlink/appDelegateLinker.js b/autolink/postlink/appDelegateLinker.js new file mode 100644 index 00000000000..35ff99e10cb --- /dev/null +++ b/autolink/postlink/appDelegateLinker.js @@ -0,0 +1,209 @@ +// @ts-check +var fs = require('fs'); +var path = require('./path'); +var nodePath = require('path'); +var { warnn, logn, infon, debugn, errorn } = require('./log'); + +class AppDelegateLinker { + constructor() { + this.appDelegatePath = path.appDelegate; + this.appDelegateHeaderPath = path.appDelegateHeader; + this.removeUnneededImportsSuccess = false; + this.removeApplicationLaunchContentSuccess = false; + } + + link() { + if (!this.appDelegatePath) { + errorn( + ' AppDelegate not found! Does the file exist in the correct folder?\n Please check the manual installation docs:\n https://wix.github.io/react-native-navigation/docs/installing#native-installation' + ); + return; + } + + logn('Linking AppDelegate...'); + + // New flow for Swift + if (nodePath.extname(this.appDelegatePath) === '.swift') { + debugn('Entering Swift flow ...'); + var appDelegateContents = fs.readFileSync(this.appDelegatePath, 'utf8'); + appDelegateContents = this._extendRNNAppDelegateSwift(appDelegateContents); + fs.writeFileSync(this.appDelegatePath, appDelegateContents); + this.removeUnneededImportsSuccess = true + this.removeApplicationLaunchContentSuccess = true + + } else { // Old flow for Objective-C + debugn('Entering Objective-C flow ...'); + var appDelegateContents = fs.readFileSync(this.appDelegatePath, 'utf8'); + + if (this.appDelegateHeaderPath) { + var appDelegateHeaderContents = fs.readFileSync(this.appDelegateHeaderPath, 'utf8'); + appDelegateHeaderContents = this._extendRNNAppDelegate(appDelegateHeaderContents); + fs.writeFileSync(this.appDelegateHeaderPath, appDelegateHeaderContents); + } + + try { + appDelegateContents = this._removeUnneededImports(appDelegateContents); + this.removeUnneededImportsSuccess = true; + } catch (e) { + errorn(' ' + e.message); + } + + appDelegateContents = this._importNavigation(appDelegateContents); + + appDelegateContents = this._bootstrapNavigation(appDelegateContents); + + try { + appDelegateContents = this._removeApplicationLaunchContent(appDelegateContents); + this.removeApplicationLaunchContentSuccess = true; + } catch (e) { + errorn(' ' + e.message); + } + + fs.writeFileSync(this.appDelegatePath, appDelegateContents); + } + + if (this.removeUnneededImportsSuccess && this.removeApplicationLaunchContentSuccess) { + infon('AppDelegate linked successfully!\n'); + } else { + warnn( + 'AppDelegate was partially linked, please check the details above and proceed with the manual installation documentation to complete the linking process.!\n' + ); + } + } + + _removeUnneededImports(content) { + debugn(' Removing Unneeded imports'); + + const unneededImports = [/#import\s+\\s/]; + let elementsRemovedCount = 0; + + unneededImports.forEach((unneededImport) => { + if (unneededImport.test(content)) { + content = content.replace(unneededImport, ''); + elementsRemovedCount++; + } + }); + + if (unneededImports.length === elementsRemovedCount) { + debugn(' All imports have been removed'); + } else if (elementsRemovedCount === 0) { + warnn( + ' No imports could be removed. Check the manual installation docs to verify that everything is properly setup:\n https://wix.github.io/react-native-navigation/docs/installing#native-installation' + ); + } else { + throw new Error( + 'Some imports were removed. Check the manual installation docs to verify that everything is properly setup:\n https://wix.github.io/react-native-navigation/docs/installing#native-installation' + ); + } + + return content; + } + + _extendRNNAppDelegate(content) { + return content + .replace( + /#import*./, + '#import "RNNAppDelegate.h"' + ) + .replace( + /:*.RCTAppDelegate/, + ': RNNAppDelegate' + ) + } + + _importNavigation(content) { + if (!this._doesImportNavigation(content)) { + debugn(' Importing ReactNativeNavigation.h'); + return content.replace( + /#import\s+"AppDelegate.h"/, + '#import "AppDelegate.h"\n#import ' + ); + } + + warnn(' AppDelegate already imports ReactNativeNavigation.h'); + return content; + } + + _bootstrapNavigation(content) { + if (this._doesBootstrapNavigation(content)) { + warnn(' Navigation Bootstrap already present.'); + return content; + } + + debugn(' Bootstrapping Navigation !!!!'); + return content + .replace( + /RCTBridge.*];/, + 'RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];\n' + + '[ReactNativeNavigation bootstrapWithBridge:bridge];' + ) + .replace( + /self.moduleName.*;(.|\n)*@{};\n?/, + '' + ); + } + + _doesBootstrapNavigation(content) { + return /ReactNativeNavigation\s+bootstrap/.test(content); + } + + _removeApplicationLaunchContent(content) { + debugn(' Removing Application launch content'); + + const toRemove = [ + /RCTRootView\s+\*rootView((.|\r|\s)*?)];\s+/, + /UIView \*rootView = RCTAppSetupDefaultRootView\(bridge, @".*", nil\);/, + /if \(@available\(iOS 13\.0, \*\)\)\s{\s+ rootView.backgroundColor((.|\r)*)];\s+}\s+else {[^}]*}/, + /self.window((.|\r)*)];\s+/, + /UIViewController\s\*rootViewController((.|\r)*)];\s+/, + /rootViewController\.view\s+=\s+rootView;\s+/, + /self.window.rootViewController\s+=\s+rootViewController;\s+/, + /\[self.window\s+makeKeyAndVisible];\s+/, + // Added from RN 0.69 + /NSDictionary\s+\*initProps\s+=\s+\[self prepareInitialProps];\s+/, + /UIView \*rootView = RCTAppSetupDefaultRootView\(bridge, @".*", initProps\);/, + ]; + + let elementsRemovedCount = 0; + + toRemove.forEach((element) => { + if (element.test(content)) { + content = content.replace(element, ''); + elementsRemovedCount++; + } + }); + + if (toRemove.length === elementsRemovedCount) { + debugn(' Application Launch content has been removed'); + } else if (elementsRemovedCount === 0) { + warnn( + ' No elements could be removed. Check the manual installation docs to verify that everything is properly setup:\n https://wix.github.io/react-native-navigation/docs/installing#native-installation' + ); + } else { + warnn( + 'Some elements were removed. Check the manual installation docs to verify that everything is properly setup:\n https://wix.github.io/react-native-navigation/docs/installing#native-installation' + ); + } + + return content; + } + + _doesImportNavigation(content) { + return /#import\s+\/.test(content); + } + + // SWIFT implementation + _extendRNNAppDelegateSwift(content) { + return content + .replace( + /import React_RCTAppDelegate/, + 'import ReactNativeNavigation' + ) + .replace( + /class AppDelegate: RCTAppDelegate/, + 'class AppDelegate: RNNAppDelegate' + ) + } +} + +module.exports = AppDelegateLinker; diff --git a/autolink/postlink/appDelegateLinker.test.js b/autolink/postlink/appDelegateLinker.test.js new file mode 100644 index 00000000000..c3e2a55bc22 --- /dev/null +++ b/autolink/postlink/appDelegateLinker.test.js @@ -0,0 +1,45 @@ +import fs from 'node:fs'; +import * as mockHelpers from './__helpers__/fixtures'; + +jest.mock('./log'); + +describe('appDelegateLinker', () => { + it('should work for RN 0.77 with Objective-C', () => { + jest.mock('./path', () => { + const appDelegatePath = mockHelpers.prepareFixtureDuplicate77({ + userFixtureFileName: 'AppDelegate.mm.template', + patchedFixtureFileName: 'rnn-tests_AppDelegate.mm', + }); + return { + appDelegate: appDelegatePath, + }; + }); + + const AppDelegateLinker = require('./appDelegateLinker'); + const linker = new AppDelegateLinker(); + + linker.link(); + const appDelegateContent = fs.readFileSync(linker.appDelegatePath, 'utf8'); + expect(appDelegateContent).toMatchSnapshot(); + }); + + it('should work for RN 0.77 with Swift', () => { + jest.mock('./path', () => { + const tmpAppDelegatePath = mockHelpers.prepareFixtureDuplicate77({ + userFixtureFileName: 'AppDelegate.swift.template', + patchedFixtureFileName: 'rnn-tests_AppDelegate.swift', + }); + + return { + appDelegate: tmpAppDelegatePath, + }; + }); + + const AppDelegateLinker = require('./appDelegateLinker'); + const linker = new AppDelegateLinker(); + linker.link(); + + const appDelegateContent = fs.readFileSync(linker.appDelegatePath, 'utf8'); + expect(appDelegateContent).toMatchSnapshot(); + }); +}); diff --git a/autolink/postlink/applicationLinker.js b/autolink/postlink/applicationLinker.js new file mode 100644 index 00000000000..b77d1496487 --- /dev/null +++ b/autolink/postlink/applicationLinker.js @@ -0,0 +1,184 @@ +// @ts-check +var path = require('./path'); +var fs = require('fs'); +var { warnn, logn, infon, debugn, errorn } = require('./log'); + +class ApplicationLinker { + constructor() { + this.applicationPath = path.mainApplicationKotlin; + this.navigationApplicationSuccess = false; + this.navigationHostSuccess = false; + this.soLoaderInitSuccess = false; + this.newArchEntryPointLoadSuccess = false; + } + + link() { + if (!this.applicationPath) { + errorn( + 'MainApplication.kt not found! Does the file exist in the correct folder?\n' + + ' Please check the manual installation docs:\n' + + ' https://wix.github.io/react-native-navigation/docs/installing#3-update-mainapplicationjava' + ); + } + + logn('Linking MainApplication...'); + var applicationContents = fs.readFileSync(this.applicationPath, 'utf8'); + + try { + applicationContents = this._extendNavigationApplication(applicationContents); + this.navigationApplicationSuccess = true; + } catch (e) { + errorn(' ' + e); + } + try { + applicationContents = this._extendNavigationHost(applicationContents); + this.navigationHostSuccess = true; + } catch (e) { + errorn(' ' + e); + } + try { + applicationContents = this._removeSOLoaderInit(applicationContents); + this.soLoaderInitSuccess = true; + } catch (e) { + errorn(' ' + e); + } + try { + applicationContents = this._removeNewArchEntryPointLoad(applicationContents); + this.newArchEntryPointLoadSuccess = true; + } catch (e) { + errorn(' ' + e); + } + + fs.writeFileSync(this.applicationPath, applicationContents); + + if ( + this.navigationApplicationSuccess && + this.navigationHostSuccess && + this.soLoaderInitSuccess && + this.newArchEntryPointLoadSuccess + ) { + infon('MainApplication.kt linked successfully!\n'); + } else if ( + !this.navigationApplicationSuccess && + !this.navigationHostSuccess && + !this.soLoaderInitSuccess && + !this.newArchEntryPointLoadSuccess + ) { + errorn( + 'MainApplication.kt was not successfully linked! Please check the information above:\n https://wix.github.io/react-native-navigation/docs/installing#3-update-mainapplicationjava' + ); + } else { + warnn( + 'MainApplication.kt was partially linked. Please check the information above and complete the missing steps manually:\n https://wix.github.io/react-native-navigation/docs/installing#3-update-mainapplicationjava' + ); + } + } + + _extendNavigationApplication(applicationContent) { + if (this._doesExtendApplication(applicationContent)) { + debugn(' Extending NavigationApplication'); + return applicationContent + .replace(/:\s*Application\(\)\s*,\s*ReactApplication/gi, ': NavigationApplication()') + .replace( + 'import com.facebook.react.ReactApplication', + 'import com.reactnativenavigation.NavigationApplication' + ); + } + + if (this._hasAlreadyLinkedApplication(applicationContent)) { + warnn(' MainApplication already extends NavigationApplication, skipping.'); + return applicationContent; + } + + throw new Error( + 'There was a problem extending NavigationApplication from your MainApplication file.' + ); + } + + _doesExtendApplication(applicationContent) { + return /\s+MainApplication\s*:\s*Application\(\)\s*,\s*ReactApplication\s+/.test( + applicationContent + ); + } + + _hasAlreadyLinkedApplication(applicationContent) { + return /\s*:\s*NavigationApplication\(\)\s*/.test(applicationContent); + } + + _extendNavigationHost(applicationContent) { + if (this._hasAlreadyLinkedNavigationHost(applicationContent)) { + warnn(' NavigationReactNativeHost is already used, skipping.'); + return applicationContent; + } + + if (this._doesExtendDefaultReactNativeHost(applicationContent)) { + debugn(' Changing host implementation to NavigationReactNativeHost'); + return applicationContent + .replace('DefaultReactNativeHost(this)', 'NavigationReactNativeHost(this)') + .replace( + 'import com.facebook.react.defaults.DefaultReactNativeHost', + 'import com.facebook.react.defaults.DefaultReactNativeHost\nimport com.reactnativenavigation.react.NavigationReactNativeHost' + ); + } else if (this._doesExtendReactNativeHost(applicationContent)) { + debugn(' Changing host implementation to NavigationReactNativeHost'); + return applicationContent + .replace('ReactNativeHost(this)', 'NavigationReactNativeHost(this)') + .replace( + 'import com.facebook.react.ReactNativeHost', + 'import com.facebook.react.ReactNativeHost\nimport com.reactnativenavigation.react.NavigationReactNativeHost' + ); + } + + throw new Error('There was a problem extending NavigationReactNativeHost().'); + } + + _doesExtendReactNativeHost(applicationContent) { + return /\s*ReactNativeHost\(this\)\s*/.test(applicationContent); + } + + _doesExtendDefaultReactNativeHost(applicationContent) { + return /\s*DefaultReactNativeHost\(this\)\s*/.test(applicationContent); + } + + _hasAlreadyLinkedNavigationHost(applicationContent) { + return /\s*NavigationReactNativeHost\(this\)\s*/.test(applicationContent); + } + + _removeSOLoaderInit(applicationContent) { + if (this._isSOLoaderInitCalled(applicationContent)) { + debugn(' Removing call to SOLoader.init()'); + return applicationContent.replace( + /SoLoader\.init\(\s*this\s*,\s*OpenSourceMergedSoMapping\s*\);?/, + '' + ); + } + warnn(' SOLoader.init() is not called, skipping.'); + return applicationContent; + } + + _isSOLoaderInitCalled(applicationContent) { + return /SoLoader\.init\(\s*this\s*,\s*OpenSourceMergedSoMapping\s*\);?/.test( + applicationContent + ); + } + + _removeNewArchEntryPointLoad(applicationContent) { + if (this._isNewArchEntryPointLoadCalled(applicationContent)) { + debugn(' Removing New Architecture entry point load block'); + return applicationContent.replace( + /if\s*\(\s*BuildConfig\.IS_NEW_ARCHITECTURE_ENABLED\s*\)\s*\{[\s\S]*?load\(\)\s*[\s}]*?\}/, + '' + ); + } + warnn(' New Architecture entry point load block is not called, skipping.'); + return applicationContent; + } + + _isNewArchEntryPointLoadCalled(applicationContent) { + return /if\s*\(\s*BuildConfig\.IS_NEW_ARCHITECTURE_ENABLED\s*\)\s*\{[\s\S]*?load\(\)\s*[\s}]*?\}/.test( + applicationContent + ); + } +} + +module.exports = ApplicationLinker; diff --git a/autolink/postlink/applicationLinker.test.js b/autolink/postlink/applicationLinker.test.js new file mode 100644 index 00000000000..bf219d25dc4 --- /dev/null +++ b/autolink/postlink/applicationLinker.test.js @@ -0,0 +1,25 @@ +import fs from 'node:fs'; +import * as mockHelpers from './__helpers__/fixtures'; + +jest.mock('./log'); + +describe('applicationLinker', () => { + it('should work for RN 0.77', () => { + jest.mock('./path', () => { + const mainApplicationPath = mockHelpers.prepareFixtureDuplicate77({ + userFixtureFileName: 'MainApplication.kt.template', + patchedFixtureFileName: 'rnn-tests_MainApplication.kt', + }); + return { + mainApplicationKotlin: mainApplicationPath, + }; + }); + + const ApplicationLinker = require('./applicationLinker'); + const linker = new ApplicationLinker(); + linker.link(); + + const mainApplicationContent = fs.readFileSync(linker.applicationPath, 'utf8'); + expect(mainApplicationContent).toMatchSnapshot(); + }); +}); diff --git a/autolink/postlink/gradleLinker.js b/autolink/postlink/gradleLinker.js new file mode 100644 index 00000000000..591ecc31d6b --- /dev/null +++ b/autolink/postlink/gradleLinker.js @@ -0,0 +1,145 @@ +// @ts-check +var path = require('./path'); +var fs = require('fs'); +var { warnn, errorn, logn, infon, debugn } = require('./log'); +var DEFAULT_KOTLIN_VERSION = '2.0.21'; +// This should be the minSdkVersion required for RNN. +var DEFAULT_MIN_SDK_VERSION = 24; + +class GradleLinker { + constructor() { + this.gradlePath = path.rootGradle; + this.setKlotinVersionSuccess = false; + this.setMinSdkVersionSuccess = false; + } + + link() { + if (!this.gradlePath) { + errorn( + 'Root build.gradle not found! Does the file exist in the correct folder?\n Please check the manual installation docs.' + ); + return; + } + + logn('Linking root build.gradle...'); + var contents = fs.readFileSync(this.gradlePath, 'utf8'); + + try { + contents = this._setKotlinVersion(contents); + this.setKlotinVersionSuccess = true; + } catch (e) { + errorn(' ' + e); + } + try { + contents = this._setMinSdkVersion(contents); + this.setMinSdkVersionSuccess = true; + } catch (e) { + errorn(' ' + e); + } + + fs.writeFileSync(this.gradlePath, contents); + + if ( + this.setKlotinVersionSuccess && + this.setMinSdkVersionSuccess + ) { + infon('Root build.gradle linked successfully!\n'); + } else if ( + !this.setKlotinVersionSuccess && + !this.setMinSdkVersionSuccess + ) { + errorn( + 'Root build.gradle link failed. Please review the information above and complete the necessary steps manually by following the instructions on https://wix.github.io/react-native-navigation/docs/installing#1-update-androidbuildgradle\n' + ); + } else { + warnn( + 'Root build.gradle link partially succeeded. Please review the information above and complete the necessary steps manually by following the instructions on https://wix.github.io/react-native-navigation/docs/installing#1-update-androidbuildgradle\n' + ); + } + } + + + _setKotlinVersion(contents) { + if (this._isKotlinVersionSpecified(contents)) { + warnn(' Kotlin version already specified'); + } else { + var kotlinVersion = this._getKotlinVersion(contents); + if (this._hasExtensionVariablesBlock(contents)) { + debugn(' Adding RNNKotlinVersion to extension block'); + return contents.replace(/ext\s*{/, `ext {\n RNNKotlinVersion = ${kotlinVersion}`); + } else { + debugn(' Adding RNNKotlinVersion extension variable'); + return contents.replace( + /buildscript\s*{/, + `buildscript {\n ext.RNNKotlinVersion = ${kotlinVersion}` + ); + } + } + return contents; + } + + /** + * Check the current minSdkVersion specified and if it's lower than + * the required version, set it to the required version otherwise leave as it is. + */ + _setMinSdkVersion(contents) { + var minSdkVersion = this._getMinSdkVersion(contents); + // If user entered minSdkVersion is lower than the default, set it to default. + if (minSdkVersion < DEFAULT_MIN_SDK_VERSION) { + debugn(` Updating minSdkVersion to ${DEFAULT_MIN_SDK_VERSION}`); + return contents.replace( + /minSdkVersion\s{0,}=\s{0,}\d*/, + `minSdkVersion = ${DEFAULT_MIN_SDK_VERSION}` + ); + } + + warnn(` Already specified minSdkVersion ${minSdkVersion}`); + return contents.replace(/minSdkVersion\s{0,}=\s{0,}\d*/, `minSdkVersion = ${minSdkVersion}`); + } + + /** + * @param { string } contents + */ + _getKotlinVersion(contents) { + var hardCodedVersion = contents.match(/(?<=kotlin-gradle-plugin:)\$*[\d\.]{3,}/); + if (hardCodedVersion && hardCodedVersion.length > 0) { + return `"${hardCodedVersion[0]}"`; + } + var extensionVariableVersion = contents.match(/(?<=kotlin-gradle-plugin:)\$*[a-zA-Z\d\.]*/); + if (extensionVariableVersion && extensionVariableVersion.length > 0) { + return extensionVariableVersion[0].replace('$', ''); + } + return `"${DEFAULT_KOTLIN_VERSION}"`; + } + + /** + * Get the minSdkVersion value. + * @param { string } contents + */ + _getMinSdkVersion(contents) { + var minSdkVersion = contents.match(/minSdkVersion\s{0,}=\s{0,}(\d*)/); + + if (minSdkVersion && minSdkVersion[1]) { + // It'd be something like 16 for a fresh React Native project. + return +minSdkVersion[1]; + } + + return DEFAULT_MIN_SDK_VERSION; + } + + /** + * @param {string} contents + */ + _hasExtensionVariablesBlock(contents) { + return /ext\s*{/.test(contents); + } + + /** + * @param {string} contents + */ + _isKotlinVersionSpecified(contents) { + return /RNNKotlinVersion/.test(contents); + } +} + +module.exports = GradleLinker; diff --git a/autolink/postlink/gradleLinker.test.js b/autolink/postlink/gradleLinker.test.js new file mode 100644 index 00000000000..daa1b3e0124 --- /dev/null +++ b/autolink/postlink/gradleLinker.test.js @@ -0,0 +1,26 @@ +import fs from 'fs'; +import * as mockHelpers from './__helpers__/fixtures'; + +jest.mock('./log'); + +describe('gradleLinker', () => { + it('should work for RN 0.77', () => { + jest.mock('./path', () => { + const tmpBuildGradlePath = mockHelpers.prepareFixtureDuplicate77({ + userFixtureFileName: 'build.gradle.template', + patchedFixtureFileName: 'rnn-tests_build.gradle', + }); + + return { + rootGradle: tmpBuildGradlePath, + }; + }); + + const GradleLinker = require('./gradleLinker'); + const linker = new GradleLinker(); + linker.link(); + + const buildGradleContent = fs.readFileSync(linker.gradlePath, 'utf8'); + expect(buildGradleContent).toMatchSnapshot(); + }); +}); diff --git a/autolink/postlink/log.js b/autolink/postlink/log.js new file mode 100644 index 00000000000..b1d4bb23468 --- /dev/null +++ b/autolink/postlink/log.js @@ -0,0 +1,33 @@ +const bColors = { + HEADER: '\033[95m', + OKBLUE: '\033[94m', + OKGREEN: '\033[92m', + WARNING: '\033[93m', + FAIL: '\033[91m', + ENDC: '\033[0m', + BOLD: '\033[1m', + UNDERLINE: '\033[4m', +}; + +const log = (text) => process.stdout.write(text); +const logn = (text) => process.stdout.write(text + '\n'); +const warn = (text) => process.stdout.write(`${bColors.WARNING}${text}${bColors.ENDC}`); +const warnn = (text) => warn(text + '\n'); +const error = (text) => process.stdout.write(`${bColors.FAIL}${text}${bColors.ENDC}`); +const errorn = (text) => error(text + '\n'); +const info = (text) => process.stdout.write(`${bColors.OKGREEN}${text}${bColors.ENDC}`); +const infon = (text) => info(text + '\n'); +const debug = (text) => process.stdout.write(`${bColors.OKBLUE}${text}${bColors.ENDC}`); +const debugn = (text) => debug(text + '\n'); + +module.exports = { + log, + logn, + warn, + warnn, + info, + infon, + debug, + debugn, + errorn, +}; diff --git a/autolink/postlink/path.js b/autolink/postlink/path.js new file mode 100644 index 00000000000..c3fb62d4eba --- /dev/null +++ b/autolink/postlink/path.js @@ -0,0 +1,37 @@ +var glob = require('glob'); +var ignoreFolders = { + ignore: ['node_modules/**', '**/build/**', '**/Build/**', '**/DerivedData/**', '**/*-tvOS*/**'], +}; +var { warnn, infon, debugn } = require('./log'); + +exports.mainActivityKotlin = glob.sync('**/MainActivity.kt', ignoreFolders)[0]; +var mainApplicationKotlin = glob.sync('**/MainApplication.kt', ignoreFolders)[0]; +exports.mainApplicationKotlin = mainApplicationKotlin; +exports.rootGradle = mainApplicationKotlin.replace(/android\/app\/.*\.kt/, 'android/build.gradle'); + +var reactNativeVersion = require('../../../react-native/package.json').version; +infon('Found React Native version: ' + reactNativeVersion); +infon('Locating the AppDelegate.mm file ...'); +exports.appDelegate = glob.sync( + '**/AppDelegate.mm', + ignoreFolders +)[0]; + +if (exports.appDelegate === undefined) { + warnn('AppDelegate.mm file not found, looking for AppDelegate.swift ...'); + exports.appDelegate = glob.sync( + '**/AppDelegate.swift', + ignoreFolders + )[0]; + + if (exports.appDelegate !== undefined) { + debugn('Found AppDelegate.swift'); + } + +} else { + debugn('Found AppDelegate.mm'); + exports.appDelegateHeader = glob.sync('**/AppDelegate.h', ignoreFolders)[0]; +} + +exports.podFile = glob.sync('**/Podfile', ignoreFolders)[0]; +exports.plist = glob.sync('**/info.plist', ignoreFolders)[0]; diff --git a/autolink/postlink/plistLinker.js b/autolink/postlink/plistLinker.js new file mode 100644 index 00000000000..eedad45a3fb --- /dev/null +++ b/autolink/postlink/plistLinker.js @@ -0,0 +1,47 @@ +// @ts-check +var fs = require('fs'); +var path = require('./path'); +var {logn, errorn} = require('./log'); + +const viewControllerBasedStatusBar = /UIViewControllerBasedStatusBarAppearance<\/key>(\s+|\n+)<(.*)\/>/; + +class plistLinker { + constructor() { + this.plistPath = path.plist; + } + + link() { + if (!this.plistPath) { + errorn( + ' info.plist not found! Does the file exist in the correct folder?\n Please check the manual installation docs:\n https://wix.github.io/react-native-navigation/docs/installing#native-installation' + ); + return; + } + + logn('Linking info.plist...'); + + var plistContent = fs.readFileSync(this.plistPath, 'utf8'); + + if (this._viewControllerBasedStatusBarDefined(plistContent)) { + plistContent = this._updateViewControllerBasedStatusBar(plistContent); + } else { + plistContent = this._applyViewControllerBasedStatusBar(plistContent); + } + + fs.writeFileSync(this.plistPath, plistContent); + } + + _viewControllerBasedStatusBarDefined(content) { + return viewControllerBasedStatusBar.test(content); + } + + _applyViewControllerBasedStatusBar(content) { + return content.replace(/<\/dict>\s<\/plist>/, 'UIViewControllerBasedStatusBarAppearance\n\n<\/dict>\n<\/plist>') + } + + _updateViewControllerBasedStatusBar(content) { + return content.replace(viewControllerBasedStatusBar, 'UIViewControllerBasedStatusBarAppearance\n') + } +} + +module.exports = plistLinker; diff --git a/autolink/postlink/podfileLinker.js b/autolink/postlink/podfileLinker.js new file mode 100644 index 00000000000..ef430f3e8d5 --- /dev/null +++ b/autolink/postlink/podfileLinker.js @@ -0,0 +1,59 @@ +// @ts-check +var path = require('./path'); +var fs = require('fs'); +var { logn, debugn, infon, errorn, warnn } = require('./log'); + +class PodfileLinker { + constructor() { + this.podfilePath = path.podFile; + } + + link() { + if (!this.podfilePath) { + errorn( + 'Podfile not found! Does the file exist in the correct folder?\n Please check the manual installation docs.' + ); + return; + } + + logn('Updating Podfile...'); + var podfileContent = fs.readFileSync(this.podfilePath, 'utf8'); + + podfileContent = this._removeRNNPodLink(podfileContent); + podfileContent = this._setMinimumIOSVersion(podfileContent); + + fs.writeFileSync(this.podfilePath, podfileContent); + } + + /** + * Sets the minimum iOS version to iOS 11.0 which is the minimum version required by the library. + */ + _setMinimumIOSVersion(contents) { + const platformDefinition = contents.match(/platform :ios, '.*'/); + const minimumIOSVersion = contents.match(/(?<=platform\s:ios,\s(?:"|'))(.*)(?=(?:"|'))/); + + if (parseFloat(minimumIOSVersion) < 11) { + debugn(' Bump minumum iOS version to iOS 11.0'); + return contents.replace(platformDefinition, "platform :ios, '11.0'"); + } + + return contents; + } + + /** + * Removes the RNN pod added by react-native link script. + */ + _removeRNNPodLink(contents) { + const rnnPodLink = contents.match(/\s+.*pod 'ReactNativeNavigation'.+react-native-navigation'/); + + if (!rnnPodLink) { + warnn(' RNN Pod has not been added to Podfile'); + return contents; + } + + debugn(' Removing RNN Pod from Podfile'); + return contents.replace(rnnPodLink, ''); + } +} + +module.exports = PodfileLinker; diff --git a/autolink/postlink/postLinkAndroid.js b/autolink/postlink/postLinkAndroid.js new file mode 100644 index 00000000000..28899294ee7 --- /dev/null +++ b/autolink/postlink/postLinkAndroid.js @@ -0,0 +1,12 @@ +// @ts-check +var { infon } = require('./log'); +var ApplicationLinker = require('./applicationLinker'); +var ActivityLinker = require('./activityLinker'); +var GradleLinker = require('./gradleLinker'); + +module.exports = () => { + infon('\nRunning Android postlink script.\n'); + new ApplicationLinker().link(); + new ActivityLinker().link(); + new GradleLinker().link(); +}; diff --git a/autolink/postlink/postLinkIOS.js b/autolink/postlink/postLinkIOS.js new file mode 100644 index 00000000000..fd7c272e7a5 --- /dev/null +++ b/autolink/postlink/postLinkIOS.js @@ -0,0 +1,12 @@ +// @ts-check +var {infon} = require('./log'); +var AppDelegateLinker = require('./appDelegateLinker'); +var PodfileLinker = require('./podfileLinker'); +var PlistLinker = require('./plistLinker'); + +module.exports = () => { + infon('Running iOS postlink script.\n'); + new AppDelegateLinker().link(); + new PodfileLinker().link(); + new PlistLinker().link(); +}; diff --git a/autolink/postlink/run.js b/autolink/postlink/run.js new file mode 100644 index 00000000000..7a4a18e122f --- /dev/null +++ b/autolink/postlink/run.js @@ -0,0 +1,17 @@ +#!/usr/bin/env node + +// @ts-check +var { infon, warnn } = require('./log'); +var postLinkAndroid = require('./postLinkAndroid'); +var postLinkIOS = require('./postLinkIOS'); + +postLinkAndroid(); +postLinkIOS(); + +infon('\nReact Native Navigation link is completed. Check the logs above for more information.\n'); +warnn( + ' If any of the steps failed, check the installation docs and go through the necessary steps manually:' +); +warnn(' https://wix.github.io/react-native-navigation/docs/installing#manual-installation\n'); +infon("When you're done, don't forget to update the index.js file as mentioned in docs!\n"); +infon('Thank you for using React Native Navigation!\n\n'); diff --git a/autolink/postlink/stringUtils.js b/autolink/postlink/stringUtils.js new file mode 100644 index 00000000000..6261e1f0bb0 --- /dev/null +++ b/autolink/postlink/stringUtils.js @@ -0,0 +1,14 @@ +// @ts-check + +/** + * @param {string} to + * @param {number} fromIndex + * @param {string} what + */ +function insertString(to, fromIndex, what) { + return to.substring(0, fromIndex) + what + to.substring(fromIndex, to.length); +} + +module.exports = { + insertString, +}; diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 00000000000..c05b94b830d --- /dev/null +++ b/babel.config.js @@ -0,0 +1,11 @@ +module.exports = function (api) { + api && api.cache(false); + return { + presets: ['module:@react-native/babel-preset'], + plugins: [ + '@babel/plugin-proposal-export-namespace-from', + '@babel/plugin-proposal-export-default-from', + 'react-native-reanimated/plugin', + ], + }; +}; diff --git a/docs/.nojekyll b/docs/.nojekyll deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index c3506c09a9b..00000000000 --- a/docs/README.md +++ /dev/null @@ -1,23 +0,0 @@ - -

-
- React Native Navigation -

- -App-wide support for 100% native navigation with an easy cross-platform interface. - ----- - -## Important -Latest stable version is `1.1.x` and is published to npm under tag `latest`. It supports react-native 0.43 and above. -

We are currently redesigning and rewriting this project under branch `v2`. -
As a result, new features and pull requests on the current stable version will take more time to process. - -## Why use this package - -One of the major things missing from React Native core is fully featured native navigation. Navigation includes the entire skeleton of your app with critical components like nav bars, tab bars and side menu drawers. - -If you're trying to deliver a user experience that's on par with the best native apps out there, you simply can't compromise on JS-based components trying to fake the real thing. - -For example, this package replaces the native [NavigatorIOS](https://facebook.github.io/react-native/docs/navigatorios.html) that has been [abandoned](https://facebook.github.io/react-native/docs/navigator-comparison.html) in favor of JS-based solutions that are easier to maintain. For more details see in-depth discussion [here](https://github.com/wix/react-native-controllers#why-do-we-need-this-package). - diff --git a/docs/_navbar.md b/docs/_navbar.md deleted file mode 100644 index 1624e1d2491..00000000000 --- a/docs/_navbar.md +++ /dev/null @@ -1 +0,0 @@ -- [Github](https://github.com/wix/react-native-navigation/) \ No newline at end of file diff --git a/docs/_sidebar.md b/docs/_sidebar.md deleted file mode 100644 index 61e71766466..00000000000 --- a/docs/_sidebar.md +++ /dev/null @@ -1,17 +0,0 @@ -- Getting started - - [Installation - iOS](/installation-ios) - - [Installation - Android](/installation-android) - - [Usage](/usage) - -- Guide - - [Top Level API](/top-level-api) - - [Screen API](/screen-api) - - [Deep links](/deep-links) - - [Android Specific Use Cases](/android-specific-use-cases) - - [Third Party Libraries Support](/third-party-libraries-support) - -- Customization - - [Styling the Navigator](/styling-the-navigator) - - [Adding Buttons to the Navigator](/adding-buttons-to-the-navigator) - - [Styling the Tab Bar](/styling-the-tab-bar) - \ No newline at end of file diff --git a/docs/adding-buttons-to-the-navigator.md b/docs/adding-buttons-to-the-navigator.md deleted file mode 100644 index 11eb16569e7..00000000000 --- a/docs/adding-buttons-to-the-navigator.md +++ /dev/null @@ -1,246 +0,0 @@ -# Adding buttons to the navigator - -Nav bar buttons can be defined per-screen by adding `static navigatorButtons = {...};` on the screen component definition. This object can also be passed when the screen is originally created; and can be overridden when a screen is pushed. Handle onPress events for the buttons by setting your handler with `navigator.setOnNavigatorEvent(callback)`. - -```js -class FirstTabScreen extends Component { - static navigatorButtons = { - rightButtons: [ - { - title: 'Edit', // for a textual button, provide the button title (label) - id: 'edit', // id for this button, given in onNavigatorEvent(event) to help understand which button was clicked - testID: 'e2e_rules', // optional, used to locate this view in end-to-end tests - disabled: true, // optional, used to disable the button (appears faded and doesn't interact) - disableIconTint: true, // optional, by default the image colors are overridden and tinted to navBarButtonColor, set to true to keep the original image colors - showAsAction: 'ifRoom', // optional, Android only. Control how the button is displayed in the Toolbar. Accepted valued: 'ifRoom' (default) - Show this item as a button in an Action Bar if the system decides there is room for it. 'always' - Always show this item as a button in an Action Bar. 'withText' - When this item is in the action bar, always show it with a text label even if it also has an icon specified. 'never' - Never show this item as a button in an Action Bar. - buttonColor: 'blue', // Optional, iOS only. Set color for the button (can also be used in setButtons function to set different button style programatically) - buttonFontSize: 14, // Set font size for the button (can also be used in setButtons function to set different button style programatically) - buttonFontWeight: '600', // Set font weight for the button (can also be used in setButtons function to set different button style programatically) - }, - { - icon: require('../../img/navicon_add.png'), // for icon button, provide the local image asset name - id: 'add' // id for this button, given in onNavigatorEvent(event) to help understand which button was clicked - } - ] - }; - - constructor(props) { - super(props); - // if you want to listen on navigator events, set this up - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); - } - - onNavigatorEvent(event) { // this is the onPress handler for the two buttons together - if (event.type == 'NavBarButtonPress') { // this is the event type for button presses - if (event.id == 'edit') { // this is the same id field from the static navigatorButtons definition - AlertIOS.alert('NavBar', 'Edit button pressed'); - } - if (event.id == 'add') { - AlertIOS.alert('NavBar', 'Add button pressed'); - } - } - } - - render() { - return ( - ... - ); - } -``` - -#### Buttons object format - -```js -{ - rightButtons: [{ // buttons for the right side of the nav bar (optional) - title: 'Edit', // if you want a textual button - icon: require('../../img/navicon_edit.png'), // if you want an image button - component: 'example.CustomButton', // if you want a custom button - passProps: {}, // Object that will be passed as props to custom components (optional) - id: 'compose', // id of the button which will pass to your press event handler. See the section bellow for Android specific button ids - testID: 'e2e_is_awesome', // if you have e2e tests, use this to find your button - disabled: true, // optional, used to disable the button (appears faded and doesn't interact) - disableIconTint: true, // optional, by default the image colors are overridden and tinted to navBarButtonColor, set to true to keep the original image colors - buttonColor: 'blue', // Set color for the button (can also be used in setButtons function to set different button style programatically) - buttonFontSize: 14, // Set font size for the button (can also be used in setButtons function to set different button style programatically) - buttonFontWeight: '600' // Set font weight for the button (can also be used in setButtons function to set different button style programatically) - systemItem: 'compose', // Optional, iOS only. Set a system bar button item as the icon. Matches UIBarButtonSystemItem naming. - }], - leftButtons: [] // buttons for the left side of the nav bar (optional) -} -``` - -##### iOS System Items -On iOS, UIKit supplies some common bar button glyphs for developers to use. The following values can be supplied as values to to `systemItem` to use them as an icon for your button. - -* `done` -* `cancel` -* `edit` -* `save` -* `add` -* `flexibleSpace` -* `fixedSpace` -* `compose` -* `reply` -* `action` -* `organize` -* `bookmarks` -* `search` -* `refresh` -* `stop` -* `camera` -* `trash` -* `play` -* `pause` -* `rewind` -* `fastForward` -* `undo` -* `redo` - -More information about these glyphs can be found in [Apple's Human Interface Guidelines](https://developer.apple.com/ios/human-interface-guidelines/icons-and-images/system-icons/). - - -##### Android left button -On Android, four button types are supported by default without the need to provide an icon. You can use them by specifying one of the following ids in your left button definition: - -* back -* cancel -* accept -* sideMenu - -#### Custom Navigation Buttons - -On iOS, react-native-navigation uses `UIBarButtonItem` to display all items in the navigation bar. Instead of using images or text for normal `UIBarButtonItem`s, you can supply a custom component to be displayed within a custom view of a `UIBarButtonItem`, using the `component` property when specifying a navigation button. - -Custom components must first be registered, just as screens are registered, using [`Navigation.registerComponent`](#/top-level-api?id=registercomponentscreenid-generator-store-undefined-provider-undefined). - -Additionally, ensure that the view is able to size itself, as custom navigation buttons will size depending on their content. Only `width` will be respected by the navigation bar; views can overflow outside of the navigation bar if they are too tall. - -```js -const styles = StyleSheet.create({ - button: { - overflow: 'hidden', - width: 34, - height: 34, - borderRadius: 34 / 2, - justifyContent: 'center', - alignItems: 'center', - }, -}); - -// Our custom component we want as a button in the nav bar -const CustomButton = ({ text }) => - console.log('pressed me!')} - > - - - {text} - - - ; - -// Register the component -Navigation.registerComponent('CustomButton', () => CustomButton); - -Navigation.startSingleScreenApp({ - screen: { - screen: 'example.screen', - title: 'React Native Navigation', - navigatorButtons: { - leftButtons: [ - { - id: 'custom-button', - component: 'CustomButton', // This line loads our component as a nav bar button item - passProps: { - text: 'Hi!', - }, - }, - ], - }, - }, -}); -``` - -#### Floating Action Button (FAB) - Android only -Each screen can contain a single Fab which is displayed at the bottom right corner of the screen. - -* Simple Fab: - -```js - static navigatorButtons = { - fab: { - collapsedId: 'share', - collapsedIcon: require('../../img/ic_share.png'), - collapsedIconColor: 'red', // optional - backgroundColor: '#607D8B' - } - }; -``` - -* Fab with expanded state -[Example](https://material-design.storage.googleapis.com/publish/material_v_9/0B8v7jImPsDi-ZmQ0UnFPZmtiSU0/components-buttons-fab-transition_speeddial_02.mp4) - -```js - fab: { - collapsedId: 'share', - collapsedIcon: require('../../img/ic_share.png'), - collapsedIconColor: 'green', // optional - expendedId: 'clear', - expendedIcon: require('../../img/ic_clear.png'), - expendedIconColor: 'red', // optional - backgroundColor: '#3F51B5', - actions: [ - { - id: 'mail', - icon: require('../../img/ic_mail.png'), - iconColor: 'blue', // optional - backgroundColor: '#03A9F4' - }, - { - id: 'twitter', - icon: require('../../img/ic_twitter.png'), - backgroundColor: '#4CAF50' - } - ] - } -``` - -#### Contextual TopBar Menu - Android only -A contextual menu offers actions that affect a specific item or context frame in the UI. You can provide a context menu for any view, but they are most often used for items in a ListView, GridView, or other view collections in which the user can perform direct actions on each item. (Taken from the [Android documentation](https://developer.android.com/guide/topics/ui/menus.html#context-menu)) - -#### showing the contextual menu - -```js -this.props.navigator.showContextualMenu( - { - rightButtons: [ - { - title: 'Add', - icon: require('../img/add.png') - }, - { - title: 'Delete', - icon: require('../img/delete.png') - } - ], - onButtonPressed: (index) => console.log(`Button ${index} tapped`) - } -); -``` - -##### Hiding the contextual menu -```js -this.props.navigator.dismissContextualMenu(); -``` - - -To style the `ContextualMenu`, use the following properties in the screen's `navigatorStyle`: -```js -static navigatorStyle = { - contextualMenuStatusBarColor: '#0092d1', - contextualMenuBackgroundColor: '#00adf5', - contextualMenuButtonsColor: '#ffffff' -}; -``` diff --git a/docs/android-specific-use-cases.md b/docs/android-specific-use-cases.md deleted file mode 100644 index 19fd23c039a..00000000000 --- a/docs/android-specific-use-cases.md +++ /dev/null @@ -1,329 +0,0 @@ -# Android Specific Use Cases - -## Activity Lifecycle and onActivityResult -In order to listen to activity lifecycle callbacks, set `ActivityCallback` in `MainApplication.onCreate` as follows: - -```java -public class MainApplication extends NavigationApplication { - @Override - public void onCreate() { - super.onCreate(); - setActivityCallbacks(new ActivityCallbacks() { - @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - - } - - @Override - public void onActivityStarted(Activity activity) { - - } - - @Override - public void onActivityResumed(Activity activity) { - - } - - @Override - public void onActivityPaused(Activity activity) { - - } - - @Override - public void onActivityStopped(Activity activity) { - - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - - } - - @Override - public void onActivityDestroyed(Activity activity) { - - } - }); - } -} -``` - -## Adjusting soft input mode - -```java -public class MyApplication extends NavigationApplication { - @Override - public void onCreate() { - registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { - @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - } - }); - } -} -``` - -### Why overriding these methods in `MainActivity` won't work -`MainActivity` extends `SplashActiviy` which is used to start the react context. Once react is up and running `MainActivity` is **stopped** and another activity takes over to run our app: `NavigationActivity`. Due to this design, there's usually no point in overriding lifecycle callbacks in `MainActivity`. - -## Splash screen -Override `getSplashLayout` or `createSplashLayout` in `MainActivity` to provide a splash layout which will be displayed while Js context initialises, for example: - -```java -import android.widget.LinearLayout; -import android.graphics.Color; -import android.widget.TextView; -import android.view.Gravity; -import android.util.TypedValue; - -import com.reactnativenavigation.controllers.SplashActivity; - -public class MainActivity extends SplashActivity { - - @Override - public LinearLayout createSplashLayout() { - LinearLayout view = new LinearLayout(this); - TextView textView = new TextView(this); - - view.setBackgroundColor(Color.parseColor("#607D8B")); - view.setGravity(Gravity.CENTER); - - textView.setTextColor(Color.parseColor("#FFFFFF")); - textView.setText("React Native Navigation"); - textView.setGravity(Gravity.CENTER); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40); - - view.addView(textView); - return view; - } -} -``` - -## Snackbar -Snackbars provide lightweight feedback about an operation. They show a brief message at the bottom of the screen. Snackbars appear above all other elements on screen and only one can be displayed at a time. - -```js -this.props.navigator.showSnackbar({ - text: 'Hello from Snackbar', - actionText: 'done', // optional - actionId: 'fabClicked', // Mandatory if you've set actionText - actionColor: 'green', // optional - textColor: 'red', // optional - backgroundColor: 'blue', // optional - duration: 'indefinite' // default is `short`. Available options: short, long, indefinite -}); -``` - -## Collapsing React header -A screen can have a header, either an image or a react component, that collapses as the screen is scrolled. - -### Collapsing react view - -```js -export default class CollapsingReactViewScreen extends Component { -static navigatorStyle = { - navBarHideOnScroll: false, - navBarBackgroundColor: '#4dbce9', // This will be the TitleBars color when the react view is hidden and collapsed - collapsingToolBarComponent: 'example.header', - navBarTranslucent: true, // Optional, sets a translucent dark background to the TitleBar. Useful when displaying bright colored header to emphasize the title and buttons in the TitleBar - showTitleWhenExpended: false, // default: true. Show the screens title only when the toolbar is collapsed - collapsingToolBarCollapsedColor: 'green', // optional. The TitleBar (navBar) color in collapsed state - collapsingToolBarExpendedColor: 'red' // optional. The TitleBar (navBar) color in expended state - }; -} -``` - -### Collapsing react view with top tabs - -**Note:** `example.header` represents a component that's registered as a screen: -```js -import Header from './Header'; -Navigation.registerComponent('example.header', () => Header); -``` - -```js -export default class CollapsingReactViewTopTabsScreen extends Component { - static navigatorStyle = { - navBarHideOnScroll: false, // false, since we collapse the TopBar and the TitleBar remains visible with the top tabs - topBarCollapseOnScroll: true, - navBarBackgroundColor: '#4dbce9', // This will be the TitleBar's color when the react view is hidden and collapsed - collapsingToolBarComponent: 'example.header', // id used to register the component - expendCollapsingToolBarOnTopTabChange: false, // Don't expend the TopBar when selected TopTab changes - collapsingToolBarCollapsedColor: '#4dbce9' // Optional, use this property with navBarTranslucent: true to animate between translucent and solid color title bar color - }; -} -``` - -Specify `topTab` in the screen object you use when starting your app: - -```js -Navigation.startSingleScreenApp({ - screen: { - screen: 'example.collapsingReactViewTopTabsScreen', - title: 'Collapsing React TopTabs View', - topTabs: [ - { - screenId: 'example.ListScreen', - icon: require('../img/list.png') - }, - { - screenId: 'example.secondTabScreen', - icon: require('../img/list.png') - } - ] -}); -``` -## Shared Element Transition -Screen transitions provide visual connections between different states through motion and transformations between common elements. You can specify custom animations for transitions of shared elements between screens. - -The `` component determines how views that are shared between two screens transition between these screens. For example, if two screens have the same image in different positions and sizes, the `` will translate and scale the image smoothly between these screens. - -### Supported transitions -* Scale -* Text color -* Linear translation -* Curved motion translation -* Image bounds and scale transformation - Unlike the basic scale transformation, this transformation will change the actual image scale and bounds, instead of simply scaling it up or down. - -### Specifying shared elements -First, wrap the view you would like to transition in a `` and give it a unique id. This is how our `` element is defined in the first screen: - -```js - - React Native Navigation - -``` -
In the second screen, we also wrap the corresponding `` element but this time, we also specify the transition props: - -```js - - React Native Navigation - -
-``` -
Finally, specify the elements you'd like to transition when pushing the second screen: - -```js -this.props.navigator.push({ - screen: 'SharedElementScreen', - sharedElements: ['SharedTextId'] - } -}); -``` -### Animating image bounds and scale -By default, when animating images, a basic scale transition is used. This is good enough for basic use cases where both images have the same aspect ratio. If the images have different size and scale, you can animate their bounds and scale by setting `animateClipBounds={true}` on the final `` element. - -### Curved motion -The `path` interpolator transitions elements along a curved path based on Bézier curves. This interpolator specifies a motion curve in a 1x1 square, with anchor points at (0,0) and (1,1) and control points specified using the `showInterpolation` and `hideInterpolation` props. - -#### Using curved motion -First, wrap the view you would like to transition in a `` and give it a unique id. In this example we are going to transition an `'. - -```js - - - -``` - -
In the `` wrapping the Image in the second screen, define control points in `showInterpolation` and `hideInterpolation` props: - -```js - - - -``` - -
As in the previous example, specify the elements you'd like to transition when pushing the second screen: - -```js -this.props.navigator.push({ - screen: 'SharedElementScreen', - sharedElements: ['sharedImageId'] - } -}); -``` - -### Easing -specify the rate of change of a parameter over time - -* `accelerateDecelerate` - the rate of change starts and ends slowly but accelerates through the middle. -* `accelerate` - the rate of change starts out slowly and and then accelerates. -* `decelerate` - the rate of change starts out quickly and and then decelerates. -* `fastOutSlowIn` - the rate of change starts fast but decelerates slowly. -* `linear` - the rate of change is constant (default) - -### Screen animation -When Shared Element Transition is used, a cross-fade transition is used between the entering and exiting screens. Make sure the root `View` has a background color in order for the cross-fade animation to be visible. - -To disable the cross-fade animation, set `animated: false` when pushing the second screen. Disabling this animation is useful if you'd like to animate the reset of the elements on screen your self. - -## Compatibility with HeadlessJs -In most cases, `Navigation.startSingleScreenApp()` or `Navigation.startTabBasedApp` are called from global context. If the bundle is parsed when the app is not running, this will result in the app opening even though the developer had no intent to open the app. - -`Navigation.startSingleScreenApp()` or `Navigation.startTabBasedApp` are called from global context since RNN assums react context isn't created when the app is launched. When a background task completes, react context is put into a **paused state** and not destroyed. Therefore we should also handle the use case where our app is opened when react context is created , and the bundle has already been parsed. We do that by listening to `RNN.AppLaunched` event. - -```js -import {Navigation, NativeEventsReceiver} from 'react-native-navigation'; - -Navigation.isAppLaunched() - .then(appLaunched => { - if (appLaunched) { - startApp(); // App is launched -> show UI - } - new NativeEventsReceiver().appLaunched(startApp); // App hasn't been launched yet -> show the UI only when needed. - }); - -function startApp() { - Navigation.startTabBasedApp({ ... }); -} -``` - -## Reloading from terminal -You can easily reload your app from terminal using `adb shell am broadcast -a react.native.RELOAD`. This is particularly useful when debugging on device. diff --git a/docs/deep-links.md b/docs/deep-links.md deleted file mode 100644 index 8b991e2c1c9..00000000000 --- a/docs/deep-links.md +++ /dev/null @@ -1,44 +0,0 @@ -# Deep Links - -Deep links are strings which represent internal app paths/routes. They commonly appear on push notification payloads to control which section of the app should be displayed when the notification is clicked. For example, in a chat app, clicking on the notification should open the relevant conversation on the "chats" tab. - -Another use-case for deep links is when one screen wants to control what happens in another sibling screen. Normally, a screen can only push/pop from its own stack, it cannot access the navigation stack of a sibling tab for example. Returning to our chat app example, assume that by clicking on a contact in the "contacts" tab we want to open the relevant conversation in the "chats" tab. Since the tabs are siblings, you can achieve this behavior by triggering a deep link: - -```js -onContactSelected(contactID) { - this.props.navigator.handleDeepLink({ - link: 'chats/' + contactID, - payload: '' // (optional) Extra payload with deep link - }); -} -``` - -> Tip: Deep links are also the recommended way to handle side drawer actions. Since the side drawer screen is a sibling to the rest of the app, it can control the other screens by triggering deep links. - -#### Handling deep links - -Every deep link event is broadcasted to all screens. A screen can listen to these events by defining a handler using `setOnNavigatorEvent` (much like listening for button events). Using this handler, the screen can filter links directed to it by parsing the link string and act upon any relevant links found. - -```js -export default class SecondTabScreen extends Component { - constructor(props) { - super(props); - // if you want to listen on navigator events, set this up - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); - } - onNavigatorEvent(event) { - // handle a deep link - if (event.type == 'DeepLink') { - const parts = event.link.split('/'); // Link parts - const payload = event.payload; // (optional) The payload - - if (parts[0] == 'tab2') { - // handle the link somehow, usually run a this.props.navigator command - } - } - } -``` - -#### Deep link string format - -There is no specification for the format of deep links. Since you're implementing the parsing logic in your handlers, you can use any format you wish. diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index a39fbf92529..00000000000 --- a/docs/index.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - React Native Navigation - truly native navigation for iOS and Android - - - - - - - -
- react-native-navigation logo -
- - - - - - - - diff --git a/docs/installation-android.md b/docs/installation-android.md deleted file mode 100644 index 69a996a7599..00000000000 --- a/docs/installation-android.md +++ /dev/null @@ -1,94 +0,0 @@ -# Android Installation - -!> Make sure you are using **react-native** version >= 0.51. We also recommend using npm version >= 3 - -1. Install `react-native-navigation` latest stable version. - - ```sh - yarn add react-native-navigation@latest - ``` - -2. Add the following in `android/settings.gradle`. - - ```groovy - include ':react-native-navigation' - project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/android/app/') - ``` - -3. Update project dependencies in `android/app/build.gradle`. - ```groovy - android { - compileSdkVersion 25 - buildToolsVersion "25.0.1" - ... - } - - dependencies { - compile fileTree(dir: "libs", include: ["*.jar"]) - compile "com.android.support:appcompat-v7:23.0.1" - compile "com.facebook.react:react-native:+" - compile project(':react-native-navigation') - } - ``` - -4. In `MainActivity.java` it should extend `com.reactnativenavigation.controllers.SplashActivity` instead of `ReactActivity`. - - This file can be located in `android/app/src/main/java/com/yourproject/`. - - ```java - import com.reactnativenavigation.controllers.SplashActivity; - - public class MainActivity extends SplashActivity { - - } - ``` - - If you have any **react-native** related methods, you can safely delete them. - -5. In `MainApplication.java`, add the following - ```java - import com.reactnativenavigation.NavigationApplication; - - public class MainApplication extends NavigationApplication { - - @Override - public boolean isDebug() { - // Make sure you are using BuildConfig from your own application - return BuildConfig.DEBUG; - } - - protected List getPackages() { - // Add additional packages you require here - // No need to add RnnPackage and MainReactPackage - return Arrays.asList( - // eg. new VectorIconsPackage() - ); - } - - @Override - public List createAdditionalReactPackages() { - return getPackages(); - } - } - ``` - - Also, add the following - - ```java - @Override - public String getJSMainModuleName() { - return "index"; - } - ``` - - if you are using `index.js` as your entry point instead of `index.ios.js` and `index.android.js` (it is the default since React Native 0.49). - - Make sure that `isDebug` and `createAdditionalReactPackages` methods are implemented. - -6. Update `AndroidManifest.xml` and set **android:name** value to `.MainApplication` - ```xml - - ``` diff --git a/docs/installation-ios.md b/docs/installation-ios.md deleted file mode 100644 index 4c8ed1ae83d..00000000000 --- a/docs/installation-ios.md +++ /dev/null @@ -1,25 +0,0 @@ -# iOS Installation - -!> Make sure you are using **react-native** version >= 0.51. We also recommend using npm version >= 3 - -1. Install `react-native-navigation` latest stable version. - - ```sh - yarn add react-native-navigation@latest - ``` - -2. In Xcode, in Project Navigator (left pane), right-click on the `Libraries` > `Add files to [project name]`. Add `./node_modules/react-native-navigation/ios/ReactNativeNavigation.xcodeproj` ([screenshots](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#step-1)) - -3. In Xcode, in Project Navigator (left pane), click on your project (top), then click on your *target* row (on the "project and targets list", which is on the left column of the right pane) and select the `Build Phases` tab (right pane). In the `Link Binary With Libraries` section add `libReactNativeNavigation.a` ([screenshots](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#step-2)) - -4. In Xcode, in Project Navigator (left pane), click on your project (top), then click on your *project* row (on the "project and targets list") and select the `Build Settings` tab (right pane). In the `Header Search Paths` section add `$(SRCROOT)/../node_modules/react-native-navigation/ios`. Make sure on the right to mark this new path `recursive` ([screenshots](https://facebook.github.io/react-native/docs/linking-libraries-ios.html#step-3)) - -5. In Xcode, you will need to edit this file: `AppDelegate.m`. This function is the main entry point for your app: - - ```objc - - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... } - ``` - -Its content must be replaced with the content of this [reference](https://github.com/wix/react-native-navigation/blob/master/example/ios/example/AppDelegate.m) - -Replace `@"index.ios"` with `@"index"` if you are using `index.js` as your entry point instead of `index.ios.js` and `index.android.js` (it is the default since React Native 0.49). diff --git a/docs/screen-api.md b/docs/screen-api.md deleted file mode 100644 index 47645e9fea9..00000000000 --- a/docs/screen-api.md +++ /dev/null @@ -1,372 +0,0 @@ -# Screen API - -This API is relevant when in a screen component context - it allows a screen to push other screens, pop screens, change its navigator style, etc. Access to this API is available through the `navigator` object that is passed to your component through `props`. - -## push(params) - -Push a new screen into this screen's navigation stack. - -```js -this.props.navigator.push({ - screen: 'example.ScreenThree', // unique ID registered with Navigation.registerScreen - title: undefined, // navigation bar title of the pushed screen (optional) - titleImage: require('../../img/my_image.png'), // iOS only. navigation bar title image instead of the title text of the pushed screen (optional) - passProps: {}, // Object that will be passed as props to the pushed screen (optional) - animated: true, // does the push have transition animation or does it happen immediately (optional) - animationType: 'fade', // 'fade' (for both) / 'slide-horizontal' (for android) does the push have different transition animation (optional) - backButtonTitle: undefined, // override the back button title (optional) - backButtonHidden: false, // hide the back button altogether (optional) - navigatorStyle: {}, // override the navigator style for the pushed screen (optional) - navigatorButtons: {}, // override the nav buttons for the pushed screen (optional) - // enable peek and pop - commited screen will have `isPreview` prop set as true. - previewView: undefined, // react ref or node id (optional) - previewHeight: undefined, // set preview height, defaults to full height (optional) - previewCommit: true, // commit to push preview controller to the navigation stack (optional) - previewActions: [{ // action presses can be detected with the `PreviewActionPress` event on the commited screen. - id: '', // action id (required) - title: '', // action title (required) - style: undefined, // 'selected' or 'destructive' (optional) - actions: [], // list of sub-actions - }], -}); -``` - -## pop(params = {}) - -Pop the top screen from this screen's navigation stack. - -```js -this.props.navigator.pop({ - animated: true, // does the pop have transition animation or does it happen immediately (optional) - animationType: 'fade', // 'fade' (for both) / 'slide-horizontal' (for android) does the pop have different transition animation (optional) -}); -``` - -## popToRoot(params = {}) - -Pop all the screens until the root from this screen's navigation stack. - -```js -this.props.navigator.popToRoot({ - animated: true, // does the popToRoot have transition animation or does it happen immediately (optional) - animationType: 'fade', // 'fade' (for both) / 'slide-horizontal' (for android) does the popToRoot have different transition animation (optional) -}); -``` - -## resetTo(params) - -Reset the screen's navigation stack to a new screen (the stack root is changed). - -```js -this.props.navigator.resetTo({ - screen: 'example.ScreenThree', // unique ID registered with Navigation.registerScreen - title: undefined, // navigation bar title of the pushed screen (optional) - passProps: {}, // simple serializable object that will pass as props to the pushed screen (optional) - animated: true, // does the resetTo have transition animation or does it happen immediately (optional) - animationType: 'fade', // 'fade' (for both) / 'slide-horizontal' (for android) does the resetTo have different transition animation (optional) - navigatorStyle: {}, // override the navigator style for the pushed screen (optional) - navigatorButtons: {} // override the nav buttons for the pushed screen (optional) -}); -``` - -## showModal(params = {}) - -Show a screen as a modal. - -```js -this.props.navigator.showModal({ - screen: "example.ModalScreen", // unique ID registered with Navigation.registerScreen - title: "Modal", // title of the screen as appears in the nav bar (optional) - passProps: {}, // simple serializable object that will pass as props to the modal (optional) - navigatorStyle: {}, // override the navigator style for the screen, see "Styling the navigator" below (optional) - animationType: 'slide-up' // 'none' / 'slide-up' , appear animation for the modal (optional, default 'slide-up') -}); -``` - -## dismissModal(params = {}) - -Dismiss the current modal. - -```js -this.props.navigator.dismissModal({ - animationType: 'slide-down' // 'none' / 'slide-down' , dismiss animation for the modal (optional, default 'slide-down') -}); -``` - -## dismissAllModals(params = {}) - -Dismiss all the current modals at the same time. - -```js -this.props.navigator.dismissAllModals({ - animationType: 'slide-down' // 'none' / 'slide-down' , dismiss animation for the modal (optional, default 'slide-down') -}); -``` - -## showLightBox(params = {}) - -Show a screen as a lightbox. - -```js -this.props.navigator.showLightBox({ - screen: "example.LightBoxScreen", // unique ID registered with Navigation.registerScreen - passProps: {}, // simple serializable object that will pass as props to the lightbox (optional) - style: { - backgroundBlur: "dark", // 'dark' / 'light' / 'xlight' / 'none' - the type of blur on the background - backgroundColor: "#ff000080" // tint color for the background, you can specify alpha here (optional) - }, - adjustSoftInput: "resize", // android only, adjust soft input, modes: 'nothing', 'pan', 'resize', 'unspecified' (optional, default 'unspecified') -}); -``` - -## dismissLightBox(params = {}) - -Dismiss the current lightbox. - -```js -this.props.navigator.dismissLightBox(); -``` - -## showInAppNotification(params = {}) - -Show in-app notification. This generally looks like a pop-up window that can appear at the top of the screen. - -```js -this.props.navigator.showInAppNotification({ - screen: "example.InAppNotification", // unique ID registered with Navigation.registerScreen - passProps: {}, // simple serializable object that will pass as props to the in-app notification (optional) - autoDismissTimerSec: 1 // auto dismiss notification in seconds -}); -``` - -## handleDeepLink(params = {}) - -Trigger a deep link within the app. See [deep links](https://wix.github.io/react-native-navigation/#/deep-links) for more details about how screens can listen for deep link events. - -```js -this.props.navigator.handleDeepLink({ - link: "chats/2349823023" // the link string (required) -}); -``` - -> `handleDeepLink` can also be called statically: -```js - import {Navigation} from 'react-native-navigation'; - Navigation.handleDeepLink(...); -``` - -## setButtons(params = {}) - -Set buttons dynamically on the navigator. If your buttons don't change during runtime, see "Adding buttons to the navigator" below to add them using `static navigatorButtons = {...};`. - -```js -this.props.navigator.setButtons({ - leftButtons: [], // see "Adding buttons to the navigator" below for format (optional) - rightButtons: [], // see "Adding buttons to the navigator" below for format (optional) - animated: true // does the change have transition animation or does it happen immediately (optional) -}); -``` - -## setTitle(params = {}) - -Set the nav bar title dynamically. If your title doesn't change during runtime, set it when the screen is defined / pushed. - -```js -this.props.navigator.setTitle({ - title: "Dynamic Title" // the new title of the screen as appears in the nav bar -}); -``` - - -## setSubTitle(params = {}) - -Set the nav bar subtitle dynamically. If your subtitle doesn't change during runtime, set it when the screen is defined / pushed. - -```js -this.props.navigator.setSubTitle({ - subtitle: "Connecting..." -}); -``` - -## toggleDrawer(params = {}) - -Toggle the side menu drawer assuming you have one in your app. - -```js -this.props.navigator.toggleDrawer({ - side: 'left', // the side of the drawer since you can have two, 'left' / 'right' - animated: true, // does the toggle have transition animation or does it happen immediately (optional) - to: 'open' // optional, 'open' = open the drawer, 'closed' = close it, missing = the opposite of current state -}); -``` - -## setDrawerEnabled(params = {}) - -Enables or disables the side menu drawer assuming you have one in your app. Both drawers are enabled by default. - -```js -this.props.navigator.setDrawerEnabled({ - side: 'left', // the side of the drawer since you can have two, 'left' / 'right' - enabled: false // should the drawer be enabled or disabled (locked closed) -}); -``` - -## toggleTabs(params = {}) - -Toggle whether the tabs are displayed or not (only in tab-based apps). - -```js -this.props.navigator.toggleTabs({ - to: 'hidden', // required, 'hidden' = hide tab bar, 'shown' = show tab bar - animated: true // does the toggle have transition animation or does it happen immediately (optional) -}); -``` - -## setTabBadge(params = {}) - -Set the badge on a tab (any string or numeric value). - -```js -this.props.navigator.setTabBadge({ - tabIndex: 0, // (optional) if missing, the badge will be added to this screen's tab - badge: 17, // badge value, null to remove badge - badgeColor: '#006400', // (optional) if missing, the badge will use the default color -}); -``` -## setTabButton(params = {}) - -Change the tab icon on a bottom tab. - -```js -this.props.navigator.setTabButton({ - tabIndex: 0, // (optional) if missing, the icon will be added to this screen's tab - icon: require('../img/one.png'), // local image asset for the tab icon unselected state (optional) - selectedIcon: require('../img/one_selected.png'), // local image asset for the tab icon selected state (optional, iOS only) - label: 'New Label' // tab label that appears under the icon (optional) -}); -``` - -## switchToTab(params = {}) - -Switch to a tab (sets it as the currently selected tab). - -```js -this.props.navigator.switchToTab({ - tabIndex: 0 // (optional) if missing, this screen's tab will become selected -}); -``` - -## toggleNavBar(params = {}) - -Toggle whether the navigation bar is displayed or not. - -```js -this.props.navigator.toggleNavBar({ - to: 'hidden', // required, 'hidden' = hide navigation bar, 'shown' = show navigation bar - animated: true // does the toggle have transition animation or does it happen immediately (optional). By default animated: true -}); -``` - -## setOnNavigatorEvent(callback) - -Set a handler for navigator events (like nav button press). This would normally go in your component constructor. -Can not be used in conjuction with `addOnNavigatorEvent`. - -```js -// this.onNavigatorEvent will be our handler -this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); -``` - -## addOnNavigatorEvent(callback) - -Add a handler for navigator events (like nav button press). This would normally go in your component constructor. -If you choose to use `addOnNavigatorEvent` instead of `setOnNavigatorEvent` you will be able to add multiple handlers. -Bear in mind that you can't use both `addOnNavigatorEvent` and `setOnNavigatorEvent`. -`addOnNavigatorEvent` returns a function, that once called will remove the registered handler. - -# Screen Visibility - -`const isVisible = await this.props.navigator.screenIsCurrentlyVisible()` - -## Listen visibility events in onNavigatorEvent handler - -```js -export default class ExampleScreen extends Component { - constructor(props) { - super(props); - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); - } - onNavigatorEvent(event) { - switch(event.id) { - case 'willAppear': - break; - case 'didAppear': - break; - case 'willDisappear': - break; - case 'didDisappear': - break; - case 'willCommitPreview': - break; - } - } -} -``` - -## Listen to visibility events globally - -```js -import {ScreenVisibilityListener as RNNScreenVisibilityListener} from 'react-native-navigation'; - -export class ScreenVisibilityListener { - - constructor() { - this.listener = new RNNScreenVisibilityListener({ - didAppear: ({screen, startTime, endTime, commandType}) => { - console.log('screenVisibility', `Screen ${screen} displayed in ${endTime - startTime} millis after [${commandType}]`); - } - }); - } - - register() { - this.listener.register(); - } - - unregister() { - if (this.listener) { - this.listener.unregister(); - this.listener = null; - } - } -} -``` - -# Listening to tab selected events -In order to listen to `bottomTabSelected` event, set an `onNavigatorEventListener` on screens that are pushed to BottomTab. The event is dispatched to the top most screen pushed to the selected tab's stack. - -```js -export default class ExampleScreen extends Component { - constructor(props) { - super(props); - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); - } - - onNavigatorEvent(event) { - if (event.id === 'bottomTabSelected') { - console.log('Tab selected!'); - } - if (event.id === 'bottomTabReselected') { - console.log('Tab reselected!'); - } - } -} -``` - -# Peek and pop (3D touch) - -react-native-navigation supports the [Peek and pop]( -https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/#//apple_ref/doc/uid/TP40016543-CH1-SW3) feature by setting a react view reference as a `previewView` parameter when doing a push, more options are available in the `push` section. - -You can define actions and listen for interactions on the pushed screen with the `PreviewActionPress` event. - -Previewed screens will have the prop `isPreview` that can be used to render different things when the screen is in the "Peek" state and will then recieve a navigator event of `willCommitPreview` when in the "Pop" state. \ No newline at end of file diff --git a/docs/styling-the-navigator.md b/docs/styling-the-navigator.md deleted file mode 100644 index cdf3959bfd3..00000000000 --- a/docs/styling-the-navigator.md +++ /dev/null @@ -1,136 +0,0 @@ -# Styling the Navigator - -You can style the navigator appearance and behavior by passing a `navigatorStyle` object. This object can be passed when the screen is originally created; can be defined per-screen by setting `static navigatorStyle = {};` on the screen component; and can be overridden when a screen is pushed. - -The easiest way to style your screen is by adding `static navigatorStyle = {};` to your screen React component definition. - -```js -export default class StyledScreen extends Component { - static navigatorStyle = { - drawUnderNavBar: true, - navBarTranslucent: true - }; - constructor(props) { - super(props); - } - render() { - return ( - ... - ); - } -``` - -## Disabling persistent styling properties on iOS -By design, most style properties on iOS are carried on to pushed screens. For example, If the navigation stack contains a single screen with `navBarButtonColor: 'blue'`; any screen pushed to this stack will have a blue `navBar` without needing to declare that property. This results in unpredictable and hard to determine style mechanism, therefore it wasn't implemented on Android. -To disable this behavior on iOS, add `keepStyleAcrossPush: false` to `appStyle`: - -```js -Navigation.startTabBasedApp({ - ... - appStyle: { - keepStyleAcrossPush: false - } -}); -``` - -## Setting styles dynamically -Use the `setStyle` method to change a screen's style dynamically. - -```js -this.props.navigator.setStyle({ - navBarBackgroundColor: 'blue' -}); -``` - -## Style object format - -```js -{ - // Common - navBarTextColor: '#000000', // change the text color of the title (remembered across pushes) - navBarTextFontSize: 18, // change the font size of the title - navBarTextFontFamily: 'font-name', // Changes the title font - navBarBackgroundColor: '#f7f7f7', // change the background color of the nav bar (remembered across pushes) - navBarCustomView: 'example.CustomTopBar', // registered component name - navBarComponentAlignment: 'center', // center/fill - navBarCustomViewInitialProps: {}, // navBar custom component props - navBarButtonColor: '#007aff', // Change color of nav bar buttons (eg. the back button) (remembered across pushes) - topBarElevationShadowEnabled: false, // (Android - default: true, iOS - default: false). Disables TopBar elevation shadow on Lolipop and above - navBarHidden: false, // make the nav bar hidden - navBarHideOnScroll: false, // make the nav bar hidden only after the user starts to scroll - navBarTranslucent: false, // make the nav bar semi-translucent, works best with drawUnderNavBar:true - navBarTransparent: false, // make the nav bar transparent, works best with drawUnderNavBar:true, - navBarNoBorder: false, // hide the navigation bar bottom border (hair line). Default false - drawUnderNavBar: false, // draw the screen content under the nav bar, works best with navBarTranslucent:true - drawUnderTabBar: false, // draw the screen content under the tab bar (the tab bar is always translucent) - navBarBlur: false, // blur the entire nav bar, works best with drawUnderNavBar:true - tabBarHidden: false, // make the screen content hide the tab bar (remembered across pushes) - statusBarHidden: false, // make the status bar hidden regardless of nav bar state - statusBarTextColorScheme: 'dark', // text color of status bar, 'dark' / 'light' (remembered across pushes) - navBarSubtitleColor: 'red', // subtitle color - navBarSubtitleFontFamily: 'font-name', // subtitle font, 'sans-serif-thin' for example - navBarSubtitleFontSize: 13, // subtitle font size - screenBackgroundColor: 'white', // Default screen color, visible before the actual react view is rendered - orientation: 'portrait' // Sets a specific orientation to a modal and all screens pushed to it. Default: 'auto'. Supported values: 'auto', 'landscape', 'portrait' - disabledButtonColor: '#ff0000' // chnaged the navigation bar button text color when disabled. - - // iOS only - statusBarTextColorSchemeSingleScreen: 'light', // same as statusBarTextColorScheme but does NOT remember across pushes - statusBarHideWithNavBar: false, // hide the status bar if the nav bar is also hidden, useful for navBarHidden:true - statusBarBlur: false, // blur the area under the status bar, works best with navBarHidden:true - - disabledBackGesture: false, // default: false. Disable the back gesture (swipe gesture) in order to pop the top screen. - disabledSimultaneousGesture: true, // default: true. Disable simultaneous gesture recognition. - screenBackgroundImageName: '', // Optional. default screen background image. - rootBackgroundImageName: '', // Static while you transition between screens. Works best with screenBackgroundColor: 'transparent' - - navBarButtonFontSize: 20, // Change font size nav bar buttons (eg. the back button) (remembered across pushes) - navBarButtonFontWeight: '500', // Change font weight nav bar buttons (eg. the back button) (remembered across pushes) - - navBarLeftButtonFontSize: 17, // Change font size of left nav bar button - navBarLeftButtonColor: 'red', // Change color of left nav bar button - navBarLeftButtonFontWeight: '400', // Change font weight of left nav bar button - - navBarRightButtonFontSize: 17, // Change font size of right nav bar button - navBarRightButtonColor: 'blue', // Change color of right nav bar button - navBarRightButtonFontWeight: '600', // Change font weight of right nav bar button - - topBarShadowColor: 'blue' // Sets shadow of the navbar, Works only when topBarElevationShadowEnabled: true - topBarShadowOpacity: 0.5, // Sets shadow opacity on the navbar, Works only when topBarElevationShadowEnabled: true - topBarShadowOffset: 12, // Sets shadow offset on the navbar, Works only when topBarElevationShadowEnabled: true - topBarShadowRadius: 3 // Sets shadow radius on the navbar, Works only when topBarElevationShadowEnabled: true - - preferredContentSize: { width: 500, height: 500 } // Sets the preferred size for the view controller’s view. - modalPresentationStyle: 'formSheet' // Sets the presentation style for modally presented view controllers. Supported styles are: 'formSheet', 'pageSheet', 'overFullScreen', 'overCurrentContext' and 'fullScreen'. - - largeTitle: false, // Sets the nav bar title to be in the larger iOS 11 style - - // Android only - navigationBarColor: '#000000', // change the background color of the bottom native navigation bar. - navBarTitleTextCentered: true, // default: false. centers the title. - navBarButtonFontFamily: 'sans-serif-thin', // Change the font family of textual buttons - statusBarColor: '#000000', // change the color of the status bar. - drawUnderStatusBar: false, // default: false, will draw the screen underneath the statusbar. Useful togheter with statusBarColor: transparent - collapsingToolBarImage: "http://lorempixel.com/400/200/", // Collapsing Toolbar image. - collapsingToolBarImage: require('../../img/topbar.jpg'), // Collapsing Toolbar image. Either use a url or require a local image. - collapsingToolBarCollapsedColor: '#0f2362', // Collapsing Toolbar scrim color. - navBarTextFontBold: false, // Optional. Set the title to bold. - navBarHeight: 70, // Optional, set the navBar height in pixels. - navBarTopPadding: 24, // Optional, set navBar top padding in dp. Useful when StatusBar.translucent=true on Android Lollipop and above. - topTabsHeight: 70, // Optional, set topTabs height in pixels. - topBarBorderColor: 'red', // Optional, set a flat border under the TopBar. - topBarBorderWidth: 5.5, // Optional, set the width of the border. -} -``` - -## Styling the StatusBar -If you set any styles related to the Status Bar, make sure that in Xcode > project > Info.plist, the property `View controller-based status bar appearance` is set to `YES`. - -## Custom fonts -If you'd like to use a custom font, you'll first have to edit your project. - -* Android - add the `.ttf` or `.otf` files to `src/main/assets/fonts/` - -* iOS - follow this [guide](https://medium.com/@dabit3/adding-custom-fonts-to-react-native-b266b41bff7f) - -All supported styles are defined [here](https://github.com/wix/react-native-controllers#styling-navigation). There's also an example project there showcasing all the different styles. diff --git a/docs/styling-the-tab-bar.md b/docs/styling-the-tab-bar.md deleted file mode 100644 index 95863f708de..00000000000 --- a/docs/styling-the-tab-bar.md +++ /dev/null @@ -1,45 +0,0 @@ -# Styling the Tab Bar - -You can style the tab bar appearance by passing a `tabsStyle` object when the app is originally created (on `startTabBasedApp`). - -```js -Navigation.startTabBasedApp({ - tabs: [ ... ], - tabsStyle: { // optional, **iOS Only** add this if you want to style the tab bar beyond the defaults - tabBarButtonColor: '#ff0000' - } -}); -``` - -#### Style object format - -```js -{ - tabBarHidden: false, // make the tab bar hidden - tabBarButtonColor: '#ffff00', // change the color of the tab icons and text (also unselected) - tabBarSelectedButtonColor: '#ff9900', // change the color of the selected tab icon and text (only selected) - tabBarBackgroundColor: '#551A8B', // change the background color of the tab bar - tabBarTranslucent: false, // change the translucent of the tab bar to false - tabBarTextFontFamily: 'Avenir-Medium', //change the tab font family -  tabBarLabelColor: '#ffb700', // iOS only. change the color of tab text -  tabBarSelectedLabelColor: 'red', // iOS only. change the color of the selected tab text -  forceTitlesDisplay: true, // Android only. If true - Show all bottom tab labels. If false - only the selected tab's label is visible. - tabBarHideShadow: true // iOS only. Remove default tab bar top shadow (hairline) -} -``` - -?> On Android, add BottomTabs styles to `AppStyle`: - -```js -Navigation.startTabBasedApp({ - tabs: [...], - appStyle: { - tabBarBackgroundColor: '#0f2362', - tabBarButtonColor: '#ffffff', - tabBarSelectedButtonColor: '#63d7cc', - tabBarTranslucent: false, - tabFontFamily: 'Avenir-Medium' // existing font family name or asset file without extension which can be '.ttf' or '.otf' (searched only if '.ttf' asset not found) - }, -... -} -``` diff --git a/docs/sw.js b/docs/sw.js deleted file mode 100644 index cf6295c494b..00000000000 --- a/docs/sw.js +++ /dev/null @@ -1,83 +0,0 @@ -/* =========================================================== - * docsify sw.js - * =========================================================== - * Copyright 2016 @huxpro - * Licensed under Apache 2.0 - * Register service worker. - * ========================================================== */ - -const RUNTIME = 'docsify' -const HOSTNAME_WHITELIST = [ - self.location.hostname, - 'fonts.gstatic.com', - 'fonts.googleapis.com', - 'unpkg.com' -] - -// The Util Function to hack URLs of intercepted requests -const getFixedUrl = (req) => { - var now = Date.now() - var url = new URL(req.url) - - // 1. fixed http URL - // Just keep syncing with location.protocol - // fetch(httpURL) belongs to active mixed content. - // And fetch(httpRequest) is not supported yet. - url.protocol = self.location.protocol - - // 2. add query for caching-busting. - // Github Pages served with Cache-Control: max-age=600 - // max-age on mutable content is error-prone, with SW life of bugs can even extend. - // Until cache mode of Fetch API landed, we have to workaround cache-busting with query string. - // Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190 - if (url.hostname === self.location.hostname) { - url.search += (url.search ? '&' : '?') + 'cache-bust=' + now - } - return url.href -} - -/** - * @Lifecycle Activate - * New one activated when old isnt being used. - * - * waitUntil(): activating ====> activated - */ -self.addEventListener('activate', event => { - event.waitUntil(self.clients.claim()) -}) - -/** - * @Functional Fetch - * All network requests are being intercepted here. - * - * void respondWith(Promise r) - */ -self.addEventListener('fetch', event => { - // Skip some of cross-origin requests, like those for Google Analytics. - if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) { - // Stale-while-revalidate - // similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale - // Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1 - const cached = caches.match(event.request) - const fixedUrl = getFixedUrl(event.request) - const fetched = fetch(fixedUrl, { cache: 'no-store' }) - const fetchedCopy = fetched.then(resp => resp.clone()) - - // Call respondWith() with whatever we get first. - // If the fetch fails (e.g disconnected), wait for the cache. - // If there’s nothing in cache, wait for the fetch. - // If neither yields a response, return offline pages. - event.respondWith( - Promise.race([fetched.catch(_ => cached), cached]) - .then(resp => resp || fetched) - .catch(_ => { /* eat any errors */ }) - ) - - // Update the cache with the version we fetched (only for ok status) - event.waitUntil( - Promise.all([fetchedCopy, caches.open(RUNTIME)]) - .then(([response, cache]) => response.ok && cache.put(event.request, response)) - .catch(_ => { /* eat any errors */ }) - ) - } -}) \ No newline at end of file diff --git a/docs/third-party-libraries-support.md b/docs/third-party-libraries-support.md deleted file mode 100644 index e4ea2125a7b..00000000000 --- a/docs/third-party-libraries-support.md +++ /dev/null @@ -1,17 +0,0 @@ -# Third Party Libraries Support - -## react-native-vector-icons - -If you would like to use [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons) for your Toolbar icons, you can follow [this example](https://github.com/wix/react-native-navigation/issues/43#issuecomment-223907515) or [this](https://gist.github.com/dropfen/4a2209d7274788027f782e8655be198f) gist. - -## Redux -Redux can be easily integrated with RNN, follow this great [blog post](https://medium.com/react-native-training/explanation-of-react-native-navigation-wix-with-redux-deabcee8edfc) for instructions. - -## Mobx -If you prefer Mobx over Redux, show your interest in this [thread](https://github.com/wix/react-native-navigation/issues/187). Also checkout @mastermoo's [POC](https://github.com/mastermoo/navigation-mobx-example) of using navigation with Mobx. - -### MobX (w/ Provider) boilerplate -Check out [this link](https://github.com/kanzitelli/react-native-navigation-mobx-boilerplate) to find a small boilerplate for RNN + MobX (w/ Provider). - -### redux-persist -Boilerplate for integrating redux-persist can be found [here](https://stackoverflow.com/questions/47732500/react-native-navigation-and-redux-persist). diff --git a/docs/top-level-api.md b/docs/top-level-api.md deleted file mode 100644 index d007b88fe0b..00000000000 --- a/docs/top-level-api.md +++ /dev/null @@ -1,225 +0,0 @@ -# Top Level API - -## Navigation - -```js -import { Navigation } from 'react-native-navigation'; -``` - -## registerComponent(screenID, generator, store = undefined, Provider = undefined) - -Every screen component in your app must be registered with a unique name. The component itself is a traditional React component extending `React.Component`. - -```js -// not using redux (just ignore the last 2 arguments) -Navigation.registerComponent('example.FirstTabScreen', () => FirstTabScreen); - -// using redux, pass your store and the Provider object from react-redux -Navigation.registerComponent( - 'example.FirstTabScreen', - () => FirstTabScreen, - store, - Provider -); -``` - -## startTabBasedApp(params) - -Change your app root into an app based on several tabs (usually 2-5), a very common pattern in iOS (like Facebook app or the iOS Contacts app). Every tab has its own navigation stack with a native nav bar. - -```js -Navigation.startTabBasedApp({ - tabs: [ - { - label: 'One', // tab label as appears under the icon in iOS (optional) - screen: 'example.FirstTabScreen', // unique ID registered with Navigation.registerScreen - icon: require('../img/one.png'), // local image asset for the tab icon unselected state (optional on iOS) - selectedIcon: require('../img/one_selected.png'), // local image asset for the tab icon selected state (optional, iOS only. On Android, Use `tabBarSelectedButtonColor` instead) - iconInsets: { // add this to change icon position (optional, iOS only). - top: 6, // optional, default is 0. - left: 0, // optional, default is 0. - bottom: -6, // optional, default is 0. - right: 0 // optional, default is 0. - }, - title: 'Screen One', // title of the screen as appears in the nav bar (optional) - titleImage: require('../img/titleImage.png'), // iOS only. navigation bar title image instead of the title text of the pushed screen (optional) - navigatorStyle: {}, // override the navigator style for the tab screen, see "Styling the navigator" below (optional), - navigatorButtons: {} // override the nav buttons for the tab screen, see "Adding buttons to the navigator" below (optional) - }, - { - label: 'Two', - screen: 'example.SecondTabScreen', - icon: require('../img/two.png'), - selectedIcon: require('../img/two_selected.png'), - title: 'Screen Two' - } - ], - tabsStyle: { // optional, add this if you want to style the tab bar beyond the defaults - tabBarButtonColor: '#ffff00', // optional, change the color of the tab icons and text (also unselected). On Android, add this to appStyle - tabBarSelectedButtonColor: '#ff9900', // optional, change the color of the selected tab icon and text (only selected). On Android, add this to appStyle - tabBarBackgroundColor: '#551A8B', // optional, change the background color of the tab bar - initialTabIndex: 1, // optional, the default selected bottom tab. Default: 0. On Android, add this to appStyle - }, - appStyle: { - orientation: 'portrait', // Sets a specific orientation to the entire app. Default: 'auto'. Supported values: 'auto', 'landscape', 'portrait' - bottomTabBadgeTextColor: 'red', // Optional, change badge text color. Android only - bottomTabBadgeBackgroundColor: 'green', // Optional, change badge background color. Android only - backButtonImage: require('./pathToImage.png') // Change the back button default arrow image with provided image. iOS only - hideBackButtonTitle: true/false // Hide back button title. Default is false. If `backButtonTitle` provided so it will take into account and the `backButtonTitle` value will show. iOS only - }, - drawer: { // optional, add this if you want a side menu drawer in your app - left: { // optional, define if you want a drawer from the left - screen: 'example.FirstSideMenu', // unique ID registered with Navigation.registerScreen - passProps: {} // simple serializable object that will pass as props to all top screens (optional), - fixedWidth: 500, // a fixed width you want your left drawer to have (optional) - }, - right: { // optional, define if you want a drawer from the right - screen: 'example.SecondSideMenu', // unique ID registered with Navigation.registerScreen - passProps: {} // simple serializable object that will pass as props to all top screens (optional) - fixedWidth: 500, // a fixed width you want your right drawer to have (optional) - }, - style: { // ( iOS only ) -      drawerShadow: true, // optional, add this if you want a side menu drawer shadow -      contentOverlayColor: 'rgba(0,0,0,0.25)', // optional, add this if you want a overlay color when drawer is open - leftDrawerWidth: 50, // optional, add this if you want a define left drawer width (50=percent) - rightDrawerWidth: 50, // optional, add this if you want a define right drawer width (50=percent) - shouldStretchDrawer: true // optional, iOS only with 'MMDrawer' type, whether or not the panning gesture will “hard-stop” at the maximum width for a given drawer side, default : true - }, - type: 'MMDrawer', // optional, iOS only, types: 'TheSideBar', 'MMDrawer' default: 'MMDrawer' - animationType: 'door', //optional, iOS only, for MMDrawer: 'door', 'parallax', 'slide', 'slide-and-scale' - // for TheSideBar: 'airbnb', 'facebook', 'luvocracy','wunder-list' - disableOpenGesture: false // optional, can the drawer be opened with a swipe instead of button - }, - passProps: {}, // simple serializable object that will pass as props to all top screens (optional) - animationType: 'slide-down' // optional, add transition animation to root change: 'none', 'slide-down', 'fade' -}); -``` - -## startSingleScreenApp(params) - -Change your app root into an app based on a single screen (like the iOS Calendar or Settings app). The screen will receive its own navigation stack with a native nav bar - -```js -Navigation.startSingleScreenApp({ - screen: { - screen: 'example.WelcomeScreen', // unique ID registered with Navigation.registerScreen - title: 'Welcome', // title of the screen as appears in the nav bar (optional) - navigatorStyle: {}, // override the navigator style for the screen, see "Styling the navigator" below (optional) - navigatorButtons: {} // override the nav buttons for the screen, see "Adding buttons to the navigator" below (optional) - }, - drawer: { - // optional, add this if you want a side menu drawer in your app - left: { - // optional, define if you want a drawer from the left - screen: 'example.FirstSideMenu', // unique ID registered with Navigation.registerScreen - passProps: {}, // simple serializable object that will pass as props to all top screens (optional) - disableOpenGesture: false, // can the drawer be opened with a swipe instead of button (optional, Android only) - fixedWidth: 500 // a fixed width you want your left drawer to have (optional) - }, - right: { - // optional, define if you want a drawer from the right - screen: 'example.SecondSideMenu', // unique ID registered with Navigation.registerScreen - passProps: {}, // simple serializable object that will pass as props to all top screens (optional) - disableOpenGesture: false, // can the drawer be opened with a swipe instead of button (optional, Android only) - fixedWidth: 500 // a fixed width you want your right drawer to have (optional) - }, - style: { - // ( iOS only ) - drawerShadow: true, // optional, add this if you want a side menu drawer shadow - contentOverlayColor: 'rgba(0,0,0,0.25)', // optional, add this if you want a overlay color when drawer is open - leftDrawerWidth: 50, // optional, add this if you want a define left drawer width (50=percent) - rightDrawerWidth: 50 // optional, add this if you want a define right drawer width (50=percent) - }, - type: 'MMDrawer', // optional, iOS only, types: 'TheSideBar', 'MMDrawer' default: 'MMDrawer' - animationType: 'door', //optional, iOS only, for MMDrawer: 'door', 'parallax', 'slide', 'slide-and-scale' - // for TheSideBar: 'airbnb', 'facebook', 'luvocracy','wunder-list' - disableOpenGesture: false // optional, can the drawer, both right and left, be opened with a swipe instead of button - }, - passProps: {}, // simple serializable object that will pass as props to all top screens (optional) - animationType: 'slide-down' // optional, add transition animation to root change: 'none', 'slide-down', 'fade' -}); -``` - -## showModal(params = {}) - -Show a screen as a modal. - -```js -Navigation.showModal({ - screen: 'example.ModalScreen', // unique ID registered with Navigation.registerScreen - title: 'Modal', // title of the screen as appears in the nav bar (optional) - passProps: {}, // simple serializable object that will pass as props to the modal (optional) - navigatorStyle: {}, // override the navigator style for the screen, see "Styling the navigator" below (optional) - navigatorButtons: {}, // override the nav buttons for the screen, see "Adding buttons to the navigator" below (optional) - animationType: 'slide-up' // 'none' / 'slide-up' , appear animation for the modal (optional, default 'slide-up') -}); -``` - -## dismissModal(params = {}) - -Dismiss the current modal. - -```js -Navigation.dismissModal({ - animationType: 'slide-down' // 'none' / 'slide-down' , dismiss animation for the modal (optional, default 'slide-down') -}); -``` - -## dismissAllModals(params = {}) - -Dismiss all the current modals at the same time. - -```js -Navigation.dismissAllModals({ - animationType: 'slide-down' // 'none' / 'slide-down' , dismiss animation for the modal (optional, default 'slide-down') -}); -``` - -## showLightBox(params = {}) - -Show a screen as a lightbox. - -```js -Navigation.showLightBox({ - screen: 'example.LightBoxScreen', // unique ID registered with Navigation.registerScreen - passProps: {}, // simple serializable object that will pass as props to the lightbox (optional) - style: { - backgroundBlur: 'dark', // 'dark' / 'light' / 'xlight' / 'none' - the type of blur on the background - backgroundColor: '#ff000080', // tint color for the background, you can specify alpha here (optional) - tapBackgroundToDismiss: true // dismisses LightBox on background taps (optional) - } -}); -``` - -## dismissLightBox(params = {}) - -Dismiss the current lightbox. - -```js -Navigation.dismissLightBox(); -``` - -## handleDeepLink(params = {}) - -Trigger a deep link within the app. See [deep links](https://wix.github.io/react-native-navigation/#/deep-links) for more details about how screens can listen for deep link events. - -```js -Navigation.handleDeepLink({ - link: 'link/in/any/format', - payload: '' // (optional) Extra payload with deep link -}); -``` - -## registerScreen(screenID, generator) - -This is an internal function you probably don't want to use directly. If your screen components extend `Screen` directly (`import { Screen } from 'react-native-navigation'`), you can register them directly with `registerScreen` instead of with `registerComponent`. The main benefit of using `registerComponent` is that it wraps your regular screen component with a `Screen` automatically. - -```js -Navigation.registerScreen('example.AdvancedScreen', () => AdvancedScreen); -``` - -## getCurrentlyVisibleScreenId() - -In some cases you might need the id of the currently visible screen. This method returns the unique id of the currently visible screen: -`const visibleScreenInstanceId = await Navigation.getCurrentlyVisibleScreenId()` -In order to have any use of this method, you'd need to map instanceId to screens your self. diff --git a/docs/usage.md b/docs/usage.md deleted file mode 100644 index 2d510ab66d8..00000000000 --- a/docs/usage.md +++ /dev/null @@ -1,73 +0,0 @@ -# Usage - -If you don't like reading, just jump into the fully working example projects: - -* [example](https://github.com/wix/react-native-navigation/tree/master/example) - Example project showing the best practice use of this package. Shows many navigation features. -* [redux-example](https://github.com/wix/react-native-navigation/tree/master/old-example-redux) - (**deprecated** in favor of [JuneDomingo/movieapp](https://github.com/JuneDomingo/movieapp/tree/feature/similar-movies)) Best practice use of this package in a [redux](https://github.com/reactjs/redux)-based project. - -> Note: example redux is deprecated. Since we did not have enough time and resources to maintain both example projects, we decided to stop maintaining the redux example. This does not mean redux can't be used with react-native-navigation (In fact, we use redux in the Wix app). For a working example project which uses redux with RNN you can refer to [JuneDomingo/movieapp](https://github.com/JuneDomingo/movieapp). - -#### Step 1 - Change the way your app starts - -This would normally go in your `index.ios.js` - -```js -import { Navigation } from 'react-native-navigation'; - -import { registerScreens } from './screens'; - -registerScreens(); // this is where you register all of your app's screens - -// start the app -Navigation.startTabBasedApp({ - tabs: [ - { - label: 'One', - screen: 'example.FirstTabScreen', // this is a registered name for a screen - icon: require('../img/one.png'), - selectedIcon: require('../img/one_selected.png'), // iOS only - title: 'Screen One' - }, - { - label: 'Two', - screen: 'example.SecondTabScreen', - icon: require('../img/two.png'), - selectedIcon: require('../img/two_selected.png'), // iOS only - title: 'Screen Two' - } - ] -}); -``` - -#### Step 2 - Register all of your screen components - -Every screen that you want to be able to place in a tab, push to the navigation stack or present modally needs to be registered. We recommend doing this in a central place, like [screens/index.js](https://github.com/wix/react-native-navigation/blob/master/example/src/screens/index.js). - -> Note: Since your screens will potentially be bundled with other packages, your registered name must be **unique**! Follow a namespacing convention like `packageName.ScreenName`. - -```js -import { Navigation } from 'react-native-navigation'; - -import FirstTabScreen from './FirstTabScreen'; -import SecondTabScreen from './SecondTabScreen'; -import PushedScreen from './PushedScreen'; - -// register all screens of the app (including internal ones) -export function registerScreens() { - Navigation.registerComponent('example.FirstTabScreen', () => FirstTabScreen); - Navigation.registerComponent('example.SecondTabScreen', () => SecondTabScreen); - Navigation.registerComponent('example.PushedScreen', () => PushedScreen); -} -``` - -#### Step 3 - That's it - -If you want to do a navigation action like push a new screen over an existing one, take a look at the [Screen API](#screen-api). It would look something like this: - -```js -// this would go inside the Component implementation of one of your screens, like FirstTabScreen.js -this.props.navigator.push({ - screen: 'example.PushedScreen', - title: 'Pushed Screen' -}); -``` diff --git a/docs/v2/index.html b/docs/v2/index.html deleted file mode 100644 index 9e465918f3f..00000000000 --- a/docs/v2/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - React Native Navigation v2 - truly native navigation for iOS and Android - - - - - - - -
- react-native-navigation logo -
- - - - - - - diff --git a/e2e/AndroidUtils.js b/e2e/AndroidUtils.js new file mode 100644 index 00000000000..942233b82d4 --- /dev/null +++ b/e2e/AndroidUtils.js @@ -0,0 +1,43 @@ +const exec = require('shell-utils').exec; + +const utils = { + pressBack: () => device.pressBack(), + pressMenu: () => device.getUiDevice().pressMenu(), + pressKeyCode: (keyCode) => device.getUiDevice().pressKeyCode(keyCode), + grantPermission: () => + utils.executeShellCommand( + 'pm grant com.reactnativenavigation.playground android.permission.READ_PHONE_STATE' + ), + revokePermission: () => + utils.executeShellCommand( + 'pm revoke com.reactnativenavigation.playground android.permission.READ_PHONE_STATE' + ), + executeShellCommand: (command) => { + // TODO Change to use Detox's ADB (see keyboard driver) + exec.execSync(`adb -s ${device.id} shell ${command}`); + }, + setDemoMode: () => { + // enter demo mode + utils.executeShellCommand('settings put global sysui_demo_allowed 1'); + // display time 12:00 + utils.executeShellCommand( + 'am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1200' + ); + // Display full mobile data with 4g type and no wifi + utils.executeShellCommand( + 'am broadcast -a com.android.systemui.demo -e command network -e mobile show -e level 4 -e datatype 4g -e wifi false' + ); + // Hide notifications + utils.executeShellCommand( + 'am broadcast -a com.android.systemui.demo -e command notifications -e visible false' + ); + // Disable pointer location + utils.executeShellCommand('settings put system pointer_location 0'); + // Show full battery but not in charging state + utils.executeShellCommand( + 'am broadcast -a com.android.systemui.demo -e command battery -e plugged false -e level 100' + ); + }, +}; + +export default utils; diff --git a/e2e/ApplicationLifecycleTest.test.js b/e2e/ApplicationLifecycleTest.test.js new file mode 100644 index 00000000000..d956a277ce8 --- /dev/null +++ b/e2e/ApplicationLifecycleTest.test.js @@ -0,0 +1,123 @@ +import Utils from './Utils'; +import Android from './AndroidUtils'; +import TestIDs from '../playground/src/testIDs'; +import includes from 'lodash/includes'; + +const { elementByLabel, elementById, sleep } = Utils; +const IS_RELEASE = includes(process.argv, '--release'); +const KEY_CODE_R = 46; + +describe.e2e('application lifecycle test', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + }); + + it('push a screen to ensure its not there after reload', async () => { + await elementById(TestIDs.STACK_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + await device.reloadReactNative(); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it('relaunch from background', async () => { + await elementById(TestIDs.STACK_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + + await device.sendToHome(); + await device.launchApp({ newInstance: false }); + + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + }); + + it(':android: relaunch after close with back button', async () => { + await elementById(TestIDs.STACK_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + + await Android.pressBack(); + + await device.launchApp({ newInstance: false }); + await expect(elementByLabel('Pushed Screen')).toBeNotVisible(); + }); + + it('device orientation does not destroy activity', async () => { + await elementById(TestIDs.STACK_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + + await device.setOrientation('landscape'); + + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + }); + + it(':android: relaunch after activity killed by system', async () => { + await elementById(TestIDs.STACK_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + await device.sendToHome(); + + await togglePhonePermission(); + await sleep(5000); + await device.launchApp({ newInstance: false }); + + await expect(elementByLabel('Pushed Screen')).toBeNotVisible(); + await expect(elementById(TestIDs.WELCOME_SCREEN_HEADER)).toBeVisible(); + }); + + it(':android: pressing r twice with delay does nothing', async () => { + if (!IS_RELEASE) { + await elementById(TestIDs.STACK_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + + await Android.pressKeyCode(KEY_CODE_R); + await sleep(1000); + await Android.pressKeyCode(KEY_CODE_R); + + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + } + }); + + xit(':android: pressing menu opens dev menu', async () => { + if (!IS_RELEASE) { + await Android.pressMenu(); + await sleep(1000); + await expect(elementByLabel('Reload')).toBeVisible(); + } + }); + + xit(':android: pressing r twice in succession reloads React Native', async () => { + if (!IS_RELEASE) { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + + await Android.pressKeyCode(KEY_CODE_R); + await Android.pressKeyCode(KEY_CODE_R); + + await sleep(300); + await expect(elementByLabel('React Native Navigation!')).toBeVisible(); + } + }); + + xit(':android: sending reload broadcast reloads react native', async () => { + if (!IS_RELEASE) { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + + Android.executeShellCommand('am broadcast -a com.reactnativenavigation.broadcast.RELOAD'); + + await sleep(1000); + await expect(elementByLabel('React Native Navigation!')).toBeVisible(); + } + }); + + async function togglePhonePermission() { + await sleep(700); + Android.revokePermission(); + await sleep(700); + Android.grantPermission(); + await sleep(1000); + } +}); diff --git a/e2e/BackButton.test.js b/e2e/BackButton.test.js new file mode 100644 index 00000000000..935cbcd5623 --- /dev/null +++ b/e2e/BackButton.test.js @@ -0,0 +1,66 @@ +import { default as TestIDs, default as testIDs } from '../playground/src/testIDs'; +import Android from './AndroidUtils'; +import Utils from './Utils'; + +const { elementByLabel, elementById } = Utils; + +describe('Back Button', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.NAVIGATION_TAB).tap(); + await elementById(TestIDs.BACK_BUTTON_SCREEN_BTN).tap(); + await elementById(TestIDs.STATIC_EVENTS_OVERLAY_BTN).tap(); + }); + + it('prevents pop and dispatch event', async () => { + await elementById(TestIDs.PUSH_DISABLED_BACK_BTN).tap(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.BACK_BUTTON).tap(); + await expect(elementByLabel('navigationButtonPressed | RNN.back')).toBeVisible(); + await expect(elementById(testIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + }); + + it('pops and does not dispatch event', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.BACK_BUTTON).tap(); + await expect(elementByLabel('navigationButtonPressed | RNN.back')).toBeNotVisible(); + }); + + it('toggle visibility', async () => { + await elementById(TestIDs.TOGGLE_BACK_BUTTON_VISIBILITY).tap(); + await expect(elementById(TestIDs.BACK_BUTTON)).toBeNotVisible(); + await elementById(TestIDs.TOGGLE_BACK_BUTTON_VISIBILITY).tap(); + await elementById(TestIDs.DISMISS_BTN).tap(); + await elementByLabel('OK').tap(); + await elementById(TestIDs.BACK_BUTTON).tap(); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it.e2e(':android: hardware back button prevents pop and dispatch event', async () => { + await elementById(TestIDs.PUSH_DISABLED_HARDWARE_BACK_BTN).tap(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await Android.pressBack(); + await expect(elementByLabel('navigationButtonPressed | RNN.hardwareBackButton')).toBeVisible(); + await expect(elementById(testIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + }); + + it.e2e(':android: hardware button pops and does not dispatch event', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await Android.pressBack(); + await expect( + elementByLabel('navigationButtonPressed | RNN.hardwareBackButton') + ).toBeNotVisible(); + await expect(elementById(testIDs.PUSHED_SCREEN_HEADER)).toBeNotVisible(); + }); + + it.e2e(':android: hardware back should not dismiss modal and dispatch event', async () => { + await elementById(TestIDs.MODAL_DISABLED_BACK_BTN).tap(); + await expect(elementByLabel('Modal')).toBeVisible(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await Android.pressBack(); + await expect(elementByLabel('Modal')).toBeVisible(); + await expect(elementByLabel('navigationButtonPressed | RNN.hardwareBackButton')).toBeVisible(); + }); +}); diff --git a/e2e/BottomTabs.test.js b/e2e/BottomTabs.test.js new file mode 100644 index 00000000000..d9b33410ec7 --- /dev/null +++ b/e2e/BottomTabs.test.js @@ -0,0 +1,181 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; +import Android from './AndroidUtils'; + +const { elementByLabel, elementById, expectImagesToBeEqual } = Utils; + +describe('BottomTabs', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.BOTTOM_TABS_BTN).tap(); + await expect(elementByLabel('First Tab')).toBeVisible(); + }); + + it.e2e('should mount first tab first', async () => { + await expect(elementById(TestIDs.MOUNTED_SCREENS_TEXT)).toHaveText( + 'Mounted screens: FirstBottomTabScreen, SecondBottomTabScreen' + ); + }); + + it('switch to tab by index', async () => { + await elementById(TestIDs.SWITCH_TAB_BY_INDEX_BTN).tap(); + await expect(elementByLabel('First Tab')).toBeNotVisible(); + await expect(elementByLabel('Second Tab')).toBeVisible(); + }); + + it('switch to tab by componentId', async () => { + await elementById(TestIDs.SWITCH_TAB_BY_COMPONENT_ID_BTN).tap(); + await expect(elementByLabel('First Tab')).toBeNotVisible(); + await expect(elementByLabel('Second Tab')).toBeVisible(); + }); + + it('push bottom tabs', async () => { + await elementById(TestIDs.SWITCH_TAB_BY_INDEX_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementById(TestIDs.PUSHED_BOTTOM_TABS)).toBeVisible(); + }); + + it('set Tab Bar badge on current Tab', async () => { + await elementById(TestIDs.SET_BADGE_BTN).tap(); + await expect(element(by.text('NEW'))).toBeVisible(); + }); + + it('Badge not cleared after showing/dismissing modal', async () => { + await elementById(TestIDs.SECOND_TAB_BAR_BTN).tap(); + await elementById(TestIDs.SET_BADGE_BTN).tap(); + await expect(element(by.text('Badge'))).toBeVisible(); + await elementById(TestIDs.MODAL_BTN).tap(); + await elementById(TestIDs.MODAL_BTN).tap(); + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(element(by.text('Badge'))).toBeVisible(); + }); + + it('set empty string badge on a current Tab should clear badge', async () => { + await elementById(TestIDs.SET_BADGE_BTN).tap(); + await expect(element(by.text('NEW'))).toBeVisible(); + await elementById(TestIDs.CLEAR_BADGE_BTN).tap(); + await expect(element(by.text('NEW'))).toBeNotVisible(); + }); + + it.e2e('merge options correctly in SideMenu inside BottomTabs layout', async () => { + await elementById(TestIDs.SWITCH_TAB_BY_INDEX_BTN).tap(); + await elementById(TestIDs.SIDE_MENU_INSIDE_BOTTOM_TABS_BTN).tap(); + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + + await elementById(TestIDs.CLOSE_LEFT_SIDE_MENU_BTN).tap(); + await expect(elementById(TestIDs.CLOSE_LEFT_SIDE_MENU_BTN)).toBeNotVisible(); + }); + + it(':android: hide Tab Bar', async () => { + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeVisible(); + await elementById(TestIDs.HIDE_TABS_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeNotVisible(); + }); + + it(':android: show Tab Bar', async () => { + await elementById(TestIDs.HIDE_TABS_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeNotVisible(); + await elementById(TestIDs.SHOW_TABS_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeVisible(); + }); + + it.e2e(':android: should set special stylizing options in root bottom-tabs', async () => { + await elementById(TestIDs.SCREEN_ROOT_LIST).scrollTo('bottom'); + await elementById(TestIDs.SET_ROOT_BTN).tap(); + const snapshotImagePath = `./e2e/assets/bottom_tabs.stylized-root.png`; + const actual = + await elementById('RNN.BottomTabsLayoutRoot').takeScreenshot(`bottom_tabs_stylized-root`); + expectImagesToBeEqual(actual, snapshotImagePath); + }); + + it.e2e(':android: should merge special stylizing options', async () => { + await elementById(TestIDs.SCREEN_ROOT_LIST).scrollTo('bottom'); + await elementById(TestIDs.STYLIZE_TABS_BTN).tap(); + const snapshotImagePath = `./e2e/assets/bottom_tabs.stylized.png`; + const actual = + await elementById('RNN.BottomTabsLayoutRoot').takeScreenshot(`bottom_tabs_stylized`); + expectImagesToBeEqual(actual, snapshotImagePath); + }); + + it('hide Tab Bar on push', async () => { + await elementById(TestIDs.HIDE_TABS_PUSH_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeNotVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeVisible(); + }); + + it('hide Tab Bar on push from second bottomTabs screen', async () => { + await elementById(TestIDs.SWITCH_TAB_BY_INDEX_BTN).tap(); + await elementById(TestIDs.HIDE_TABS_PUSH_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeNotVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeVisible(); + }); + + it('hide Tab Bar on push from second bottomTabs screen - deep stack', async () => { + await elementById(TestIDs.SWITCH_TAB_BY_INDEX_BTN).tap(); + await elementById(TestIDs.HIDE_TABS_PUSH_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeNotVisible(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeNotVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeVisible(); + }); + + it('hide Tab Bar on second tab after pressing the tab', async () => { + await elementById(TestIDs.SECOND_TAB_BAR_BTN).tap(); + await elementById(TestIDs.HIDE_TABS_PUSH_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeNotVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.BOTTOM_TABS)).toBeVisible(); + }); + + it('invoke bottomTabPressed event', async () => { + await elementById(TestIDs.THIRD_TAB_BAR_BTN).tap(); + await expect(elementByLabel('BottomTabPressed')).toBeVisible(); + await elementByLabel('OK').tap(); + await expect(elementByLabel('First Tab')).toBeVisible(); + }); + + it.e2e(':android: hardware back tab selection history', async () => { + await elementById(TestIDs.SECOND_TAB_BAR_BTN).tap(); + await elementById(TestIDs.FIRST_TAB_BAR_BUTTON).tap(); + await elementById(TestIDs.SECOND_TAB_BAR_BTN).tap(); + await elementById(TestIDs.SECOND_TAB_BAR_BTN).tap(); + await elementById(TestIDs.FIRST_TAB_BAR_BUTTON).tap(); + + await Android.pressBack(); + await expect(elementByLabel('Second Tab')).toBeVisible(); + + await Android.pressBack(); + await expect(elementByLabel('First Tab')).toBeVisible(); + + await Android.pressBack(); + await expect(elementByLabel('Second Tab')).toBeVisible(); + + await Android.pressBack(); + await expect(elementByLabel('First Tab')).toBeVisible(); + + await Android.pressBack(); + await expect(elementByLabel('First Tab')).toBeNotVisible(); + await expect(elementByLabel('Second Tab')).toBeNotVisible(); + }); + + it.e2e('Switch tab should send lifecycle events', async () => { + await elementById(TestIDs.SECOND_TAB_BAR_BTN).tap(); + await elementById(TestIDs.STATIC_EVENTS_OVERLAY_BTN).tap(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.FIRST_TAB_BAR_BUTTON).tap(); + await expect( + elementByLabel('componentWillAppear | FirstBottomTabsScreen | Component') + ).toBeVisible(); + await expect( + elementByLabel('componentDidDisappear | SecondBottomTabsScreen | Component') + ).toBeVisible(); + await expect( + elementByLabel('componentDidAppear | FirstBottomTabsScreen | Component') + ).toBeVisible(); + }); +}); diff --git a/e2e/Buttons.test.js b/e2e/Buttons.test.js new file mode 100644 index 00000000000..f3c4024b8d1 --- /dev/null +++ b/e2e/Buttons.test.js @@ -0,0 +1,109 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; + +const { + elementById, + elementByLabel, + elementTopBar, + expectImagesToBeEqual, +} = Utils; + +describe('Buttons', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.OPTIONS_TAB).tap(); + await elementById(TestIDs.GOTO_BUTTONS_SCREEN).tap(); + }); + + it.e2e('should render top/navigation-bar buttons in the right order', async () => { + const snapshottedImagePath = `./e2e/assets/buttons_navbar.${device.getPlatform()}.png`; + const actual = await elementTopBar().takeScreenshot('buttons_navbar'); + expectImagesToBeEqual(actual, snapshottedImagePath) + }); + + it(':android: should not effect left buttons when hiding back button', async () => { + await elementById(TestIDs.TOGGLE_BACK).tap(); + await expect(elementById(TestIDs.LEFT_BUTTON)).toBeVisible(); + await expect(elementById(TestIDs.TEXTUAL_LEFT_BUTTON)).toBeVisible(); + await expect(elementById(TestIDs.BACK_BUTTON)).toBeVisible(); + + await elementById(TestIDs.TOGGLE_BACK).tap(); + await expect(elementById(TestIDs.LEFT_BUTTON)).toBeVisible(); + await expect(elementById(TestIDs.TEXTUAL_LEFT_BUTTON)).toBeVisible(); + }); + it('sets right buttons', async () => { + await expect(elementById(TestIDs.BUTTON_ONE)).toBeVisible(); + await expect(elementById(TestIDs.ROUND_BUTTON)).toBeVisible(); + }); + + it('set left buttons', async () => { + await expect(elementById(TestIDs.LEFT_BUTTON)).toBeVisible(); + }); + + it('pass props to custom button component', async () => { + await expect(elementByLabel('Two')).toExist(); + }); + + it('pass props to custom button component should exist after push pop', async () => { + await expect(elementByLabel('Two')).toExist(); + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementByLabel('Two')).toExist(); + }); + + it('custom button is clickable', async () => { + await elementByLabel('Two').tap(); + await expect(elementByLabel('Times created: 1')).toExist(); + }); + + it('Resetting buttons should unmount button react view', async () => { + await elementById(TestIDs.SHOW_LIFECYCLE_BTN).tap(); + await elementById(TestIDs.RESET_BUTTONS).tap(); + await expect(elementByLabel('Button component unmounted')).toBeVisible(); + }); + + it('change button props without rendering all buttons', async () => { + await elementById(TestIDs.CHANGE_BUTTON_PROPS).tap(); + await expect(elementByLabel('Three')).toBeVisible(); + }); + + it('pop using back button', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.BACK_BUTTON).tap(); + await expect(elementByLabel('Buttons')).toBeVisible(); + }); + + it('resizes title component when a button is added with mergeOptions', async () => { + await elementById(TestIDs.RESET_BUTTONS).tap(); + await elementById(TestIDs.SET_RIGHT_BUTTONS).tap(); + await elementById(TestIDs.BUTTON_THREE).tap(); + }); + + it('Button component is not recreated if it has a predefined componentId', async () => { + await elementById(TestIDs.SET_RIGHT_BUTTONS).tap(); + await elementById(TestIDs.ROUND_BUTTON).tap(); + await expect(elementByLabel('Times created: 1')).toBeVisible(); + await elementById(TestIDs.OK_BUTTON).tap(); + + await elementById(TestIDs.SET_RIGHT_BUTTONS).tap(); + await elementById(TestIDs.ROUND_BUTTON).tap(); + await expect(elementByLabel('Times created: 1')).toBeVisible(); + await elementById(TestIDs.OK_BUTTON).tap(); + + await elementById(TestIDs.SET_RIGHT_BUTTONS).tap(); + await elementById(TestIDs.ROUND_BUTTON).tap(); + await expect(elementByLabel('Times created: 1')).toBeVisible(); + }); + + it('Accepts textual left button', async () => { + await expect(elementById(TestIDs.TEXTUAL_LEFT_BUTTON)).toBeVisible(); + }); + + it('Updates left button', async () => { + await elementById(TestIDs.ADD_COMPONENT_BUTTON).tap(); + await expect(elementById('leftButton0')).toBeVisible(); + + await elementById(TestIDs.ADD_COMPONENT_BUTTON).tap(); + await expect(elementById('leftButton1')).toBeVisible(); + }); +}); diff --git a/e2e/CustomTransition.js b/e2e/CustomTransition.js new file mode 100644 index 00000000000..f2fd4e81fde --- /dev/null +++ b/e2e/CustomTransition.js @@ -0,0 +1,20 @@ +import Utils from './Utils'; +import testIDs from '../playground/src/testIDs'; + +const { elementById } = Utils; + +describe(':ios: custom transition', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + }); + + test('sanity', async () => { + await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap(); + await elementById(testIDs.CUSTOM_TRANSITION_BUTTON).tap(); + await expect(element(by.id('shared_image1'))).toExist(); + await element(by.id('shared_image1')).tap(); + await expect(element(by.id('shared_image2'))).toExist(); + await element(by.id('shared_image2')).tap(); + await expect(element(by.id('shared_image1'))).toExist(); + }); +}); diff --git a/e2e/ExternalComponent.test.js b/e2e/ExternalComponent.test.js new file mode 100644 index 00000000000..6b658ba23d7 --- /dev/null +++ b/e2e/ExternalComponent.test.js @@ -0,0 +1,55 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; + +const { elementByLabel, elementById } = Utils; + +describe.e2e('External Component', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.NAVIGATION_TAB).tap(); + await elementById(TestIDs.EXTERNAL_COMP_BTN).tap(); + }); + + test('Push external component', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('This is an external component')).toBeVisible(); + }); + + test('Show external component in deep stack in modal', async () => { + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('External component in deep stack')).toBeVisible(); + }); + + test(':ios: Dismiss modal from external component should not crash', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('This is an external component')).toBeVisible(); + await elementById(TestIDs.EXTERNAL_DISMISS_MODAL_BTN).tap(); + await expect(elementById(TestIDs.NAVIGATION_SCREEN)).toBeVisible(); + }); + + test(':ios: Top bar buttons should be visible', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('This is an external component')).toBeVisible(); + await expect(elementById(TestIDs.EXTERNAL_TOP_BAR_RIGHT_BTN)).toBeVisible(); + }); + + test(':ios: Dismiss modal from external component should not crash when registered to modalDismissed event', async () => { + await elementById(TestIDs.REGISTER_MODAL_DISMISS_EVENT_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('This is an external component')).toBeVisible(); + await elementById(TestIDs.EXTERNAL_DISMISS_MODAL_BTN).tap(); + await expect(elementById(TestIDs.NAVIGATION_SCREEN)).toBeVisible(); + }); + + test(':ios: External component should receive options', async () => { + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('External Component')).toBeVisible(); + }); + + test(':ios: Push and pop native component', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_NATIVE_BTN).tap(); + await elementById(TestIDs.POP_NATIVE_BTN).tap(); + await expect(elementByLabel('This is an external component')).toBeVisible(); + }); +}); diff --git a/e2e/Keyboard.test.js b/e2e/Keyboard.test.js new file mode 100644 index 00000000000..f8ccd96a59c --- /dev/null +++ b/e2e/Keyboard.test.js @@ -0,0 +1,76 @@ +import { default as TestIDs, default as testIDs } from '../playground/src/testIDs'; +import { device } from 'detox'; +import Utils from './Utils'; +import kbdDriver from './drivers/androidKeyboard'; + +const { elementByLabel, elementById, sleep } = Utils; + +const KBD_OBSCURED_TEXT = 'Keyboard Demo'; + +describe.e2e('Keyboard', () => { + beforeAll(async () => { + await kbdDriver.init(); + await kbdDriver.enableOnScreenKeyboard(); + + if (device.getPlatform() === 'android') { + // 1st-time Android keyboard appearance is laggy (Android's lazy init?) + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.KEYBOARD_SCREEN_BTN).tap(); + await elementById(TestIDs.TEXT_INPUT1).tap(); + await sleep(2000); + } + }); + + afterAll(async () => { + await kbdDriver.restoreOnScreenKeyboard(); + }); + + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.KEYBOARD_SCREEN_BTN).tap(); + }); + + it('Push - should close keyboard when Back clicked', async () => { + await expect(elementByLabel(KBD_OBSCURED_TEXT)).toBeVisible(); + await elementById(TestIDs.TEXT_INPUT1).tap(); + await expect(elementByLabel(KBD_OBSCURED_TEXT)).not.toBeVisible(); + await elementById(TestIDs.BACK_BUTTON).tap(); + await expect(elementById(testIDs.MAIN_BOTTOM_TABS)).toBeVisible(); + }); + + it('Modal - should close keyboard when close clicked', async () => { + await elementById(TestIDs.MODAL_BTN).tap(); + await elementById(TestIDs.TEXT_INPUT1).tap(); + await expect(elementByLabel(KBD_OBSCURED_TEXT)).not.toBeVisible(); + await elementById(TestIDs.DISMISS_MODAL_TOPBAR_BTN).tap(); + await expect(elementById(testIDs.MAIN_BOTTOM_TABS)).toBeVisible(); + }); + + it('focus keyboard continue to resize content', async () => { + await elementById(TestIDs.TEXT_INPUT2).typeText("Hello"); + await elementById(TestIDs.TEXT_INPUT2).tapReturnKey(); + await expect(elementById(TestIDs.TEXT_INPUT1)).toBeFocused(); + await expect(elementById(TestIDs.TEXT_INPUT1)).toBeVisible(); + }); + + it('focus keyboard on push', async () => { + await elementById(TestIDs.PUSH_FOCUSED_KEYBOARD_SCREEN).tap(); + await expect(elementById(TestIDs.TEXT_INPUT1)).toBeFocused(); + }); + + it('focus keyboard on show modal', async () => { + await elementById(TestIDs.MODAL_FOCUSED_KEYBOARD_SCREEN).tap(); + await expect(elementById(TestIDs.TEXT_INPUT1)).toBeFocused(); + }); + + it('doesnt focus keyboard on show modal', async () => { + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementById(TestIDs.TEXT_INPUT1)).not.toBeFocused(); + }); + + it(':android: should respect UI with keyboard awareness', async () => { + await elementById(TestIDs.PUSH_KEYBOARD_SCREEN_STICKY_FOOTER).tap(); + await elementById(TestIDs.TEXT_INPUT2).tap(); + await expect(elementByLabel(KBD_OBSCURED_TEXT)).toBeVisible(); + }); +}); diff --git a/e2e/LazyRegsitration.test.js b/e2e/LazyRegsitration.test.js new file mode 100644 index 00000000000..7303c0d7409 --- /dev/null +++ b/e2e/LazyRegsitration.test.js @@ -0,0 +1,19 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; + +const { elementById } = Utils; + +describe.e2e('Lazy Registration', () => { + beforeEach(async () => { + await device.relaunchApp(); + await elementById(TestIDs.STACK_BTN).tap(); + }); + + it('push and pop lazily registered screen', async () => { + await elementById(TestIDs.PUSH_LAZY_BTN).tap(); + await expect(elementById(TestIDs.LAZILY_REGISTERED_SCREEN_HEADER)).toBeVisible(); + await expect(elementById(TestIDs.LAZY_TOP_PAR)).toBeVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.STACK_SCREEN_HEADER)).toBeVisible(); + }); +}); diff --git a/e2e/Modals.test.js b/e2e/Modals.test.js new file mode 100644 index 00000000000..7dc09978203 --- /dev/null +++ b/e2e/Modals.test.js @@ -0,0 +1,213 @@ +import TestIDs from '../playground/src/testIDs'; +import Android from './AndroidUtils'; +import Utils from './Utils'; + +const { elementByLabel, elementById, sleep } = Utils; + +describe('modal', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.NAVIGATION_TAB).tap(); + await elementById(TestIDs.MODAL_BTN).tap(); + }); + + it('show modal', async () => { + await expect(elementById(TestIDs.MODAL_SCREEN_HEADER)).toBeVisible(); + }); + + it('dismiss modal', async () => { + await expect(elementById(TestIDs.MODAL_SCREEN_HEADER)).toBeVisible(); + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it.e2e('unmount modal when dismissed', async () => { + await expect(elementById(TestIDs.MODAL_SCREEN_HEADER)).toBeVisible(); + await elementById(TestIDs.MODAL_LIFECYCLE_BTN).tap(); + await expect(elementByLabel('didAppear')).toBeVisible(); + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementByLabel('componentWillUnmount')).toBeVisible(); + await elementByLabel('OK').atIndex(0).tap(); + await expect(elementByLabel('didDisappear')).toBeVisible(); + await elementByLabel('OK').atIndex(0).tap(); + }); + + it('show multiple modals', async () => { + await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible(); + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 2')).toBeVisible(); + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible(); + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it.e2e('dismiss unknown screen id', async () => { + await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible(); + await elementById(TestIDs.DISMISS_UNKNOWN_MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible(); + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it('dismiss modal by id which is not the top most', async () => { + await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible(); + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 2')).toBeVisible(); + await elementById(TestIDs.DISMISS_PREVIOUS_MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 2')).toBeVisible(); + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it('dismiss all previous modals by id when they are below top presented modal', async () => { + await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible(); + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 2')).toBeVisible(); + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 3')).toBeVisible(); + + await elementById(TestIDs.DISMISS_ALL_PREVIOUS_MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 3')).toBeVisible(); + + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it('dismiss some modal by id deep in the stack', async () => { + await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible(); + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 2')).toBeVisible(); + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 3')).toBeVisible(); + + await elementById(TestIDs.DISMISS_FIRST_MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 3')).toBeVisible(); + + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 2')).toBeVisible(); + + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it('dismissAllModals', async () => { + await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible(); + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 2')).toBeVisible(); + await elementById(TestIDs.DISMISS_ALL_MODALS_BTN).tap(); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it('push into modal', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + }); + + it.e2e(':android: push into modal and dismiss pushed screen with hardware back', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await Android.pressBack(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + }); + + it('present modal multiple times', async () => { + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('Modal Stack Position: 1')).toBeVisible(); + }); + + it('setRoot dismisses modals', async () => { + await elementById(TestIDs.SET_ROOT).tap(); + await expect(elementById(TestIDs.MODAL_SCREEN_HEADER)).toBeNotVisible(); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + }); + + it.e2e(':android: override hardware back button in modal with stack', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.ADD_BACK_HANDLER).tap(); + + // Back is handled in Js + await Android.pressBack(); + await sleep(100); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + + // pop + await elementById(TestIDs.REMOVE_BACK_HANDLER).tap(); + await Android.pressBack(); + await sleep(100); + await expect(elementById(TestIDs.MODAL_SCREEN_HEADER)).toBeVisible(); + + // modal dismissed + await Android.pressBack(); + await sleep(100); + await expect(elementById(TestIDs.NAVIGATION_TAB)).toBeVisible(); + }); + + it.e2e('dismissModal promise is resolved with root ViewController id', async () => { + await elementById(TestIDs.MODAL_COMMANDS_BTN).tap(); + await elementById(TestIDs.MODAL_BTN).tap(); + + await expect(elementByLabel('showModal promise resolved with: UniqueStackId')).toBeVisible(); + await expect(elementByLabel('modalDismissed listener called with with: UniqueStackId')).toBeVisible(); + await expect(elementByLabel('dismissModal promise resolved with: UniqueStackId')).toBeVisible(); + }); + + it.e2e('should show declared modal', async () => { + await elementById(TestIDs.TOGGLE_REACT_DECLARED_MODAL).tap(); + await expect(elementById(TestIDs.DISMISS_REACT_MODAL_BTN)).toBeVisible(); + await elementById(TestIDs.DISMISS_REACT_MODAL_BTN).tap(); + await expect(elementById(TestIDs.MODAL_SCREEN_HEADER)).toBeVisible(); + }); + + it.e2e('should show and dismiss multiple modals including declared modal', async () => { + await elementById(TestIDs.TOGGLE_REACT_DECLARED_MODAL).tap(); + await elementById(TestIDs.SHOW_MODAL_FROM_DECLARED_BUTTON).tap(); + await expect(elementById(TestIDs.TOGGLE_REACT_DECLARED_MODAL)).toBeVisible(); + await elementById(TestIDs.TOGGLE_REACT_DECLARED_MODAL).tap(); + await elementById(TestIDs.DISMISS_REACT_MODAL_BTN).tap(); + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementById(TestIDs.DISMISS_REACT_MODAL_BTN)).toBeVisible(); + await elementById(TestIDs.DISMISS_REACT_MODAL_BTN).tap(); + + await expect(elementById(TestIDs.MODAL_SCREEN_HEADER)).toBeVisible(); + }); + + it.e2e('overlay should be on top of all modals', async () => { + await elementById(TestIDs.TOGGLE_REACT_DECLARED_MODAL).tap(); + await elementById(TestIDs.OVERLAY_BTN).tap(); + await expect(elementById(TestIDs.DISMISS_REACT_MODAL_BTN)).toBeVisible(); + await expect(elementById(TestIDs.DISMISS_ALL_OVERLAYS_BUTTON)).toBeVisible(); + + await elementById(TestIDs.SHOW_MODAL_FROM_DECLARED_BUTTON).tap(); + await expect(elementById(TestIDs.MODAL_LIFECYCLE_BTN)).toBeVisible(); + + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await elementById(TestIDs.DISMISS_REACT_MODAL_BTN).tap(); + + await elementById(TestIDs.DISMISS_ALL_OVERLAYS_BUTTON).tap(); + }); + + it.e2e(':android: should handle back properly', async () => { + await elementById(TestIDs.TOGGLE_REACT_DECLARED_MODAL).tap(); + await elementById(TestIDs.SHOW_MODAL_FROM_DECLARED_BUTTON).tap(); + await expect(elementById(TestIDs.TOGGLE_REACT_DECLARED_MODAL)).toBeVisible(); + + await Android.pressBack(); + + await expect(elementById(TestIDs.DISMISS_REACT_MODAL_BTN)).toBeVisible(); + + await Android.pressBack(); + + await expect(elementById(TestIDs.TOGGLE_REACT_DECLARED_MODAL)).toBeVisible(); + }); + + it.e2e('dismiss modal with side menu', async () => { + await elementById(TestIDs.MODAL_COMMANDS_BTN).tap(); + await elementById(TestIDs.SHOW_SIDE_MENU_MODAL).tap(); + await expect(elementByLabel('System UI Options')).toBeVisible(); + await elementById(TestIDs.DISMISS_MODAL_TOPBAR_BTN).tap(); + await expect(elementByLabel('System UI Options')).not.toBeVisible(); + await expect(elementByLabel('Modal Commands')).toBeVisible(); + }); +}); diff --git a/e2e/Options.test.js b/e2e/Options.test.js new file mode 100644 index 00000000000..59e7f713bba --- /dev/null +++ b/e2e/Options.test.js @@ -0,0 +1,95 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; + +const { elementById, elementByLabel } = Utils; + +describe('Options', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.OPTIONS_TAB).tap(); + }); + + it('declare options on a component', async () => { + await expect(elementByLabel('Styling Options')).toBeVisible(); + }); + + it('change title on component component', async () => { + await expect(elementByLabel('Styling Options')).toBeVisible(); + await elementById(TestIDs.CHANGE_TITLE_BTN).tap(); + await expect(elementByLabel('Title Changed')).toBeVisible(); + }); + + it('hides TopBar when pressing on Hide TopBar and shows it when pressing on Show TopBar', async () => { + await elementById(TestIDs.HIDE_TOP_BAR_BTN).tap(); + await expect(elementById(TestIDs.TOP_BAR)).toBeNotVisible(); + await elementById(TestIDs.SHOW_TOP_BAR_BTN).tap(); + await expect(elementById(TestIDs.TOP_BAR)).toBeVisible(); + }); + + it('default options should apply to all screens in stack', async () => { + await elementById(TestIDs.HIDE_TOPBAR_DEFAULT_OPTIONS).tap(); + await expect(elementById(TestIDs.TOP_BAR)).toBeVisible(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeNotVisible(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeNotVisible(); + }); + + it('default options should not override static options', async () => { + await elementById(TestIDs.HIDE_TOPBAR_DEFAULT_OPTIONS).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.TOP_BAR)).toBeVisible(); + await expect(elementByLabel('Styling Options')).toBeVisible(); + }); + + it('set title component', async () => { + await elementById(TestIDs.SET_REACT_TITLE_VIEW).tap(); + await expect(elementByLabel('Press Me')).toBeVisible(); + }); + + it('set title after setting react component', async () => { + await elementById(TestIDs.SET_REACT_TITLE_VIEW).tap(); + await expect(elementByLabel('Press Me')).toBeVisible(); + await elementById(TestIDs.CHANGE_TITLE_BTN).tap(); + await expect(elementByLabel('Title Changed')).toBeVisible(); + }); + + it('Popping screen with yellow box should not crash', async () => { + await elementById(TestIDs.SHOW_YELLOW_BOX_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementByLabel('Styling Options')).toBeVisible(); + }); + + it('Merging options to invisible component in stack should not affect current component', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.HIDE_PREVIOUS_SCREEN_TOP_BAR).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + }); + + it('Merging options to invisible component should affect the invisible component', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.HIDE_PREVIOUS_SCREEN_TOP_BAR).tap(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementByLabel('Styling Options')).toBeNotVisible(); + }); + + it(':ios: Replace tab testID', async () => { + await expect(elementById(TestIDs.OPTIONS_TAB)).toBeVisible(); + await elementById(TestIDs.REPLACE_TAB_TEST_ID).tap(); + await expect(elementById(TestIDs.OPTIONS_TAB)).toBeNotVisible(); + await expect(elementById(TestIDs.REPLACED_TAB)).toBeVisible(); + }); + + xit('hides topBar onScroll down and shows it on scroll up', async () => { + await elementById(TestIDs.PUSH_OPTIONS_BUTTON).tap(); + await elementById(TestIDs.SCROLLVIEW_SCREEN_BUTTON).tap(); + await elementById(TestIDs.TOGGLE_TOP_BAR_HIDE_ON_SCROLL).tap(); + await expect(elementById(TestIDs.TOP_BAR)).toBeVisible(); + await element(by.id(TestIDs.SCROLLVIEW_ELEMENT)).swipe('up', 'slow'); + await expect(elementById(TestIDs.TOP_BAR)).toBeNotVisible(); + await element(by.id(TestIDs.SCROLLVIEW_ELEMENT)).swipe('down', 'fast'); + await expect(elementById(TestIDs.TOP_BAR)).toBeVisible(); + }); +}); diff --git a/e2e/Orientation.test.js b/e2e/Orientation.test.js new file mode 100644 index 00000000000..d45449477a6 --- /dev/null +++ b/e2e/Orientation.test.js @@ -0,0 +1,45 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; + +const { elementById } = Utils; + +describe.e2e(':ios: orientation', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + waitForDeviceToSettleAfterOrientationChangeAndroid = (ms) => + new Promise((res) => setTimeout(res, device.getPlatform() === 'ios' ? 0 : 400)); + await elementById(TestIDs.NAVIGATION_TAB).tap(); + await elementById(TestIDs.SHOW_ORIENTATION_SCREEN).tap(); + }); + + it('landscape and portrait array', async () => { + await elementById(TestIDs.LANDSCAPE_PORTRAIT_ORIENTATION_BTN).tap(); + await expect(element(by.id(TestIDs.PORTRAIT_ELEMENT))).toBeVisible(); + await device.setOrientation('landscape'); + waitForDeviceToSettleAfterOrientationChangeAndroid(); + await expect(element(by.id(TestIDs.LANDSCAPE_ELEMENT))).toBeVisible(); + await device.setOrientation('portrait'); + waitForDeviceToSettleAfterOrientationChangeAndroid(); + await expect(element(by.id(TestIDs.PORTRAIT_ELEMENT))).toBeVisible(); + await elementById(TestIDs.DISMISS_BTN).tap(); + }); + + it(':ios: portrait only', async () => { + await elementById(TestIDs.PORTRAIT_ORIENTATION_BTN).tap(); + await expect(elementById(TestIDs.PORTRAIT_ELEMENT)).toBeVisible(); + await device.setOrientation('landscape'); + await expect(elementById(TestIDs.PORTRAIT_ELEMENT)).toBeVisible(); + await device.setOrientation('portrait'); + await expect(elementById(TestIDs.PORTRAIT_ELEMENT)).toBeVisible(); + await elementById(TestIDs.DISMISS_BTN).tap(); + }); + + it(':ios: landscape only', async () => { + await elementById(TestIDs.LANDSCAPE_ORIENTATION_BTN).tap(); + await device.setOrientation('landscape'); + await expect(element(by.id(TestIDs.LANDSCAPE_ELEMENT))).toBeVisible(); + await device.setOrientation('portrait'); + await expect(element(by.id(TestIDs.LANDSCAPE_ELEMENT))).toBeVisible(); + await elementById(TestIDs.DISMISS_BTN).tap(); + }); +}); diff --git a/e2e/Overlay.test.js b/e2e/Overlay.test.js new file mode 100644 index 00000000000..029af0bc777 --- /dev/null +++ b/e2e/Overlay.test.js @@ -0,0 +1,100 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; +import Android from './AndroidUtils'; + +const { elementByLabel, elementById, expectImagesToBeEqual,expectImagesToBeNotEqual } = Utils; + +describe('Overlay', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.NAVIGATION_TAB).tap(); + await elementById(TestIDs.OVERLAY_BTN).tap(); + }); + + it('show and dismiss overlay', async () => { + await elementById(TestIDs.SHOW_OVERLAY_BTN).tap(); + await expect(elementById(TestIDs.OVERLAY_ALERT_HEADER)).toBeVisible(); + await elementById(TestIDs.DISMISS_BTN).tap(); + await expect(elementById(TestIDs.OVERLAY_ALERT_HEADER)).toBeNotVisible(); + }); + + it('overlay pass touches - true', async () => { + await elementById(TestIDs.SHOW_TOUCH_THROUGH_OVERLAY_BTN).tap(); + await expect(elementById(TestIDs.SHOW_OVERLAY_BTN)).toBeVisible(); + await elementById(TestIDs.ALERT_BUTTON).tap(); + await expect(elementByLabel('Alert displayed')).toBeVisible(); + }); + + it.e2e('overlay should redraw after orientation change', async () => { + await elementById(TestIDs.SHOW_OVERLAY_BTN).tap(); + await device.setOrientation('landscape'); + await expect(elementById(TestIDs.OVERLAY_ALERT_HEADER)).toBeVisible(); + }); + + it('setRoot should not remove overlay', async () => { + await elementById(TestIDs.SHOW_TOUCH_THROUGH_OVERLAY_BTN).tap(); + await elementById(TestIDs.SET_ROOT_BTN).tap(); + await expect(elementById(TestIDs.OVERLAY_ALERT_HEADER)).toBeVisible(); + }); + + it('nested touchables work as expected', async () => { + await elementById(TestIDs.TOAST_BTN).tap(); + await elementById(TestIDs.TOAST_OK_BTN_INNER).tap(); + await expect(elementByLabel('Inner button clicked')).toBeVisible(); + await elementById(TestIDs.OK_BUTTON).tap(); + + await elementById(TestIDs.TOAST_BTN).tap(); + await elementById(TestIDs.TOAST_OK_BTN_OUTER).tap(); + await expect(elementByLabel('Outer button clicked')).toBeVisible(); + }); + + xtest('overlay pass touches - false', async () => { + await elementById(TestIDs.SHOW_OVERLAY_BUTTON).tap(); + await expect(elementById(TestIDs.SHOW_OVERLAY_BUTTON)).toBeVisible(); + await expect(elementById(TestIDs.TOP_BAR_ELEMENT)).toBeVisible(); + await elementById(TestIDs.HIDE_TOP_BAR_BUTTON).tap(); + await expect(elementById(TestIDs.TOP_BAR_ELEMENT)).toBeVisible(); + }); + + it.e2e(':android: should show banner overlay and not block the screen', async () => { + const snapshottedImagePath = './e2e/assets/overlay_banner_padding.png'; + Android.setDemoMode(); + let expected = await device.takeScreenshot('without_banner'); + await elementById(TestIDs.SHOW_BANNER_OVERLAY).tap(); + await expect(elementById(TestIDs.BANNER_OVERLAY)).toBeVisible(); + const actual = await device.takeScreenshot('with_banner'); + expectImagesToBeNotEqual(expected, actual) + await elementById(TestIDs.SET_LAYOUT_BOTTOM_INSETS).tap(); + expected = await device.takeScreenshot('with_banner'); + expectImagesToBeEqual(expected, snapshottedImagePath) + }); + + it.e2e(':ios: should show banner overlay and not block the screen', async () => { + await elementById(TestIDs.SHOW_BANNER_OVERLAY).tap(); + await expect(elementById(TestIDs.BANNER_OVERLAY)).toBeVisible(); + await expect(elementById(TestIDs.FOOTER_TEXT)).toBeNotVisible(); + await elementById(TestIDs.SET_LAYOUT_BOTTOM_INSETS).tap(); + await expect(elementById(TestIDs.FOOTER_TEXT)).toBeVisible(); + }); +}); + +describe('Overlay Dismiss all', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.NAVIGATION_TAB).tap(); + await elementById(TestIDs.OVERLAY_BTN).tap(); + }); + + xit('dismissAllOverlays should dismiss all opened overlays', async () => { + await elementById(TestIDs.SHOW_FULLSCREEN_OVERLAY_BTN).tap(); + await elementById(TestIDs.SHOW_OVERLAY_BTN).tap(); + await elementById(TestIDs.DISMISS_ALL_OVERLAYS_BUTTON).tap(); + await expect(elementById(TestIDs.OVERLAY_DISMISSED_COUNT)).toHaveText('2'); + }); + + it.e2e('dismissAllOverlays should be able to dismiss only one overlay', async () => { + await elementById(TestIDs.SHOW_OVERLAY_BTN).tap(); + await elementById(TestIDs.DISMISS_ALL_OVERLAYS_BUTTON).tap(); + await expect(elementById(TestIDs.OVERLAY_DISMISSED_COUNT)).toHaveText('1'); + }); +}); diff --git a/e2e/SearchBar.test.js b/e2e/SearchBar.test.js new file mode 100644 index 00000000000..14f83230e0b --- /dev/null +++ b/e2e/SearchBar.test.js @@ -0,0 +1,41 @@ +import TestIDs from '../playground/src/testIDs'; +import Utils from './Utils'; + +const { elementById, elementByTraits } = Utils; + +describe.e2e(':ios: SearchBar', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.OPTIONS_TAB).tap(); + await elementById(TestIDs.GOTO_SEARCHBAR_SCREEN).tap(); + }); + + it('show and hide search bar', async () => { + await elementById(TestIDs.SHOW_SEARCH_BAR_BTN).tap(); + await expect(elementByTraits(['searchField'])).toBeVisible(); + await elementById(TestIDs.HIDE_SEARCH_BAR_BTN).tap(); + await expect(elementByTraits(['searchField'])).toBeNotVisible(); + }); +}); + +describe.e2e(':ios: SearchBar Modal', () => { + beforeAll(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.OPTIONS_TAB).tap(); + await elementById(TestIDs.GOTO_SEARCHBAR_MODAL).tap(); + }); + + it('show and hide search bar', async () => { + await elementById(TestIDs.SHOW_SEARCH_BAR_BTN).tap(); + await expect(elementByTraits(['searchField'])).toBeVisible(); + await elementById(TestIDs.HIDE_SEARCH_BAR_BTN).tap(); + await expect(elementByTraits(['searchField'])).toBeNotVisible(); + }); + + it('searching then exiting works', async () => { + await elementById(TestIDs.SHOW_SEARCH_BAR_BTN).tap(); + await elementByTraits(['searchField']).replaceText('foo'); + await elementById(TestIDs.DISMISS_MODAL_TOPBAR_BTN).tap(); + await expect(elementById(TestIDs.OPTIONS_TAB)).toBeVisible(); + }); +}); diff --git a/e2e/SetRoot.test.js b/e2e/SetRoot.test.js new file mode 100644 index 00000000000..8bbc5edc7d9 --- /dev/null +++ b/e2e/SetRoot.test.js @@ -0,0 +1,64 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; + +const { elementById, elementByLabel } = Utils; + +describe('SetRoot', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.NAVIGATION_TAB).tap(); + await elementById(TestIDs.SET_ROOT_BTN).tap(); + }); + + it('set root multiple times with the same componentId', async () => { + await elementById(TestIDs.SET_MULTIPLE_ROOTS_BTN).tap(); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + }); + + it('set root hides bottomTabs', async () => { + await elementById(TestIDs.SET_ROOT_HIDES_BOTTOM_TABS_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeNotVisible(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeVisible(); + }); + + it('set root with deep stack hides bottomTabs', async () => { + await elementById(TestIDs.SET_ROOT_WITH_STACK_HIDES_BOTTOM_TABS_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeNotVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeVisible(); + }); + + it('set root without stack hides bottomTabs', async () => { + await elementById(TestIDs.SET_ROOT_WITHOUT_STACK_HIDES_BOTTOM_TABS_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeNotVisible(); + }); + + it(':ios: set root with two children and second tab selected hides bottomTabs', async () => { + await elementById(TestIDs.SET_ROOT_WITH_TWO_CHILDREN_HIDES_BOTTOM_TABS_BTN).tap(); + await expect(elementById(TestIDs.LAYOUTS_TAB)).toBeNotVisible(); + }); + + it('set root should not override props for component with identical id', async () => { + await expect(elementByLabel('Two')).toBeVisible(); + await elementById(TestIDs.ROUND_BUTTON).tap(); + await expect(elementByLabel('Times created: 1')).toBeVisible(); + await elementById(TestIDs.OK_BUTTON).tap(); + await elementById(TestIDs.SET_ROOT_WITH_BUTTONS).tap(); + await expect(elementByLabel('Two')).toBeVisible(); + await elementById(TestIDs.ROUND_BUTTON).tap(); + await expect(elementByLabel('Times created: 1')).toBeVisible(); + await elementById(TestIDs.OK_BUTTON).tap(); + }); +}); + +it.e2e(':ios: set root with left and right side menus - menu visibility', async () => { + await elementById(TestIDs.SET_ROOT_WITH_MENUS).tap(); + await elementById(TestIDs.TOGGLE_SIDE_MENU_OPEN_MODE_BTN).tap(); + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + await elementById(TestIDs.CLOSE_LEFT_SIDE_MENU_BTN).tap(); + await expect(elementById(TestIDs.CLOSE_LEFT_SIDE_MENU_BTN)).toBeNotVisible(); + await elementById(TestIDs.OPEN_RIGHT_SIDE_MENU_BTN).tap(); + await elementById(TestIDs.CLOSE_RIGHT_SIDE_MENU_BTN).tap(); + await expect(elementById(TestIDs.CLOSE_RIGHT_SIDE_MENU_BTN)).toBeNotVisible(); +}); diff --git a/e2e/SideMenu.test.js b/e2e/SideMenu.test.js new file mode 100644 index 00000000000..e1da0d26feb --- /dev/null +++ b/e2e/SideMenu.test.js @@ -0,0 +1,107 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; + +const {elementByLabel, elementById, expectImagesToBeEqual} = Utils; + +describe('SideMenu', () => { + beforeEach(async () => { + await device.launchApp({newInstance : true}); + await elementById(TestIDs.SIDE_MENU_BTN).tap(); + }); + + describe.each(['aboveContent', 'pushContent'])('Open mode %s', (openMode) => { + beforeEach(async () => { + if (openMode === 'pushContent') { + await elementById(TestIDs.TOGGLE_SIDE_MENU_OPEN_MODE_BTN).tap(); + } + }); + + it('close SideMenu and push to stack with static id', async () => { + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + await elementById(TestIDs.LEFT_SIDE_MENU_PUSH_BTN).tap(); + await elementById(TestIDs.CLOSE_LEFT_SIDE_MENU_BTN).tap(); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.CENTER_SCREEN_HEADER)).toBeVisible(); + }); + + it('Push to stack with static id and close SideMenu with screen options', async () => { + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + await elementById(TestIDs.LEFT_SIDE_MENU_PUSH_AND_CLOSE_BTN).tap(); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.CENTER_SCREEN_HEADER)).toBeVisible(); + }); + + it('side menu visibility - left', async () => { + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + await elementById(TestIDs.CLOSE_LEFT_SIDE_MENU_BTN).tap(); + await expect(elementById(TestIDs.CLOSE_LEFT_SIDE_MENU_BTN)).toBeNotVisible(); + }); + + it('side menu visibility - right', async () => { + await elementById(TestIDs.OPEN_RIGHT_SIDE_MENU_BTN).tap(); + await elementById(TestIDs.CLOSE_RIGHT_SIDE_MENU_BTN).tap(); + await expect(elementById(TestIDs.CLOSE_RIGHT_SIDE_MENU_BTN)).toBeNotVisible(); + }); + + it.e2e('should rotate', async () => { + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + await device.setOrientation('landscape'); + await expect(elementById(TestIDs.LEFT_SIDE_MENU_PUSH_BTN)).toBeVisible(); + }); + + it.e2e(':ios: rotation should update drawer height', async () => { + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + await expect(elementByLabel('left drawer height: 869')).toBeVisible(); + await device.setOrientation('landscape'); + await expect(elementByLabel('left drawer height: 428')).toBeVisible(); + await device.setOrientation('portrait'); + await expect(elementByLabel('left drawer height: 869')).toBeVisible(); + }); + + it.e2e('should set left drawer width', async () => { + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + await expect(elementById(TestIDs.SIDE_MENU_LEFT_DRAWER_HEIGHT_TEXT)).toBeVisible(); + await expect(elementByLabel('left drawer width: 250')).toBeVisible(); + }); + + it.e2e('should change left drawer width', async () => { + await elementById(TestIDs.CHANGE_LEFT_SIDE_MENU_WIDTH_BTN).tap(); + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + await expect(elementByLabel('left drawer width: 100')).toBeVisible(); + }); + + it.e2e('should set right drawer width', async () => { + await elementById(TestIDs.OPEN_RIGHT_SIDE_MENU_BTN).tap(); + await expect(elementByLabel('right drawer width: 250')).toBeVisible(); + }); + + it.e2e('should change right drawer width', async () => { + await elementById(TestIDs.CHANGE_RIGHT_SIDE_MENU_WIDTH_BTN).tap(); + await elementById(TestIDs.OPEN_RIGHT_SIDE_MENU_BTN).tap(); + await expect(elementByLabel('right drawer width: 50')).toBeVisible(); + }); + + it.e2e(':ios: should render side menu correctly', async () => { + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + const snapshottedImagePath = `./e2e/assets/side_menu.${openMode}.png`; + const actual = + await elementById('SideMenuContainer').takeScreenshot(`side_menu_${openMode}`); + expectImagesToBeEqual(actual, snapshottedImagePath); + }); + }); + + it.e2e(':ios: should open above-content by default', async () => { + await elementById(TestIDs.TOGGLE_SIDE_MENU_OPEN_MODE_BTN).tap(); // aboveContent --> pushContent + await elementById(TestIDs.TOGGLE_SIDE_MENU_OPEN_MODE_BTN).tap(); // pushContent --> undefined + await expect(elementByLabel('Open mode: undefined')).toBeVisible(); + + await elementById(TestIDs.OPEN_LEFT_SIDE_MENU_BTN).tap(); + + const snapshottedImagePath = `./e2e/assets/side_menu.undefined.png`; + const actual = + await elementById('SideMenuContainer').takeScreenshot(`side_menu_undefined`); + expectImagesToBeEqual(actual, snapshottedImagePath); + }); +}); diff --git a/e2e/SplitView.test.js b/e2e/SplitView.test.js new file mode 100644 index 00000000000..abd354979f2 --- /dev/null +++ b/e2e/SplitView.test.js @@ -0,0 +1,28 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; + +const cocktailsList = require('../playground/src/assets/cocktails').default; +const { elementByLabel, elementById } = Utils; + +describe.e2e(':ios: SplitView', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.SPLIT_VIEW_BUTTON).tap(); + }); + + it('master screen updates details screen', async () => { + const secondCocktail = cocktailsList[1]; + await elementById(secondCocktail.id).tap(); + await expect(elementByLabel(secondCocktail.description)).toBeVisible(); + }); + + it('push screen to master screen', async () => { + await elementById(TestIDs.PUSH_MASTER_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + }); + + it('push screen to detail screen', async () => { + await elementById(TestIDs.PUSH_DETAILS_BTN).tap(); + await expect(elementByLabel('Pushed Screen')).toBeVisible(); + }); +}); diff --git a/e2e/Stack.test.js b/e2e/Stack.test.js new file mode 100644 index 00000000000..e7c371b1b05 --- /dev/null +++ b/e2e/Stack.test.js @@ -0,0 +1,190 @@ +import jestExpect from 'expect'; +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; +import Android from './AndroidUtils'; + +const { elementByLabel, elementById, sleep } = Utils; + +const driver = { + root: { + navToTitleAndSubtitle: async () => { + await elementById(TestIDs.PUSH_TITLE_WITH_SUBTITLE).tap(); + return driver.titleWithSubtitle; + }, + }, + + titleWithSubtitle: { + titleId: `${TestIDs.TOPBAR_ID}.title`, + subtitleId: `${TestIDs.TOPBAR_ID}.subtitle`, + title: () => elementById(driver.titleWithSubtitle.titleId), + titleByLabel: () => elementByLabel('Title'), + subtitle: () => elementById(driver.titleWithSubtitle.subtitleId), + subtitleByLabel: () => elementByLabel('Subtitle'), + }, +}; + +describe('Stack', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.STACK_BTN).tap(); + }); + + it.e2e('SetStackRoot on a non created tab should work', async () => { + await elementById(TestIDs.SET_ROOT_NAVIGATION_TAB).tap(); + await elementById(TestIDs.DISMISS_MODAL_TOPBAR_BTN).tap(); + await elementById(TestIDs.NAVIGATION_TAB).tap(); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + await elementById(TestIDs.BACK_BUTTON).tap(); + await expect(elementById(TestIDs.NAVIGATION_SCREEN)).toBeVisible(); + }); + + it('push and pop screen', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.STACK_SCREEN_HEADER)).toBeVisible(); + }); + + it('push and pop screen without animation', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_NO_ANIM_BTN).tap(); + await expect(elementByLabel('Stack Position: 2')).toBeVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementByLabel('Stack Position: 1')).toBeVisible(); + }); + + it('pop using stack id', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + await elementById(TestIDs.POP_USING_STACK_ID_BTN).tap(); + await expect(elementById(TestIDs.STACK_SCREEN_HEADER)).toBeVisible(); + }); + + it('pop using previous screen id', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Stack Position: 2')).toBeVisible(); + await elementById(TestIDs.POP_USING_PREVIOUS_SCREEN_ID_BTN).tap(); + await expect(elementByLabel('Stack Position: 1')).toBeVisible(); + }); + + it('pop to specific id', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Stack Position: 3')).toBeVisible(); + await elementById(TestIDs.POP_TO_FIRST_SCREEN_BTN).tap(); + await expect(elementByLabel('Stack Position: 1')).toBeVisible(); + }); + + it('pop to root', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.POP_TO_ROOT_BTN).tap(); + await expect(elementById(TestIDs.STACK_SCREEN_HEADER)).toBeVisible(); + }); + + it.e2e('pop component should not detach component if can`t pop', async () => { + await elementById(TestIDs.POP_NONE_EXISTENT_SCREEN_BTN).tap(); + await expect(elementById(TestIDs.STACK_SCREEN_HEADER)).toBeVisible(); + }); + + it(':android: custom back button', async () => { + await elementById(TestIDs.PUSH_CUSTOM_BACK_BTN).tap(); + await elementById(TestIDs.CUSTOM_BACK_BTN).tap(); + await expect(elementByLabel('back button clicked')).toBeVisible(); + }); + + it('push title with subtitle', async () => { + const innerDriver = await driver.root.navToTitleAndSubtitle(); + await expect(innerDriver.titleByLabel()).toBeVisible(); + await expect(innerDriver.subtitleByLabel()).toBeVisible(); + }); + + it('push title & subtitle with derived test IDs', async () => { + const innerDriver = await driver.root.navToTitleAndSubtitle(); + await expect(innerDriver.title()).toBeVisible(); + await expect(innerDriver.subtitle()).toBeVisible(); + }); + + it.e2e('push title & subtitle with derived test IDs (strict e2e)', async () => { + const innerDriver = await driver.root.navToTitleAndSubtitle(); + + const titleAttr = await innerDriver.titleByLabel().getAttributes(); + jestExpect(titleAttr.identifier).toEqual(innerDriver.titleId); + + const subtitleAttr = await innerDriver.subtitleByLabel().getAttributes(); + jestExpect(subtitleAttr.identifier).toEqual(innerDriver.subtitleId); + }); + + it.e2e('screen lifecycle', async () => { + await elementById(TestIDs.PUSH_LIFECYCLE_BTN).tap(); + await expect(elementByLabel('didAppear')).toBeVisible(); + await elementById(TestIDs.PUSH_TO_TEST_DID_DISAPPEAR_BTN).tap(); + await expect(elementByLabel('didDisappear')).toBeVisible(); + }); + + it.e2e('Screen popped event', async () => { + await elementById(TestIDs.PUSH_LIFECYCLE_BTN).tap(); + await elementById(TestIDs.SCREEN_POPPED_BTN).tap(); + await expect(elementByLabel('Screen popped event')).toBeVisible(); + }); + + it.e2e('unmount is called on pop', async () => { + await elementById(TestIDs.PUSH_LIFECYCLE_BTN).tap(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementByLabel('componentWillUnmount')).toBeVisible(); + await elementByLabel('OK').atIndex(0).tap(); + await expect(elementByLabel('didDisappear')).toBeVisible(); + }); + + it.e2e(':android: override hardware back button', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.ADD_BACK_HANDLER).tap(); + await Android.pressBack(); + await sleep(100); + await expect(elementById(TestIDs.PUSHED_SCREEN_HEADER)).toBeVisible(); + + await elementById(TestIDs.REMOVE_BACK_HANDLER).tap(); + await Android.pressBack(); + await sleep(100); + await expect(elementById(TestIDs.STACK_SCREEN_HEADER)).toBeVisible(); + }); + + it('does not crash when setting the stack root to an existing component id', async () => { + await elementById(TestIDs.SET_STACK_ROOT_WITH_ID_BTN).tap(); + await elementById(TestIDs.SET_STACK_ROOT_WITH_ID_BTN).tap(); + }); + + it.e2e(':ios: set stack root component should be first in stack', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('Stack Position: 1')).toBeVisible(); + await elementById(TestIDs.SET_STACK_ROOT_BUTTON).tap(); + await expect(elementByLabel('Stack Position: 2')).toBeVisible(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementByLabel('Stack Position: 2')).toBeVisible(); + }); + + xit(':ios: set searchBar and handle onSearchUpdated event', async () => { + // Broken on iOS 13 + await elementById(TestIDs.SEARCH_BTN).tap(); + await expect(elementByLabel('Start Typing')).toBeVisible(); + await elementByLabel('Start Typing').tap(); + const query = '124'; + await elementByLabel('Start Typing').typeText(query); + await expect(elementById(TestIDs.SEARCH_RESULT_ITEM)).toHaveText(`Item ${query}`); + }); + + it.e2e('push promise is resolved with pushed ViewController id', async () => { + await elementById(TestIDs.STACK_COMMANDS_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('push promise resolved with: ChildId')).toBeVisible(); + await expect(elementByLabel('pop promise resolved with: ChildId')).toBeVisible(); + }); + + it('pop from root screen should do nothing', async () => { + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementById(TestIDs.STACK_SCREEN_HEADER)).toBeVisible(); + }); +}); diff --git a/e2e/StaticLifecycleEvents.test.js b/e2e/StaticLifecycleEvents.test.js new file mode 100644 index 00000000000..2440d91281e --- /dev/null +++ b/e2e/StaticLifecycleEvents.test.js @@ -0,0 +1,112 @@ +import Utils from './Utils'; +import TestIDs from '../playground/src/testIDs'; + +const { elementByLabel, elementById } = Utils; + +describe('static lifecycle events', () => { + beforeEach(async () => { + await device.launchApp({ newInstance: true }); + await elementById(TestIDs.NAVIGATION_TAB).tap(); + await elementById(TestIDs.SHOW_STATIC_EVENTS_SCREEN).tap(); + await elementById(TestIDs.STATIC_EVENTS_OVERLAY_BTN).tap(); + await expect(elementByLabel('Static Lifecycle Events Overlay')).toBeVisible(); + await expect(elementByLabel('componentWillAppear | EventsOverlay | Component')).toBeVisible(); + await expect(elementByLabel('componentDidAppear | EventsOverlay | Component')).toBeVisible(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + }); + + it('willAppear didAppear didDisappear', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('componentWillAppear | Pushed | Component')).toBeVisible(); + await expect(elementByLabel('componentDidAppear | Pushed | Component')).toBeVisible(); + await expect(elementByLabel('componentDidDisappear | EventsScreen | Component')).toBeVisible(); + }); + + it('pushing and popping screen dispatch static event', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await expect(elementByLabel('command started: push')).toBeVisible(); + await expect(elementByLabel('command completed: push')).toBeVisible(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.POP_BTN).tap(); + await expect(elementByLabel('command started: pop')).toBeVisible(); + await expect(elementByLabel('command completed: pop')).toBeVisible(); + }); + + it('showModal and dismissModal dispatch static event', async () => { + await elementById(TestIDs.MODAL_BTN).tap(); + await expect(elementByLabel('command started: showModal')).toBeVisible(); + await expect(elementByLabel('command completed: showModal')).toBeVisible(); + await expect(elementByLabel('componentWillAppear | Modal | Component')).toBeVisible(); + await expect(elementByLabel('componentDidAppear | Modal | Component')).toBeVisible(); + await expect(elementByLabel('componentDidDisappear | EventsScreen | Component')).toBeVisible(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.DISMISS_MODAL_BTN).tap(); + await expect(elementByLabel('command started: dismissModal')).toBeVisible(); + await expect(elementByLabel('command completed: dismissModal')).toBeVisible(); + await expect(elementByLabel('componentWillAppear | EventsScreen | Component')).toBeVisible(); + await expect(elementByLabel('componentDidAppear | EventsScreen | Component')).toBeVisible(); + await expect(elementByLabel('componentDidDisappear | Modal | Component')).toBeVisible(); + }); + + it('unmounts when dismissed', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.DISMISS_BTN).tap(); + await expect(elementByLabel('Overlay Unmounted')).toBeVisible(); + await elementByLabel('OK').tap(); + }); + + it('top bar buttons willAppear didAppear didDisappear', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_OPTIONS_BUTTON).tap(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.GOTO_BUTTONS_SCREEN).tap(); + await expect( + elementByLabel('componentWillAppear | CustomRoundedButton | TopBarButton') + ).toBeVisible(); + await expect( + elementByLabel('componentDidAppear | CustomRoundedButton | TopBarButton') + ).toBeVisible(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.RESET_BUTTONS).tap(); + await expect( + elementByLabel('componentDidDisappear | CustomRoundedButton | TopBarButton') + ).toBeVisible(); + }); + + it('top bar title willAppear didAppear didDisappear', async () => { + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.PUSH_OPTIONS_BUTTON).tap(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.SET_REACT_TITLE_VIEW).tap(); + await expect( + elementByLabel('componentWillAppear | ReactTitleView | TopBarTitle') + ).toBeVisible(); + await expect(elementByLabel('componentDidAppear | ReactTitleView | TopBarTitle')).toBeVisible(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await expect( + elementByLabel('componentDidDisappear | ReactTitleView | TopBarTitle') + ).toBeVisible(); + }); + + it.e2e('unmounts previous root before resolving setRoot promise', async () => { + await elementById(TestIDs.SET_ROOT_BTN).tap(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.SET_ROOT_BTN).tap(); + await expect(elementByLabel('setRoot complete')).toBeVisible(); + await expect(elementByLabel('component unmounted')).toBeVisible(); + }); + + it('top bar custom button willAppear didAppear after pop, on a root screen', async () => { + await elementById(TestIDs.SHOW_RIGHT_BUTTON).tap(); + await elementById(TestIDs.PUSH_BTN).tap(); + await elementById(TestIDs.CLEAR_OVERLAY_EVENTS_BTN).tap(); + await elementById(TestIDs.BACK_BUTTON).tap(); + await expect( + elementByLabel('componentWillAppear | CustomRoundedButton | TopBarButton') + ).toBeVisible(); + await expect( + elementByLabel('componentDidAppear | CustomRoundedButton | TopBarButton') + ).toBeVisible(); + }); +}); diff --git a/e2e/Utils.js b/e2e/Utils.js new file mode 100644 index 00000000000..c8c8ea1260d --- /dev/null +++ b/e2e/Utils.js @@ -0,0 +1,102 @@ +import { readFileSync } from 'fs'; +import { PNG } from 'pngjs'; +import { ssim } from 'ssim.js'; + +const SSIM_SCORE_THRESHOLD = 0.997; + +function convertToSSIMFormat(image) { + return { + data: new Uint8ClampedArray(image.data), + width: image.width, + height: image.height + }; +} + +function loadImage(path) { + const image = PNG.sync.read(readFileSync(path)); + + return convertToSSIMFormat(image); +} + +function bitmapDiff(imagePath, expectedImagePath, ssimThreshold = SSIM_SCORE_THRESHOLD) { + const image = loadImage(imagePath); + const expectedImage = loadImage(expectedImagePath); + + const { mssim, performance } = ssim(image, expectedImage); + + if (mssim < ssimThreshold) { + throw new Error( + `Expected bitmaps at '${imagePath}' and '${expectedImagePath}' to have an SSIM score ` + + `of at least ${SSIM_SCORE_THRESHOLD}, but got ${mssim}. This means the snapshots are different ` + + `(comparison took ${performance}ms)`, + ); + } +} + +const sleep = (ms) => + new Promise((res) => setTimeout(res, ms)); + +/** + * @param tries Total tries to attempt (retries + 1) + * @param delay Delay between retries, in milliseconds + * @param {Function>} func + * @returns {Promise} + * @throws {Error} if the function fails after all retries + */ +async function retry({ tries = 3, delay = 1000 }, func) { + for (let i = 0; i < tries; i++) { + const result = await func(); + if (result) { + return; + } + + await sleep(delay); + } + + throw new Error(`Failed even after ${tries} attempts`); +} + +const utils = { + elementByLabel: (label) => { + // uncomment for running tests with rn's new arch + // return element(by.label(label)).atIndex(0); + return element(by.text(label)); + }, + elementById: (id) => element(by.id(id)), + elementByTraits: (traits) => element(by.traits(traits)), + elementByType: (type) => element(by.type(type)), + elementTopBar: () => { + const elementType = (device.getPlatform() === 'ios') ? + 'UINavigationBar' : + 'com.reactnativenavigation.views.stack.topbar.TopBar'; + return utils.elementByType(elementType); + }, + tapBackIos: () => { + try { + return element(by.traits(['button']).and(by.label('Back'))) + .atIndex(0) + .tap(); + } catch (err) { + return element(by.type('_UIModernBarButton').and(by.label('Back'))).tap(); + } + }, + sleep, + retry, + expectImagesToBeEqual: (imagePath, expectedImagePath) => { + bitmapDiff(imagePath, expectedImagePath); + + }, + expectImagesToBeNotEqual: (imagePath, expectedImagePath) => { + try { + bitmapDiff(imagePath, expectedImagePath); + } catch (error) { + return + } + + throw new Error( + `Expected bitmaps at '${imagePath}' and '${expectedImagePath}' to be different`, + ); + }, +}; + +export default utils; diff --git a/e2e/assets/bottom_tabs.stylized-root.png b/e2e/assets/bottom_tabs.stylized-root.png new file mode 100644 index 00000000000..2f9c3116e64 Binary files /dev/null and b/e2e/assets/bottom_tabs.stylized-root.png differ diff --git a/e2e/assets/bottom_tabs.stylized.png b/e2e/assets/bottom_tabs.stylized.png new file mode 100644 index 00000000000..3d9fa4554c1 Binary files /dev/null and b/e2e/assets/bottom_tabs.stylized.png differ diff --git a/e2e/assets/buttons_navbar.android.png b/e2e/assets/buttons_navbar.android.png new file mode 100644 index 00000000000..8b5d247352b Binary files /dev/null and b/e2e/assets/buttons_navbar.android.png differ diff --git a/e2e/assets/buttons_navbar.ios.png b/e2e/assets/buttons_navbar.ios.png new file mode 100644 index 00000000000..86580f50a5d Binary files /dev/null and b/e2e/assets/buttons_navbar.ios.png differ diff --git a/e2e/assets/overlay_banner_padding.png b/e2e/assets/overlay_banner_padding.png new file mode 100644 index 00000000000..cb857bc04cb Binary files /dev/null and b/e2e/assets/overlay_banner_padding.png differ diff --git a/e2e/assets/side_menu.aboveContent.png b/e2e/assets/side_menu.aboveContent.png new file mode 100644 index 00000000000..0b1c2acf010 Binary files /dev/null and b/e2e/assets/side_menu.aboveContent.png differ diff --git a/e2e/assets/side_menu.pushContent.png b/e2e/assets/side_menu.pushContent.png new file mode 100644 index 00000000000..995a94cfdc4 Binary files /dev/null and b/e2e/assets/side_menu.pushContent.png differ diff --git a/e2e/assets/side_menu.undefined.png b/e2e/assets/side_menu.undefined.png new file mode 100644 index 00000000000..831a8d36bf2 Binary files /dev/null and b/e2e/assets/side_menu.undefined.png differ diff --git a/e2e/drivers/androidKeyboard.js b/e2e/drivers/androidKeyboard.js new file mode 100644 index 00000000000..222bbb01588 --- /dev/null +++ b/e2e/drivers/androidKeyboard.js @@ -0,0 +1,66 @@ +import { device } from 'detox'; +import Utils from '../Utils'; + +const { retry, sleep } = Utils; + +const androidKbdDriver = { + async init() { + if (device.getPlatform() !== 'android') { + return; + } + + await this._initADB(); + await this._initKbdState(); + }, + + async enableOnScreenKeyboard() { + if (!this.adb) { + // Not initialized (iOS?) + return; + } + await this._setOnscreenKeyboard(true); + }, + + async restoreOnScreenKeyboard() { + if (!this.adb) { + // Not initialized (iOS?) + return; + } + await this._setOnscreenKeyboard(this.kbdEnabled); + }, + + _initADB() { + const { id: adbName } = device; + const { adb } = device.deviceDriver; + + if (!adb || !adbName) { + throw new Error(`Keyboard driver init failed (id=${adbName}, hasADB=${!!adb})`); + } + + this.adb = adb; + this.adbName = adbName; + }, + + async _initKbdState() { + this.kbdEnabled = await this.adb.shell(this.adbName, 'settings get Secure show_ime_with_hard_keyboard'); + + if (!(this.kbdEnabled === '0' || this.kbdEnabled === '1')) { + console.warn('[KbdDriver] Unable to get on-screen KBD setting, defaulting to false'); + this.kbdEnabled = '0'; + } + }, + + async _setOnscreenKeyboard(_value) { + const value = (!!Number(_value) ? '1' : '0'); + + await retry( { tries: 10 }, async () => { + await this.adb.shell(this.adbName, `settings put Secure show_ime_with_hard_keyboard ${value}`); + await sleep(1000); + + const result = await this.adb.shell(this.adbName, 'settings get Secure show_ime_with_hard_keyboard'); + return result === value; + }); + } +} + +module.exports = androidKbdDriver; diff --git a/e2e/iOSUtils.js b/e2e/iOSUtils.js new file mode 100644 index 00000000000..821beed7173 --- /dev/null +++ b/e2e/iOSUtils.js @@ -0,0 +1,11 @@ +import { execSync } from 'shell-utils/src/exec'; + +const utils = { + setDemoMode: () => { + execSync( + 'xcrun simctl status_bar "iPhone 13" override --time "12:00" --batteryState charged --batteryLevel 100 --wifiBars 3 --cellularMode active --cellularBars 4' + ); + }, +}; + +export default utils; diff --git a/e2e/init.js b/e2e/init.js new file mode 100644 index 00000000000..68711b27440 --- /dev/null +++ b/e2e/init.js @@ -0,0 +1 @@ +require('detox-testing-library-rnn-adapter').extendDetox(); diff --git a/e2e/jest.config.js b/e2e/jest.config.js new file mode 100644 index 00000000000..f3f8c99750b --- /dev/null +++ b/e2e/jest.config.js @@ -0,0 +1,19 @@ +module.exports = { + ...require('../jest.config.js'), + + // bail: true, + globalSetup: 'detox/runners/jest/globalSetup', + globalTeardown: 'detox/runners/jest/globalTeardown', + reporters: ['detox/runners/jest/reporter'], + maxWorkers: 1, + moduleNameMapper: { + ...require('../jest.config.js').moduleNameMapper, + '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'identity-obj-proxy', + }, + rootDir: '..', + setupFilesAfterEnv: ['/e2e/init.js'], + testEnvironment: 'detox/runners/jest/testEnvironment', + testMatch: ['/e2e/**.test.{js,ts}'], + testTimeout: 30000, + verbose: true, +}; diff --git a/example/.flowconfig b/example/.flowconfig deleted file mode 100644 index c3edaf94640..00000000000 --- a/example/.flowconfig +++ /dev/null @@ -1,65 +0,0 @@ -[ignore] - -# We fork some components by platform. -.*/*.web.js -.*/*.android.js - -# Some modules have their own node_modules with overlap -.*/node_modules/node-haste/.* - -# Ugh -.*/node_modules/babel.* -.*/node_modules/babylon.* -.*/node_modules/invariant.* - -# Ignore react and fbjs where there are overlaps, but don't ignore -# anything that react-native relies on -.*/node_modules/fbjs/lib/Map.js -.*/node_modules/fbjs/lib/Promise.js -.*/node_modules/fbjs/lib/fetch.js -.*/node_modules/fbjs/lib/ExecutionEnvironment.js -.*/node_modules/fbjs/lib/isEmpty.js -.*/node_modules/fbjs/lib/crc32.js -.*/node_modules/fbjs/lib/ErrorUtils.js - -# Flow has a built-in definition for the 'react' module which we prefer to use -# over the currently-untyped source -.*/node_modules/react/react.js -.*/node_modules/react/lib/React.js -.*/node_modules/react/lib/ReactDOM.js - -# Ignore commoner tests -.*/node_modules/commoner/test/.* - -# See https://github.com/facebook/flow/issues/442 -.*/react-tools/node_modules/commoner/lib/reader.js - -# Ignore jest -.*/node_modules/jest-cli/.* - -# Ignore Website -.*/website/.* - -[include] - -[libs] -node_modules/react-native/Libraries/react-native/react-native-interface.js - -[options] -module.system=haste - -munge_underscores=true - -module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' -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\)$' -> 'RelativeImageStub' - -suppress_type=$FlowIssue -suppress_type=$FlowFixMe -suppress_type=$FixMe - -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-1]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ -suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy - -[version] -0.21.0 diff --git a/example/.gitignore b/example/.gitignore deleted file mode 100644 index 94fc86711d1..00000000000 --- a/example/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# OSX -# -.DS_Store - -# Xcode -# -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -*.moved-aside -DerivedData -*.hmap -*.ipa -*.xcuserstate -project.xcworkspace - -# Android/IJ -# -.idea -.gradle -local.properties - -# node.js -# -node_modules/ -npm-debug.log diff --git a/example/README.md b/example/README.md deleted file mode 100644 index e4d828d36d7..00000000000 --- a/example/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# example - -A simple usage example. If you're using redux, take a look at [example-redux](../example-redux). - -## Installation - iOS - -* In the `example/` folder, run `npm install` - -> Make sure you're using npm ver 3. If you normally use npm ver 2 on your system and reluctant to upgrade, you can install [npm 3 alongside 2](https://www.npmjs.com/package/npm3). For more details see https://github.com/wix/react-native-navigation/issues/1 - -* Open `example/ios/example.xcodeproj` in Xcode and press the play button diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle deleted file mode 100644 index d820066fe60..00000000000 --- a/example/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -apply plugin: "com.android.application" - -import com.android.build.OutputFile -apply from: "../../node_modules/react-native/react.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 25 - buildToolsVersion '26.0.2' - - defaultConfig { - applicationId "com.example" - minSdkVersion 16 - targetSdkVersion 23 - 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" - } - } - buildTypes { - release { - minifyEnabled enableProguardInReleaseBuilds - proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" - } - } - // 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 - } - } - } -} - -dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.facebook.react:react-native:+' - compile project(':react-native-navigation') -} diff --git a/example/android/app/proguard-rules.pro b/example/android/app/proguard-rules.pro deleted file mode 100644 index 87280825b58..00000000000 --- a/example/android/app/proguard-rules.pro +++ /dev/null @@ -1,67 +0,0 @@ -# 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 - -# Do not strip any method/class that is annotated with @DoNotStrip --keep @com.facebook.proguard.annotations.DoNotStrip class * --keepclassmembers class * { - @com.facebook.proguard.annotations.DoNotStrip *; -} - --keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { - void set*(***); - *** withOrder*(); -} - --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.** - -# okhttp - --keepattributes Signature --keepattributes *Annotation* --keep class com.squareup.okhttp.** { *; } --keep interface com.squareup.okhttp.** { *; } --dontwarn com.squareup.okhttp.** - -# okio - --keep class sun.misc.Unsafe { *; } --dontwarn java.nio.file.* --dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement --dontwarn okio.** - -# stetho - --dontwarn com.facebook.stetho.** diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index f3b22ec4f2e..00000000000 --- a/example/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - diff --git a/example/android/app/src/main/ic_launcher-web.png b/example/android/app/src/main/ic_launcher-web.png deleted file mode 100644 index b986e3997a2..00000000000 Binary files a/example/android/app/src/main/ic_launcher-web.png and /dev/null differ diff --git a/example/android/app/src/main/java/com/example/MainActivity.java b/example/android/app/src/main/java/com/example/MainActivity.java deleted file mode 100644 index ee836cfe77e..00000000000 --- a/example/android/app/src/main/java/com/example/MainActivity.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.example; - -import com.reactnativenavigation.controllers.SplashActivity; - -public class MainActivity extends SplashActivity { - -} diff --git a/example/android/app/src/main/java/com/example/MainApplication.java b/example/android/app/src/main/java/com/example/MainApplication.java deleted file mode 100644 index ab75ec36c2d..00000000000 --- a/example/android/app/src/main/java/com/example/MainApplication.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.example; - -import android.support.annotation.Nullable; - -import com.facebook.react.ReactPackage; -import com.reactnativenavigation.NavigationApplication; - -import java.util.List; - -public class MainApplication extends NavigationApplication { - @Override - public boolean isDebug() { - return BuildConfig.DEBUG; - } - - @Nullable - @Override - public List createAdditionalReactPackages() { - return null; - } - - @Nullable - @Override - public String getJSMainModuleName() { - return "index"; - } -} diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 80c0303c1ce..00000000000 Binary files a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 1db4b9da449..00000000000 Binary files a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 66318285982..00000000000 Binary files a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index c2c3b7aaa43..00000000000 Binary files a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index cb3d21d272a..00000000000 Binary files a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/example/android/app/src/main/res/values/strings.xml b/example/android/app/src/main/res/values/strings.xml deleted file mode 100644 index e90a30adda1..00000000000 --- a/example/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - React Native Navigation - diff --git a/example/android/build.gradle b/example/android/build.gradle deleted file mode 100644 index ba204f90cf0..00000000000 --- a/example/android/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - mavenLocal() - jcenter() - google() - 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/example/android/gradle.properties b/example/android/gradle.properties deleted file mode 100644 index 1fd964e90b1..00000000000 --- a/example/android/gradle.properties +++ /dev/null @@ -1,20 +0,0 @@ -# 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/example/android/gradle/wrapper/gradle-wrapper.jar b/example/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 3baa851b28c..00000000000 Binary files a/example/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 0e27bccfc3d..00000000000 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Sun Jan 28 19:31:28 IST 2018 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/example/android/gradlew b/example/android/gradlew deleted file mode 100755 index 27309d92314..00000000000 --- a/example/android/gradlew +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# 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\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# 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 -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -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" -a "$nonstop" = "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"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # 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/example/android/gradlew.bat b/example/android/gradlew.bat deleted file mode 100644 index f6d5974e72f..00000000000 --- a/example/android/gradlew.bat +++ /dev/null @@ -1,90 +0,0 @@ -@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 - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@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= - -@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 Windows 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/example/android/settings.gradle b/example/android/settings.gradle deleted file mode 100644 index dda7fa40abb..00000000000 --- a/example/android/settings.gradle +++ /dev/null @@ -1,6 +0,0 @@ -rootProject.name = 'example' - -include ':app' -include ':react-native-navigation' -project(':react-native-navigation').projectDir = new File( - rootProject.projectDir, '../node_modules/react-native-navigation/android/app/') \ No newline at end of file diff --git a/example/img/beach.jpg b/example/img/beach.jpg deleted file mode 100644 index c8b003629fb..00000000000 Binary files a/example/img/beach.jpg and /dev/null differ diff --git a/example/img/delete@1x.png b/example/img/delete@1x.png deleted file mode 100644 index 999aa4ccc3f..00000000000 Binary files a/example/img/delete@1x.png and /dev/null differ diff --git a/example/img/delete@2x.png b/example/img/delete@2x.png deleted file mode 100644 index 796ccd22559..00000000000 Binary files a/example/img/delete@2x.png and /dev/null differ diff --git a/example/img/edit@1x.png b/example/img/edit@1x.png deleted file mode 100644 index 9efbaae2884..00000000000 Binary files a/example/img/edit@1x.png and /dev/null differ diff --git a/example/img/edit@2x.png b/example/img/edit@2x.png deleted file mode 100644 index 87f8de1ca30..00000000000 Binary files a/example/img/edit@2x.png and /dev/null differ diff --git a/example/img/heroes/bouny_hunter.png b/example/img/heroes/bouny_hunter.png deleted file mode 100644 index 127c206976d..00000000000 Binary files a/example/img/heroes/bouny_hunter.png and /dev/null differ diff --git a/example/img/heroes/earthspirit.png b/example/img/heroes/earthspirit.png deleted file mode 100644 index 45a616380d9..00000000000 Binary files a/example/img/heroes/earthspirit.png and /dev/null differ diff --git a/example/img/heroes/oracle.png b/example/img/heroes/oracle.png deleted file mode 100644 index 13ccbc1f703..00000000000 Binary files a/example/img/heroes/oracle.png and /dev/null differ diff --git a/example/img/heroes/skywrath_mage.png b/example/img/heroes/skywrath_mage.png deleted file mode 100644 index 7cc488165fa..00000000000 Binary files a/example/img/heroes/skywrath_mage.png and /dev/null differ diff --git a/example/img/heroes/templar_assasin.png b/example/img/heroes/templar_assasin.png deleted file mode 100644 index f79b5d0e35c..00000000000 Binary files a/example/img/heroes/templar_assasin.png and /dev/null differ diff --git a/example/img/list@1.5x.android.png b/example/img/list@1.5x.android.png deleted file mode 100644 index 313c43f8947..00000000000 Binary files a/example/img/list@1.5x.android.png and /dev/null differ diff --git a/example/img/list@1x.png b/example/img/list@1x.png deleted file mode 100644 index 64ad8e1445d..00000000000 Binary files a/example/img/list@1x.png and /dev/null differ diff --git a/example/img/list@2x.android.png b/example/img/list@2x.android.png deleted file mode 100644 index f0a2bbc7446..00000000000 Binary files a/example/img/list@2x.android.png and /dev/null differ diff --git a/example/img/list@3x.android.png b/example/img/list@3x.android.png deleted file mode 100644 index 6d4c06ef8c2..00000000000 Binary files a/example/img/list@3x.android.png and /dev/null differ diff --git a/example/img/list@4x.android.png b/example/img/list@4x.android.png deleted file mode 100644 index cd9d1cab07b..00000000000 Binary files a/example/img/list@4x.android.png and /dev/null differ diff --git a/example/img/navicon_add@2x.ios.png b/example/img/navicon_add@2x.ios.png deleted file mode 100644 index 4df23afccce..00000000000 Binary files a/example/img/navicon_add@2x.ios.png and /dev/null differ diff --git a/example/img/swap@1x.png b/example/img/swap@1x.png deleted file mode 100644 index 6566746e224..00000000000 Binary files a/example/img/swap@1x.png and /dev/null differ diff --git a/example/img/swap@2x.png b/example/img/swap@2x.png deleted file mode 100644 index 6f732559827..00000000000 Binary files a/example/img/swap@2x.png and /dev/null differ diff --git a/example/img/transform@1x.png b/example/img/transform@1x.png deleted file mode 100644 index d5503ce4767..00000000000 Binary files a/example/img/transform@1x.png and /dev/null differ diff --git a/example/img/transform@2x.png b/example/img/transform@2x.png deleted file mode 100644 index 18f89daed91..00000000000 Binary files a/example/img/transform@2x.png and /dev/null differ diff --git a/example/index.js b/example/index.js deleted file mode 100644 index e627acc4a71..00000000000 --- a/example/index.js +++ /dev/null @@ -1,2 +0,0 @@ -__STRESS_TEST__ = false; -import App from './src/app'; diff --git a/example/ios/example.xcodeproj/project.pbxproj b/example/ios/example.xcodeproj/project.pbxproj deleted file mode 100644 index 40395a20e31..00000000000 --- a/example/ios/example.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1150 +0,0 @@ -// !$*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 /* exampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* exampleTests.m */; }; - 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 */; }; - 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; - 2647D65F1DB175C200B23722 /* libReactNativeNavigation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2647D65E1DB175B300B23722 /* libReactNativeNavigation.a */; }; - 7B9B39861DEB4091004A6281 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B9B39631DEB4076004A6281 /* libRCTAnimation.a */; }; - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.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 = example; - }; - 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; - }; - 2647D65D1DB175B300B23722 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 2647D6591DB175B300B23722 /* ReactNativeNavigation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = D8AFADBD1BEE6F3F00A4592D; - remoteInfo = ReactNativeNavigation; - }; - 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTLinking; - }; - 7B9B39621DEB4076004A6281 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B9B395C1DEB4076004A6281 /* RCTAnimation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTAnimation; - }; - 7B9B39641DEB4076004A6281 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 7B9B395C1DEB4076004A6281 /* RCTAnimation.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28201D9B03D100D4039D; - remoteInfo = "RCTAnimation-tvOS"; - }; - 7B9B39691DEB4076004A6281 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; - remoteInfo = "RCTImage-tvOS"; - }; - 7B9B396D1DEB4076004A6281 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28471D9B043800D4039D; - remoteInfo = "RCTLinking-tvOS"; - }; - 7B9B39711DEB4076004A6281 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28541D9B044C00D4039D; - remoteInfo = "RCTNetwork-tvOS"; - }; - 7B9B39751DEB4076004A6281 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28611D9B046600D4039D; - remoteInfo = "RCTSettings-tvOS"; - }; - 7B9B39791DEB4076004A6281 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A287B1D9B048500D4039D; - remoteInfo = "RCTText-tvOS"; - }; - 7B9B397E1DEB4076004A6281 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28881D9B049200D4039D; - remoteInfo = "RCTWebSocket-tvOS"; - }; - 7B9B39821DEB4076004A6281 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28131D9B038B00D4039D; - remoteInfo = "React-tvOS"; - }; - 7BFF94261E5F10F20054957C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C059A1DE3340900C268FA; - remoteInfo = yoga; - }; - 7BFF94281E5F10F20054957C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C06751DE3340C00C268FA; - remoteInfo = "yoga-tvOS"; - }; - 7BFF942A1E5F10F20054957C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; - remoteInfo = cxxreact; - }; - 7BFF942C1E5F10F20054957C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; - remoteInfo = "cxxreact-tvOS"; - }; - 7BFF942E1E5F10F20054957C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; - remoteInfo = jschelpers; - }; - 7BFF94301E5F10F20054957C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; - remoteInfo = "jschelpers-tvOS"; - }; - 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5119B1A9E6C1200147676; - remoteInfo = RCTText; - }; - E5E62BA91FFA2FF40025960D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3DBE0D001F3B181A0099AA32; - remoteInfo = fishhook; - }; - E5E62BAB1FFA2FF40025960D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3DBE0D0D1F3B181C0099AA32; - remoteInfo = "fishhook-tvOS"; - }; - E5E62BBB1FFA2FF40025960D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 139D7ECE1E25DB7D00323FB7; - remoteInfo = "third-party"; - }; - E5E62BBD1FFA2FF40025960D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D383D3C1EBD27B6005632C8; - remoteInfo = "third-party-tvOS"; - }; - E5E62BBF1FFA2FF40025960D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 139D7E881E25C6D100323FB7; - remoteInfo = "double-conversion"; - }; - E5E62BC11FFA2FF40025960D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D383D621EBD27B9005632C8; - remoteInfo = "double-conversion-tvOS"; - }; - E5E62BC31FFA2FF40025960D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 9936F3131F5F2E4B0010BF04; - remoteInfo = privatedata; - }; - E5E62BC51FFA2FF40025960D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 9936F32F1F5F2E5B0010BF04; - remoteInfo = "privatedata-tvOS"; - }; -/* 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 /* exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = exampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 00E356F21AD99517003FC87E /* exampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = exampleTests.m; 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 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = example/AppDelegate.h; sourceTree = ""; }; - 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = example/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 = example/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = example/Info.plist; sourceTree = ""; }; - 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = example/main.m; sourceTree = ""; }; - 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; - 2647D6591DB175B300B23722 /* ReactNativeNavigation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeNavigation.xcodeproj; path = "../node_modules/react-native-navigation/ios/ReactNativeNavigation.xcodeproj"; sourceTree = ""; }; - 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; - 7B9B395C1DEB4076004A6281 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; - 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 00E356EB1AD99517003FC87E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 7B9B39861DEB4091004A6281 /* libRCTAnimation.a in Frameworks */, - 2647D65F1DB175C200B23722 /* libReactNativeNavigation.a in Frameworks */, - 146834051AC3E58100842450 /* libReact.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 */, - ); - 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 */, - 7B9B396A1DEB4076004A6281 /* libRCTImage-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302D41ABCB9D200DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, - 7B9B39721DEB4076004A6281 /* libRCTNetwork-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 00C302E01ABCB9EE00DB3ED1 /* Products */ = { - isa = PBXGroup; - children = ( - 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, - ); - name = Products; - sourceTree = ""; - }; - 00E356EF1AD99517003FC87E /* exampleTests */ = { - isa = PBXGroup; - children = ( - 00E356F21AD99517003FC87E /* exampleTests.m */, - 00E356F01AD99517003FC87E /* Supporting Files */, - ); - path = exampleTests; - sourceTree = ""; - }; - 00E356F01AD99517003FC87E /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 00E356F11AD99517003FC87E /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 139105B71AF99BAD00B5F7CC /* Products */ = { - isa = PBXGroup; - children = ( - 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, - 7B9B39761DEB4076004A6281 /* libRCTSettings-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 139FDEE71B06529A00C62182 /* Products */ = { - isa = PBXGroup; - children = ( - 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, - 7B9B397F1DEB4076004A6281 /* libRCTWebSocket-tvOS.a */, - E5E62BAA1FFA2FF40025960D /* libfishhook.a */, - E5E62BAC1FFA2FF40025960D /* libfishhook-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 13B07FAE1A68108700A75B9A /* example */ = { - 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 = example; - sourceTree = ""; - }; - 146834001AC3E56700842450 /* Products */ = { - isa = PBXGroup; - children = ( - 146834041AC3E56700842450 /* libReact.a */, - 7B9B39831DEB4076004A6281 /* libReact.a */, - 7BFF94271E5F10F20054957C /* libyoga.a */, - 7BFF94291E5F10F20054957C /* libyoga.a */, - 7BFF942B1E5F10F20054957C /* libcxxreact.a */, - 7BFF942D1E5F10F20054957C /* libcxxreact.a */, - 7BFF942F1E5F10F20054957C /* libjschelpers.a */, - 7BFF94311E5F10F20054957C /* libjschelpers.a */, - E5E62BBC1FFA2FF40025960D /* libthird-party.a */, - E5E62BBE1FFA2FF40025960D /* libthird-party.a */, - E5E62BC01FFA2FF40025960D /* libdouble-conversion.a */, - E5E62BC21FFA2FF40025960D /* libdouble-conversion.a */, - E5E62BC41FFA2FF40025960D /* libprivatedata.a */, - E5E62BC61FFA2FF40025960D /* libprivatedata-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 2647D65A1DB175B300B23722 /* Products */ = { - isa = PBXGroup; - children = ( - 2647D65E1DB175B300B23722 /* libReactNativeNavigation.a */, - ); - name = Products; - sourceTree = ""; - }; - 78C398B11ACF4ADC00677621 /* Products */ = { - isa = PBXGroup; - children = ( - 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, - 7B9B396E1DEB4076004A6281 /* libRCTLinking-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 7B9B395D1DEB4076004A6281 /* Products */ = { - isa = PBXGroup; - children = ( - 7B9B39631DEB4076004A6281 /* libRCTAnimation.a */, - 7B9B39651DEB4076004A6281 /* libRCTAnimation.a */, - ); - name = Products; - sourceTree = ""; - }; - 832341AE1AAA6A7D00B99B32 /* Libraries */ = { - isa = PBXGroup; - children = ( - 7B9B395C1DEB4076004A6281 /* RCTAnimation.xcodeproj */, - 2647D6591DB175B300B23722 /* ReactNativeNavigation.xcodeproj */, - 146833FF1AC3E56700842450 /* React.xcodeproj */, - 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.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 */, - ); - name = Libraries; - sourceTree = ""; - }; - 832341B11AAA6A8300B99B32 /* Products */ = { - isa = PBXGroup; - children = ( - 832341B51AAA6A8300B99B32 /* libRCTText.a */, - 7B9B397A1DEB4076004A6281 /* libRCTText-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 83CBB9F61A601CBA00E9B192 = { - isa = PBXGroup; - children = ( - 13B07FAE1A68108700A75B9A /* example */, - 832341AE1AAA6A7D00B99B32 /* Libraries */, - 00E356EF1AD99517003FC87E /* exampleTests */, - 83CBBA001A601CBA00E9B192 /* Products */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - }; - 83CBBA001A601CBA00E9B192 /* Products */ = { - isa = PBXGroup; - children = ( - 13B07F961A680F5B00A75B9A /* example.app */, - 00E356EE1AD99517003FC87E /* exampleTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 00E356ED1AD99517003FC87E /* exampleTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */; - buildPhases = ( - 00E356EA1AD99517003FC87E /* Sources */, - 00E356EB1AD99517003FC87E /* Frameworks */, - 00E356EC1AD99517003FC87E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 00E356F51AD99517003FC87E /* PBXTargetDependency */, - ); - name = exampleTests; - productName = exampleTests; - productReference = 00E356EE1AD99517003FC87E /* exampleTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 13B07F861A680F5B00A75B9A /* example */ = { - isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */; - buildPhases = ( - 13B07F871A680F5B00A75B9A /* Sources */, - 13B07F8C1A680F5B00A75B9A /* Frameworks */, - 13B07F8E1A680F5B00A75B9A /* Resources */, - 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = example; - productName = "Hello World"; - productReference = 13B07F961A680F5B00A75B9A /* example.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; - }; - }; - }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 83CBB9F61A601CBA00E9B192; - productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; - ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; - }, - { - ProductGroup = 7B9B395D1DEB4076004A6281 /* Products */; - ProjectRef = 7B9B395C1DEB4076004A6281 /* RCTAnimation.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 = 2647D65A1DB175B300B23722 /* Products */; - ProjectRef = 2647D6591DB175B300B23722 /* ReactNativeNavigation.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - 13B07F861A680F5B00A75B9A /* example */, - 00E356ED1AD99517003FC87E /* exampleTests */, - ); - }; -/* 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; - }; - 2647D65E1DB175B300B23722 /* libReactNativeNavigation.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReactNativeNavigation.a; - remoteRef = 2647D65D1DB175B300B23722 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTLinking.a; - remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7B9B39631DEB4076004A6281 /* libRCTAnimation.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTAnimation.a; - remoteRef = 7B9B39621DEB4076004A6281 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7B9B39651DEB4076004A6281 /* libRCTAnimation.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTAnimation.a; - remoteRef = 7B9B39641DEB4076004A6281 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7B9B396A1DEB4076004A6281 /* libRCTImage-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTImage-tvOS.a"; - remoteRef = 7B9B39691DEB4076004A6281 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7B9B396E1DEB4076004A6281 /* libRCTLinking-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTLinking-tvOS.a"; - remoteRef = 7B9B396D1DEB4076004A6281 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7B9B39721DEB4076004A6281 /* libRCTNetwork-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTNetwork-tvOS.a"; - remoteRef = 7B9B39711DEB4076004A6281 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7B9B39761DEB4076004A6281 /* libRCTSettings-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTSettings-tvOS.a"; - remoteRef = 7B9B39751DEB4076004A6281 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7B9B397A1DEB4076004A6281 /* libRCTText-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTText-tvOS.a"; - remoteRef = 7B9B39791DEB4076004A6281 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7B9B397F1DEB4076004A6281 /* libRCTWebSocket-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTWebSocket-tvOS.a"; - remoteRef = 7B9B397E1DEB4076004A6281 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7B9B39831DEB4076004A6281 /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = 7B9B39821DEB4076004A6281 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7BFF94271E5F10F20054957C /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = 7BFF94261E5F10F20054957C /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7BFF94291E5F10F20054957C /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = 7BFF94281E5F10F20054957C /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7BFF942B1E5F10F20054957C /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = 7BFF942A1E5F10F20054957C /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7BFF942D1E5F10F20054957C /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = 7BFF942C1E5F10F20054957C /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7BFF942F1E5F10F20054957C /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = 7BFF942E1E5F10F20054957C /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 7BFF94311E5F10F20054957C /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = 7BFF94301E5F10F20054957C /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTText.a; - remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E5E62BAA1FFA2FF40025960D /* libfishhook.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libfishhook.a; - remoteRef = E5E62BA91FFA2FF40025960D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E5E62BAC1FFA2FF40025960D /* libfishhook-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libfishhook-tvOS.a"; - remoteRef = E5E62BAB1FFA2FF40025960D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E5E62BBC1FFA2FF40025960D /* libthird-party.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libthird-party.a"; - remoteRef = E5E62BBB1FFA2FF40025960D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E5E62BBE1FFA2FF40025960D /* libthird-party.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libthird-party.a"; - remoteRef = E5E62BBD1FFA2FF40025960D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E5E62BC01FFA2FF40025960D /* libdouble-conversion.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libdouble-conversion.a"; - remoteRef = E5E62BBF1FFA2FF40025960D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E5E62BC21FFA2FF40025960D /* libdouble-conversion.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libdouble-conversion.a"; - remoteRef = E5E62BC11FFA2FF40025960D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E5E62BC41FFA2FF40025960D /* libprivatedata.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libprivatedata.a; - remoteRef = E5E62BC31FFA2FF40025960D /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E5E62BC61FFA2FF40025960D /* libprivatedata-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libprivatedata-tvOS.a"; - remoteRef = E5E62BC51FFA2FF40025960D /* 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 = ( - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, - ); - 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"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 00E356EA1AD99517003FC87E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 00E356F31AD99517003FC87E /* exampleTests.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 /* example */; - targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 13B07FB21A68108700A75B9A /* Base */, - ); - name = LaunchScreen.xib; - path = example; - 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 = exampleTests/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)/example.app/example"; - }; - 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 = exampleTests/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)/example.app/example"; - }; - name = Release; - }; - 13B07F941A680F5B00A75B9A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEAD_CODE_STRIPPING = NO; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/../node_modules/react-native-navigation/ios/**", - ); - INFOPLIST_FILE = example/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = ( - "-ObjC", - "-l\"c++\"", - ); - PRODUCT_NAME = example; - }; - name = Debug; - }; - 13B07F951A680F5B00A75B9A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/../node_modules/react-native-navigation/ios/**", - ); - INFOPLIST_FILE = example/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = ( - "-ObjC", - "-l\"c++\"", - ); - PRODUCT_NAME = example; - }; - 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; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - OTHER_LDFLAGS = ""; - 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; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - OTHER_LDFLAGS = ""; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "exampleTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 00E356F61AD99517003FC87E /* Debug */, - 00E356F71AD99517003FC87E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "example" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 13B07F941A680F5B00A75B9A /* Debug */, - 13B07F951A680F5B00A75B9A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "example" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83CBBA201A601CBA00E9B192 /* Debug */, - 83CBBA211A601CBA00E9B192 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} diff --git a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme deleted file mode 100644 index eae9513713c..00000000000 --- a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example_release.xcscheme b/example/ios/example.xcodeproj/xcshareddata/xcschemes/example_release.xcscheme deleted file mode 100644 index fcc0dafca7d..00000000000 --- a/example/ios/example.xcodeproj/xcshareddata/xcschemes/example_release.xcscheme +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/example/AppDelegate.h b/example/ios/example/AppDelegate.h deleted file mode 100644 index a9654d5e01b..00000000000 --- a/example/ios/example/AppDelegate.h +++ /dev/null @@ -1,16 +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 - -@interface AppDelegate : UIResponder - -@property (nonatomic, strong) UIWindow *window; - -@end diff --git a/example/ios/example/AppDelegate.m b/example/ios/example/AppDelegate.m deleted file mode 100644 index ec926a7b0be..00000000000 --- a/example/ios/example/AppDelegate.m +++ /dev/null @@ -1,51 +0,0 @@ -#import "AppDelegate.h" -#import - -// ********************************************** -// *** DON'T MISS: THE NEXT LINE IS IMPORTANT *** -// ********************************************** -#import "RCCManager.h" - -// IMPORTANT: if you're getting an Xcode error that RCCManager.h isn't found, you've probably ran "npm install" -// with npm ver 2. You'll need to "npm install" with npm 3 (see https://github.com/wix/react-native-navigation/issues/1) - -#import - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - NSURL *jsCodeLocation; -#ifdef DEBUG -// jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios&dev=true"]; - jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; -#else - jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; -#endif - - - // ********************************************** - // *** DON'T MISS: THIS IS HOW WE BOOTSTRAP ***** - // ********************************************** - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - self.window.backgroundColor = [UIColor whiteColor]; - [[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation launchOptions:launchOptions]; - - /* - // original RN bootstrap - remove this part - RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation - moduleName:@"example" - initialProperties:nil - launchOptions:launchOptions]; - 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/example/ios/example/Base.lproj/LaunchScreen.xib b/example/ios/example/Base.lproj/LaunchScreen.xib deleted file mode 100644 index 9e04807a83b..00000000000 --- a/example/ios/example/Base.lproj/LaunchScreen.xib +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json b/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 118c98f7461..00000000000 --- a/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/example/ios/example/Info.plist b/example/ios/example/Info.plist deleted file mode 100644 index 3f1e7c11331..00000000000 --- a/example/ios/example/Info.plist +++ /dev/null @@ -1,47 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - NSLocationWhenInUseUsageDescription - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - - diff --git a/example/ios/example/main.m b/example/ios/example/main.m deleted file mode 100644 index 3d767fcbb9f..00000000000 --- a/example/ios/example/main.m +++ /dev/null @@ -1,18 +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 - -#import "AppDelegate.h" - -int main(int argc, char * argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/example/ios/exampleTests/Info.plist b/example/ios/exampleTests/Info.plist deleted file mode 100644 index 886825ccc9b..00000000000 --- a/example/ios/exampleTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - 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/example/ios/exampleTests/exampleTests.m b/example/ios/exampleTests/exampleTests.m deleted file mode 100644 index 96c0b6bc04d..00000000000 --- a/example/ios/exampleTests/exampleTests.m +++ /dev/null @@ -1,70 +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 -#import - -#import -#import - -#define TIMEOUT_SECONDS 240 -#define TEXT_TO_LOOK_FOR @"Welcome to React Native!" - -@interface exampleTests : XCTestCase - -@end - -@implementation exampleTests - -- (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 = [[[[UIApplication sharedApplication] 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/example/package.json b/example/package.json deleted file mode 100644 index f25c5b4f284..00000000000 --- a/example/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "example", - "version": "0.0.1", - "private": true, - "scripts": { - "postinstall": "node ./scripts/postinstall.js", - "start": "watchman watch-del-all && (adb reverse tcp:8081 tcp:8081 || true) && node node_modules/react-native/local-cli/cli.js start --reset-cache", - "xcode": "open ios/example.xcodeproj", - "android": "cd android && ./gradlew installDebug", - "e2e": "detox test --configuration ios.sim.debug", - "e2e-release": "detox test --configuration ios.sim.release" - }, - "dependencies": { - "react": "16.0.0", - "react-native": "0.53.0", - "react-native-animatable": "^1.1.0", - "react-native-navigation": "latest" - }, - "devDependencies": { - "detox": "^5.0.0", - "mocha": "^3.4.2" - }, - "detox": { - "specs": "test/e2e", - "configurations": { - "ios.sim.debug": { - "binaryPath": "ios/DerivedData/example/Build/Products/Debug-iphonesimulator/example.app", - "type": "ios.simulator", - "name": "iPhone 6s" - }, - "ios.sim.release": { - "binaryPath": "ios/DerivedData/example/Build/Products/Release-iphonesimulator/example.app", - "type": "ios.simulator", - "name": "iPhone 6s" - } - } - } -} diff --git a/example/scripts/postinstall.js b/example/scripts/postinstall.js deleted file mode 100644 index 56b8b5c4dcb..00000000000 --- a/example/scripts/postinstall.js +++ /dev/null @@ -1,3 +0,0 @@ -const cp = require('child_process'); -cp.execSync(`rm -rf node_modules/react-native-navigation/node_modules`); -cp.execSync(`rm -rf node_modules/react-native-navigation/example `); diff --git a/example/src/app.js b/example/src/app.js deleted file mode 100644 index d5d22d346d9..00000000000 --- a/example/src/app.js +++ /dev/null @@ -1,57 +0,0 @@ -import {Platform} from 'react-native'; -import {Navigation} from 'react-native-navigation'; -import {registerScreens, registerScreenVisibilityListener} from './screens'; - - -// screen related book keeping -registerScreens(); -registerScreenVisibilityListener(); - -const tabs = [{ - label: 'Navigation', - screen: 'example.Types', - icon: require('../img/list.png'), - title: 'Navigation Types', -}, { - label: 'Actions', - screen: 'example.Actions', - icon: require('../img/swap.png'), - title: 'Navigation Actions', -}]; - -if (Platform.OS === 'android') { - tabs.push({ - label: 'Transitions', - screen: 'example.Transitions', - icon: require('../img/transform.png'), - title: 'Navigation Transitions', - }); -} - -// this will start our app -Navigation.startTabBasedApp({ - tabs, - animationType: Platform.OS === 'ios' ? 'slide-down' : 'fade', - tabsStyle: { - tabBarBackgroundColor: '#003a66', - tabBarButtonColor: '#ffffff', - tabBarSelectedButtonColor: '#ff505c', - tabFontFamily: 'BioRhyme-Bold', - }, - appStyle: { - tabBarBackgroundColor: '#003a66', - navBarButtonColor: '#ffffff', - tabBarButtonColor: '#ffffff', - navBarTextColor: '#ffffff', - tabBarSelectedButtonColor: '#ff505c', - navigationBarColor: '#003a66', - navBarBackgroundColor: '#003a66', - statusBarColor: '#002b4c', - tabFontFamily: 'BioRhyme-Bold', - }, - drawer: { - left: { - screen: 'example.Types.Drawer' - } - } -}); diff --git a/example/src/components/Row.js b/example/src/components/Row.js deleted file mode 100644 index 97e484b9da9..00000000000 --- a/example/src/components/Row.js +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import {StyleSheet, View, Text, TouchableHighlight, Platform} from 'react-native'; - -class Row extends React.PureComponent { - render() { - const {title, onPress, onPressIn, platform, testID} = this.props; - if (platform && platform !== Platform.OS) { - return ; - } - - return ( - - - {title} - - - ); - } -} - -Row.propTypes = { - title: PropTypes.string.isRequired, - onPress: PropTypes.func.isRequired, - onPressIn: PropTypes.func -}; - -const styles = StyleSheet.create({ - row: { - height: 48, - paddingHorizontal: 16, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - borderBottomWidth: 1, - borderBottomColor: 'rgba(0, 0, 0, 0.054)', - }, - text: { - fontSize: 16, - }, -}); - -export default Row; diff --git a/example/src/screens/Actions.js b/example/src/screens/Actions.js deleted file mode 100644 index 24f1673f53c..00000000000 --- a/example/src/screens/Actions.js +++ /dev/null @@ -1,172 +0,0 @@ -import React from 'react'; -import {StyleSheet, ScrollView} from 'react-native'; -import Row from '../components/Row'; - -class Actions extends React.Component { - - constructor(props) { - super(props); - - this._fab = false; - this._rightButton = null; - this._contextualMenu = false; - this._toggleTabs = 'shown'; - this._toggleNavBar = 'shown'; - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); - } - - onNavigatorEvent(event) { - if (event.id === 'contextualMenuDismissed') { - this._contextualMenu = false; - } - } - - setTitle = () => { - this.props.navigator.setTitle({ - title: 'New Title!' - }); - }; - - setSubtitle = () => { - this.props.navigator.setSubTitle({ - subtitle: 'New SubTitle!', - navigatorStyle: { - navBarSubtitleColor: 'red' - } - }); - }; - - toggleTabs = () => { - const to = this._toggleTabs === 'shown' ? 'hidden' : 'shown'; - - this.props.navigator.toggleTabs({ - to, - animated: true - }); - this._toggleTabs = to; - }; - - setTabBadge = () => { - this.props.navigator.setTabBadge({ - tabIndex: 1, - badge: Math.floor(Math.random() * 20) + 1 - }); - }; - - switchToTab = () => { - this.props.navigator.switchToTab({ - tabIndex: 0 - }); - }; - - toggleNavBar = () => { - const to = this._toggleNavBar === 'shown' ? 'hidden' : 'shown'; - - this.props.navigator.toggleNavBar({ - to, - animated: true - }); - this._toggleNavBar = to; - }; - - showSnackbar = () => { - this.props.navigator.showSnackbar({ - text: 'Woo Snacks!' - }); - }; - - toggleContextualMenu = () => { - if (!this._contextualMenu) { - this.props.navigator.showContextualMenu({ - rightButtons: [{ - title: 'Edit', - icon: require('../../img/edit.png') - }, { - title: 'Delete', - icon: require('../../img/delete.png') - }], - onButtonPressed: (index) => console.log(`Button ${index} tapped`) - }); - this._contextualMenu = true; - } else { - this.props.navigator.dismissContextualMenu(); - this._contextualMenu = false; - } - - }; - - setButtons = () => { - let title = ''; - - if (!this._rightButton) { - title = 'Hello'; - } else if (this._rightButton === 'Hello') { - title = 'Its Me'; - } - - this.props.navigator.setButtons({ - rightButtons: [{ - title, - id: 'topRight' - }], - animated: true - }); - this._rightButton = title; - }; - - toggleFAB = () => { - if (this._fab) { - this.props.navigator.setButtons({ - fab: {} - }); - this._fab = false; - } else { - this.props.navigator.setButtons({ - fab: { - collapsedId: 'share', - collapsedIcon: require('../../img/edit.png'), - expendedId: 'clear', - expendedIcon: require('../../img/edit.png'), - backgroundColor: '#ff505c', - actions: [ - { - id: 'mail', - icon: require('../../img/edit.png'), - backgroundColor: '#03A9F4' - }, - { - id: 'delete', - icon: require('../../img/delete.png'), - backgroundColor: '#4CAF50' - } - ] - }, - animated: true - }); - this._fab = true; - } - }; - - render() { - return ( - - - - - - - - - - - - - ); - } -} - -const styles = StyleSheet.create({ - container: {} -}); - -export default Actions; diff --git a/example/src/screens/NavigationTypes.js b/example/src/screens/NavigationTypes.js deleted file mode 100644 index 4973829f74f..00000000000 --- a/example/src/screens/NavigationTypes.js +++ /dev/null @@ -1,169 +0,0 @@ -import React from 'react'; -import {StyleSheet, ScrollView} from 'react-native'; -import Row from '../components/Row'; - -class NavigationTypes extends React.Component { - - constructor(props) { - super(props); - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); - } - - onNavigatorEvent(event) { - if (event.type === 'DeepLink') { - const parts = event.link.split('/'); - if (parts[0] === 'tab1') { - this.props.navigator.push({ - screen: parts[1] - }); - } - } - } - - toggleDrawer = () => { - this.props.navigator.toggleDrawer({ - side: 'left', - animated: true - }); - }; - - pushScreen = () => { - this.props.navigator.push({ - screen: 'example.Types.Push', - title: 'New Screen', - }); - }; - - previewScreen = () => { - this.props.navigator.push({ - screen: 'example.Types.Push', - title: 'New Screen', - previewCommit: true, - previewHeight: 250, - previewView: this.previewRef, - previewActions: [{ - id: 'action-cancel', - title: 'Cancel' - }, { - id: 'action-delete', - title: 'Delete', - actions: [{ - id: 'action-delete-sure', - title: 'Are you sure?', - style: 'destructive' - }] - }] - }); - }; - - pushListScreen = () => { - console.log('RANG', 'pushListScreen'); - this.props.navigator.push({ - screen: 'example.Types.ListScreen', - title: 'List Screen', - }); - }; - - pushCustomTopBarScreen = () => { - this.props.navigator.push({ - screen: 'example.Types.CustomTopBarScreen' - }); - }; - - pushCustomButtonScreen = () => { - this.props.navigator.push({ - screen: 'example.Types.CustomButtonScreen', - title: 'Custom Buttons' - }); - }; - - pushTopTabsScreen = () => { - this.props.navigator.push({ - screen: 'example.Types.TopTabs', - title: 'Top Tabs', - topTabs: [{ - screenId: 'example.Types.TopTabs.TabOne', - title: 'Tab One', - }, { - screenId: 'example.Types.TopTabs.TabTwo', - title: 'Tab Two', - }], - }); - }; - - showModal = () => { - this.props.navigator.showModal({ - screen: 'example.Types.Modal', - title: 'Modal', - }); - }; - - showLightBox = () => { - this.props.navigator.showLightBox({ - screen: "example.Types.LightBox", - passProps: { - title: 'LightBox', - content: 'Hey there, I\'m a light box screen :D', - onClose: this.dismissLightBox, - }, - style: { - backgroundBlur: 'dark', - backgroundColor: 'rgba(0, 0, 0, 0.7)', - tapBackgroundToDismiss: true - } - }); - }; - - dismissLightBox = () => { - this.props.navigator.dismissLightBox(); - }; - - showInAppNotification = () => { - this.props.navigator.showInAppNotification({ - screen: 'example.Types.Notification', - }); - }; - - render() { - return ( - - - - (this.previewRef = ref)} - title={'Preview Screen'} - testID={'previewScreen'} - onPress={this.pushScreen} - onPressIn={this.previewScreen} - /> - {/**/} - - - - - - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - row: { - height: 48, - paddingHorizontal: 16, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - borderBottomWidth: 1, - borderBottomColor: 'rgba(0, 0, 0, 0.054)', - }, - text: { - fontSize: 16, - }, -}); - -export default NavigationTypes; diff --git a/example/src/screens/Transitions.js b/example/src/screens/Transitions.js deleted file mode 100644 index ff5d418b4b4..00000000000 --- a/example/src/screens/Transitions.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import {StyleSheet, ScrollView, Text} from 'react-native'; -import Row from '../components/Row'; - -class Transitions extends React.Component { - - showCollapsingHeader = () => { - this.props.navigator.showModal({ - title: 'Collapsing Header', - screen: 'example.Transitions.CollapsingHeader', - }); - }; - - showSharedElementTransitions = () => { - this.props.navigator.showModal({ - title: 'Shared Element Transition Examples', - screen: 'example.Transitions.SharedElementTransitions', - }); - }; - - render() { - return ( - - - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, -}); - -export default Transitions; diff --git a/example/src/screens/index.js b/example/src/screens/index.js deleted file mode 100644 index 38d6696f4eb..00000000000 --- a/example/src/screens/index.js +++ /dev/null @@ -1,63 +0,0 @@ -import {Navigation, ScreenVisibilityListener} from 'react-native-navigation'; - -import Types from './NavigationTypes'; -import Actions from './Actions'; -import Transitions from './Transitions'; - -import Push from './types/Push'; -import Drawer from './types/Drawer'; -import ListScreen from './types/ListScreen'; -import DummyScreen from './types/DummyScreen'; -import LightBox from './types/LightBox'; -import Notification from './types/Notification'; -import Modal from './types/Modal'; -import CustomTopBarScreen from './types/CustomTopBarScreen'; -import CustomButtonScreen from './types/CustomButtonScreen'; -import TopTabs from './types/TopTabs'; -import TabOne from './types/tabs/TabOne'; -import TabTwo from './types/tabs/TabTwo'; - -import CollapsingHeader from './transitions/CollapsingHeader'; -import SharedElementTransitions from './transitions/SharedElementTransitions'; - -import Cards from './transitions/sharedElementTransitions/Cards/Cards'; -import CardsInfo from './transitions/sharedElementTransitions/Cards/Info'; - -import Masonry from './transitions/sharedElementTransitions/Masonry/Masonry'; -import MasonryItem from './transitions/sharedElementTransitions/Masonry/Item'; - -export function registerScreens() { - Navigation.registerComponent('example.Types', () => Types); - Navigation.registerComponent('example.Actions', () => Actions); - Navigation.registerComponent('example.Transitions', () => Transitions); - - Navigation.registerComponent('example.Types.Push', () => Push); - Navigation.registerComponent('example.Types.Drawer', () => Drawer); - Navigation.registerComponent('example.Types.Screen', () => Drawer); - Navigation.registerComponent('example.Types.ListScreen', () => ListScreen); - Navigation.registerComponent('example.Types.DummyScreen', () => DummyScreen); - Navigation.registerComponent('example.Types.Modal', () => Modal); - Navigation.registerComponent('example.Types.LightBox', () => LightBox); - Navigation.registerComponent('example.Types.Notification', () => Notification); - Navigation.registerComponent('example.Types.CustomTopBarScreen', () => CustomTopBarScreen); - Navigation.registerComponent('example.Types.CustomButtonScreen', () => CustomButtonScreen); - Navigation.registerComponent('example.Types.TopTabs', () => TopTabs); - Navigation.registerComponent('example.Types.TopTabs.TabOne', () => TabOne); - Navigation.registerComponent('example.Types.TopTabs.TabTwo', () => TabTwo); - - Navigation.registerComponent('example.Transitions.CollapsingHeader', () => CollapsingHeader); - Navigation.registerComponent('example.Transitions.SharedElementTransitions', () => SharedElementTransitions); - Navigation.registerComponent('example.Transitions.SharedElementTransitions.Cards', () => Cards); - Navigation.registerComponent('example.Transitions.SharedElementTransitions.Cards.Info', () => CardsInfo); - Navigation.registerComponent('example.Transitions.SharedElementTransitions.Masonry', () => Masonry); - Navigation.registerComponent('example.Transitions.SharedElementTransitions.Masonry.Item', () => MasonryItem); -} - -export function registerScreenVisibilityListener() { - new ScreenVisibilityListener({ - willAppear: ({screen}) => console.log(`Displaying screen ${screen}`), - didAppear: ({screen, startTime, endTime, commandType}) => console.log('screenVisibility', `Screen ${screen} displayed in ${endTime - startTime} millis [${commandType}]`), - willDisappear: ({screen}) => console.log(`Screen will disappear ${screen}`), - didDisappear: ({screen}) => console.log(`Screen disappeared ${screen}`) - }).register(); -} diff --git a/example/src/screens/transitions/CollapsingHeader.js b/example/src/screens/transitions/CollapsingHeader.js deleted file mode 100644 index 93c3de3c995..00000000000 --- a/example/src/screens/transitions/CollapsingHeader.js +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import {StyleSheet, View, Text, ScrollView} from 'react-native'; - -class CollapsingHeader extends React.Component { - - static navigatorStyle = { - drawUnderTabBar: true, - navBarButtonColor: '#ffffff', - navBarTextColor: '#ffffff', - collapsingToolBarImage: require('../../../img/gyro_header.jpg'), - collapsingToolBarCollapsedColor: '#0f2362', - navBarBackgroundColor: '#eeeeee' - }; - - render() { - return ( - - - {[...new Array(40)].map((a, index) => ( - Row {index} - ))} - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#fff', - }, -}); - -export default CollapsingHeader; diff --git a/example/src/screens/transitions/SharedElementTransitions.js b/example/src/screens/transitions/SharedElementTransitions.js deleted file mode 100644 index 1d44fde275b..00000000000 --- a/example/src/screens/transitions/SharedElementTransitions.js +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; -import {StyleSheet, ScrollView, Text} from 'react-native'; -import Row from '../../components/Row'; - -class Transitions extends React.Component { - - showCardsExample = () => { - this.props.navigator.showModal({ - title: 'Cards', - screen: 'example.Transitions.SharedElementTransitions.Cards', - }); - }; - - showProfileExample = () => { - this.props.navigator.showModal({ - title: 'Profiles', - screen: 'example.Transitions.SharedElementTransitions.Profiles', - }); - }; - - showMasonryExample = () => { - this.props.navigator.showModal({ - title: 'Masonry', - screen: 'example.Transitions.SharedElementTransitions.Masonry', - }); - }; - - render() { - return ( - - - {/**/} - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#ffffff', - }, -}); - -export default Transitions; diff --git a/example/src/screens/transitions/sharedElementTransitions/Cards/Cards.js b/example/src/screens/transitions/sharedElementTransitions/Cards/Cards.js deleted file mode 100644 index 3c2eb91f3ac..00000000000 --- a/example/src/screens/transitions/sharedElementTransitions/Cards/Cards.js +++ /dev/null @@ -1,106 +0,0 @@ -import React from 'react'; -import {ScrollView, TouchableHighlight, StyleSheet, Image, Text, View, ScrolView} from 'react-native'; -import {SharedElementTransition} from 'react-native-navigation'; - -const IMAGE_HEIGHT = 190; - -class CardScreen extends React.Component { - - goToCard = (index) => { - this.props.navigator.push({ - screen: 'example.Transitions.SharedElementTransitions.Cards.Info', - sharedElements: [`image${index}`], - animated: false, - overrideBackPress: true, - passProps: { - sharedImageId: `image${index}` - } - }) - }; - - _renderCard(index) { - return ( - - this.goToCard(index)} - > - - {this._renderImage(index)} - {this._renderCardContent()} - - - - ); - } - - _renderImage(index) { - return ( - - - - ); - } - - _renderCardContent() { - return ( - - This is a title - This is a very long long long long long long long long long long content - - ); - } - - render() { - return ( - - {this._renderCard(0)} - {this._renderCard(1)} - {this._renderCard(2)} - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#ffffff', - }, - content: { - marginHorizontal: 8, - }, - cardContainer: { - marginVertical: 8, - elevation: 2, - borderRadius: 2, - backgroundColor: '#F5F5F5' - }, - imageContainer: { - justifyContent: 'flex-start' - }, - image: { - height: IMAGE_HEIGHT, - borderTopLeftRadius: 2, - borderTopRightRadius: 2 - }, - cardContentContainer: { - padding: 8 - }, - title: { - fontWeight: '500', - paddingBottom: 8, - fontSize: 17 - }, -}); - -export default CardScreen; diff --git a/example/src/screens/transitions/sharedElementTransitions/Cards/Info.js b/example/src/screens/transitions/sharedElementTransitions/Cards/Info.js deleted file mode 100644 index d43fb819416..00000000000 --- a/example/src/screens/transitions/sharedElementTransitions/Cards/Info.js +++ /dev/null @@ -1,123 +0,0 @@ -import React, {Component} from 'react'; -import { - ScrollView, - TouchableOpacity, - StyleSheet, - Image, - Text, - View, - Platform, - ScrolView -} from 'react-native'; -import {SharedElementTransition} from 'react-native-navigation'; -import * as Animatable from 'react-native-animatable'; - -const SHOW_DURATION = 400; -const HIDE_DURATION = 300; - -class InfoScreen extends Component { - - constructor(props) { - super(props); - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); - this.state = { - animationType: 'fadeInRight', - animationDuration: SHOW_DURATION - } - } - - onNavigatorEvent(event) { - if (event.id === 'backPress') { - this.setState({ - animationType: 'fadeOutRight', - animationDuration: HIDE_DURATION - }); - this.props.navigator.pop(); - } - } - - render() { - return ( - - {this._renderImage()} - {this._renderContent()} - - ); - } - - _renderImage() { - return ( - - - - ); - } - - _renderContent() { - return ( - - Line 1 - Line 2 - Line 3 - Line 4 - Line 5 - Line 6 - Line 7 - Line 8 - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1 - }, - content: { - flex: 1, - marginTop: 190, - backgroundColor: 'white' - }, - imageContainer: { - position: 'absolute', - top: 0, - left: 0, - right: 0, - }, - image: { - height: 190 - }, - text: { - fontSize: 17, - paddingVertical: 4, - paddingLeft: 8 - } -}); - -export default InfoScreen; diff --git a/example/src/screens/transitions/sharedElementTransitions/Masonry/Item.js b/example/src/screens/transitions/sharedElementTransitions/Masonry/Item.js deleted file mode 100644 index 1996e866b77..00000000000 --- a/example/src/screens/transitions/sharedElementTransitions/Masonry/Item.js +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import {StyleSheet, View, Text, Image} from 'react-native'; -import {SharedElementTransition} from 'react-native-navigation'; - -const SHOW_DURATION = 240; -const HIDE_DURATION = 200; - -class Item extends React.Component { - - static navigatorStyle = { - navBarHidden: true, - drawUnderNavBar: true - }; - - render() { - return ( - - - - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#ffffff', - justifyContent: 'center', - }, - image: { - width: 400, - height: 400, - } -}); - -export default Item; diff --git a/example/src/screens/transitions/sharedElementTransitions/Masonry/Masonry.js b/example/src/screens/transitions/sharedElementTransitions/Masonry/Masonry.js deleted file mode 100644 index 310f9f8bda7..00000000000 --- a/example/src/screens/transitions/sharedElementTransitions/Masonry/Masonry.js +++ /dev/null @@ -1,98 +0,0 @@ -import React from 'react'; -import {StyleSheet, View, Text, PixelRatio, FlatList, Image, TouchableHighlight} from 'react-native'; -import {Navigation, SharedElementTransition} from 'react-native-navigation'; - -import images from './images'; - -const ROW_HEIGHT = 650; -const COLS = 2; - -class Masonry extends React.Component { - - onAssetPress = (image, key) => { - this.props.navigator.push({ - screen: 'example.Transitions.SharedElementTransitions.Masonry.Item', - sharedElements: [key], - passProps: { - image, - sharedImageId: key, - }, - }); - }; - - renderAsset = (asset, row, column, index) => { - const key = `row_${row}_column_${column}_asset_${index}`; - - return ( - { - this.onAssetPress(asset.source, key); - }} - style={[styles.assetContainer, {flex: asset.weight}]} - > - - - - - - - ); - }; - - renderItem = ({item, index}) => { - return ( - - {[...new Array(COLS)].map((column, columnIndex) => ( - - {item.images[columnIndex].map((asset, assetIndex) => this.renderAsset(asset, index, columnIndex, assetIndex))} - - ))} - - ); - }; - - render() { - return ( - - ({length: ROW_HEIGHT, offset: ROW_HEIGHT * index, index})} - /> - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#ffffff', - }, - item: { - flex: 1, - flexDirection: 'row', - }, - assetContainer: { - margin: 5, - borderRadius: 6, - borderWidth: StyleSheet.hairlineWidth, - }, - asset: { - flex: 1, - borderRadius: 6, - }, -}); - -export default Masonry; diff --git a/example/src/screens/transitions/sharedElementTransitions/Masonry/images.js b/example/src/screens/transitions/sharedElementTransitions/Masonry/images.js deleted file mode 100644 index 91acdff2b02..00000000000 --- a/example/src/screens/transitions/sharedElementTransitions/Masonry/images.js +++ /dev/null @@ -1,100 +0,0 @@ -const images = [ - require('../../../../../img/masonry/Cfw87359UT.jpeg'), - require('../../../../../img/masonry/a848dHxA4e.jpeg'), - require('../../../../../img/masonry/AdGXmD1CH6.jpeg'), - require('../../../../../img/masonry/5Gi8kova3k.jpeg'), - require('../../../../../img/masonry/ri90ueind7.jpeg'), - require('../../../../../img/masonry/kVN0FryOZk.jpeg'), - require('../../../../../img/masonry/v8KLi2f0Tr.jpeg'), - require('../../../../../img/masonry/xU42hx19BB.jpeg'), - require('../../../../../img/masonry/61mpAVRV73.jpeg'), - require('../../../../../img/masonry/pqgylg80SD.jpeg'), - require('../../../../../img/masonry/37r6Cqp1B8.jpeg'), - require('../../../../../img/masonry/N30E32431C.jpeg'), - require('../../../../../img/masonry/rVOcz7rd0z.jpeg'), - require('../../../../../img/masonry/A4g0lZ33Z8.jpeg'), - require('../../../../../img/masonry/j51Pva1P8L.jpeg'), - require('../../../../../img/masonry/158xD4xbeh.jpeg'), -]; - -function randomImage() { - return images[Math.floor(Math.random() * images.length)]; -} - -export default [ - { - key: 1, - images: [[{ - weight: 2, - source: randomImage(), - }, { - weight: 1, - source: randomImage(), - }, { - weight: 3, - source: randomImage(), - }], [{ - weight: 1, - source: randomImage(), - }, { - weight: 3, - source: randomImage(), - }, { - weight: 1, - source: randomImage(), - }, { - weight: 1, - source: randomImage(), - }]], - }, - { - key: 2, - images: [[{ - weight: 1, - source: randomImage(), - }, { - weight: 1, - source: randomImage(), - }, { - weight: 1, - source: randomImage(), - }, { - weight: 3, - source: randomImage(), - }], [{ - weight: 3, - source: randomImage(), - }, { - weight: 3, - source: randomImage(), - }]], - }, - { - key: 3, - images: [[{ - weight: 1, - source: randomImage(), - }, { - weight: 2, - source: randomImage(), - }, { - weight: 1, - source: randomImage(), - }, { - weight: 2, - source: randomImage(), - }], [{ - weight: 2, - source: randomImage(), - }, { - weight: 1, - source: randomImage(), - }, { - weight: 2, - source: randomImage(), - }, { - weight: 1, - source: randomImage(), - }]], - } -]; diff --git a/example/src/screens/transitions/sharedElementTransitions/Profiles/Profiles.js b/example/src/screens/transitions/sharedElementTransitions/Profiles/Profiles.js deleted file mode 100644 index b28edeb1aa9..00000000000 --- a/example/src/screens/transitions/sharedElementTransitions/Profiles/Profiles.js +++ /dev/null @@ -1,213 +0,0 @@ -import React, {Component} from 'react'; -import { - ScrollView, - TouchableOpacity, - StyleSheet, - Image, - Text, - View, - ScrolView -} from 'react-native'; -import {SharedElementTransition} from 'react-native-navigation'; -import * as Animatable from 'react-native-animatable'; - -const FADE_DURATION = 500; -const SHOW_DURATION = 500; -const HIDE_DURATION = 500; - -const ICON_MARGIN = 24; - -class Profiles extends Component { - - constructor(props) { - super(props); - this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)); - this.state = { - animationType: 'fadeIn' - } - } - - componentDidMount() { - if (__STRESS_TEST__) { - setTimeout(() => { - this.setState({ - animationType: 'fadeOut' - }); - this.props.navigator.pop(); - }, 650); - } - } - - onNavigatorEvent(event) { - if (event.id === 'backPress') { - this.setState({ - animationType: 'fadeOut' - }); - this.props.navigator.pop(); - } - } - - _renderHeader() { - return ( - - - - {this._renderIcon()} - {this._renderTitle()} - - - ); - } - - _renderTitle() { - return ( - - - {this.props.title} - - - ); - } - - _renderContent() { - return ( - - - {this._genRows()} - - - ); - } - - _genRows() { - const children = []; - for (let ii = 0; ii < 30; ii++) { - children.push( - {'row ' + ii} - ); - } - return children; - } - - _renderIcon() { - return ( - - - - ); - } - - render() { - return ( - - {this._renderHeader()} - {this._renderContent()} - - ); - } - -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - flexDirection: 'column', - backgroundColor: 'transparent' - }, - header: { - height: 110, - flexDirection: 'column-reverse' - }, - titleContainer: { - marginLeft: ICON_MARGIN + 90 + +16, - marginBottom: 8 - }, - title: { - fontSize: 23, - }, - iconContainer: { - position: 'absolute', - bottom: -ICON_MARGIN, - left: ICON_MARGIN - }, - heroIcon: { - width: 90, - height: 90, - resizeMode: 'contain' - }, - body: { - flex: 4, - backgroundColor: 'white', - }, - list: { - marginTop: 16, - marginHorizontal: 8 - } -}); - -export default Profiles; diff --git a/example/src/screens/transitions/sharedElementTransitions/Profiles/data.js b/example/src/screens/transitions/sharedElementTransitions/Profiles/data.js deleted file mode 100644 index a8a5fdc89ed..00000000000 --- a/example/src/screens/transitions/sharedElementTransitions/Profiles/data.js +++ /dev/null @@ -1,32 +0,0 @@ -export default heroes = [ - { - title: 'Bounty Hunter', - icon: require('../../../../../img/heroes/bouny_hunter.png'), - primaryColor: '#f0cb3c', - titleColor: '#993825' - }, - { - title: 'Templar Assasin', - icon: require('../../../../../img/heroes/templar_assasin.png'), - primaryColor: '#f6f6f6', - titleColor: 'red', - }, - { - title: 'Oracle', - icon: require('../../../../../img/heroes/oracle.png'), - primaryColor: '#19b0b9', - titleColor: '#a2195b' - }, - { - title: 'Earthspirit', - icon: require('../../../../../img/heroes/earthspirit.png'), - primaryColor: '#819c97', - titleColor: 'red', - }, - { - title: 'Skywrath Mage', - icon: require('../../../../../img/heroes/skywrath_mage.png'), - primaryColor: '#dfb42e', - titleColor: '#1e5ea6' - } -]; diff --git a/example/src/screens/types/CustomButtonScreen.js b/example/src/screens/types/CustomButtonScreen.js deleted file mode 100644 index 162adbfebaf..00000000000 --- a/example/src/screens/types/CustomButtonScreen.js +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; -import { - View, - StyleSheet, - Text, - TouchableOpacity, - Button -} from 'react-native'; -import {Navigation} from 'react-native-navigation'; - -let navigator; -const CustomButton = ({text}) => - navigator.pop()} - > - - {text} - - ; -Navigation.registerComponent('CustomButton', () => CustomButton); - -export default class CustomButtonScreen extends React.Component { - static navigatorButtons = { - rightButtons: [ - { - id: 'custom-button', - component: 'CustomButton', - passProps: { - text: 'Hi!' - } - } - ] - }; - - componentWillMount() { - navigator = this.props.navigator; - } - - render() { - return ( - - Custom Left Button - - ); - } - - componentWillUnmount() { - navigator = null; - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - backgroundColor: 'white' - }, - buttonContainer: { - width: 48, - height: 48, - justifyContent: 'center', - alignItems: 'center' - }, - button: { - backgroundColor: 'tomato', - width: 34, - height: 34, - borderRadius: 34 / 2, - overflow: 'hidden', - justifyContent: 'center', - alignItems: 'center' - } -}); diff --git a/example/src/screens/types/CustomTopBar.js b/example/src/screens/types/CustomTopBar.js deleted file mode 100644 index da3e1c17c0b..00000000000 --- a/example/src/screens/types/CustomTopBar.js +++ /dev/null @@ -1,46 +0,0 @@ -import React, {Component} from 'react'; -import { - StyleSheet, - View, - TouchableOpacity, - Text, - Alert, - Platform -} from 'react-native'; - -export default class CustomTopBar extends Component { - - constructor(props) { - super(props); - this.state = {}; - } - - render() { - return ( - - Alert.alert(this.props.title, 'Thanks for that :)') }> - Press Me - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center' - }, - button: { - alignSelf: 'center', - backgroundColor: 'green' - }, - text: { - alignSelf: 'center', - color: Platform.OS === 'ios' ? 'black' : 'white' - } -}); - - - diff --git a/example/src/screens/types/CustomTopBarScreen.js b/example/src/screens/types/CustomTopBarScreen.js deleted file mode 100644 index da2538d5194..00000000000 --- a/example/src/screens/types/CustomTopBarScreen.js +++ /dev/null @@ -1,37 +0,0 @@ -import React, {Component} from 'react'; -import { - View, - StyleSheet, - Text -} from 'react-native'; -import {Navigation} from 'react-native-navigation'; -import CustomTopBar from './CustomTopBar'; - -Navigation.registerComponent('example.CustomTopBar', () => CustomTopBar); - -export default class CustomTopBarScreen extends Component { - componentDidMount() { - this.props.navigator.setStyle({ - navBarCustomView: 'example.CustomTopBar', - navBarComponentAlignment: 'center', - navBarCustomViewInitialProps: {title: 'Hi Custom'} - }); - } - - render() { - return ( - - Custom component in TopBar - - ); - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - backgroundColor: 'white' - } -}); diff --git a/example/src/screens/types/Drawer.js b/example/src/screens/types/Drawer.js deleted file mode 100644 index 4d7cc398df9..00000000000 --- a/example/src/screens/types/Drawer.js +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; -import {StyleSheet, View, Button} from 'react-native'; - -class MyClass extends React.Component { - - onShowModal = () => { - this.toggleDrawer(); - this.props.navigator.showModal({ - screen: 'example.Types.Modal', - title: `Modal` - }); - }; - - onPushToFirstTab = () => { - this.toggleDrawer(); - this.props.navigator.handleDeepLink({ - link: 'tab1/example.Types.Push' - }); - }; - - toggleDrawer = () => { - this.props.navigator.toggleDrawer({ - side: 'left' - }); - }; - - render() { - return ( - - - - - ); - })} - - - - ); - } -} - -function getRandomColor(index) { - return Colors[index % Colors.length]; -} - -const styles = StyleSheet.create({ - cellContainer: { - flex: 1, - paddingVertical: 30, - } -}); - - - -module.exports = ListScreen; \ No newline at end of file diff --git a/example/src/screens/types/Modal.js b/example/src/screens/types/Modal.js deleted file mode 100644 index d645900532e..00000000000 --- a/example/src/screens/types/Modal.js +++ /dev/null @@ -1,109 +0,0 @@ -import React, {Component} from 'react'; -import {StyleSheet, View, Text, Button, TouchableOpacity, Platform} from 'react-native'; -import {Navigation} from 'react-native-navigation'; - -const CloseModalButton = ({text}) => - navigator.dismissModal()} -> - - {text} - -; -Navigation.registerComponent('CloseModalButton', () => CloseModalButton); - -class Modal extends Component { - static navigatorButtons = { - rightButtons: [ - { - id: 'close-modal-button', - component: Platform.OS === 'ios' ? 'CloseModalButton' : null, - passProps: { - text: 'Close' - } - } - ] - }; - - componentWillMount() { - navigator = this.props.navigator; - } - - onPushScreen = () => { - this.props.navigator.push({ - screen: 'example.Types.Modal', - title: `Screen ${this.props.count || 1}`, - passProps: { - count: this.props.count ? this.props.count + 1 : 2 - } - }); - }; - - onResetTo = () => { - this.props.navigator.resetTo({ - screen: 'example.Types.Modal', - icon: require('../../../img/list.png'), - title: 'Modal' - }); - }; - - onPopToRoot = () => { - this.props.navigator.popToRoot(); - }; - - render() { - return ( - - Modal Screen - -