diff --git a/ios/eSteem.xcodeproj/project.pbxproj b/ios/eSteem.xcodeproj/project.pbxproj index 23d1464c1..04e408567 100644 --- a/ios/eSteem.xcodeproj/project.pbxproj +++ b/ios/eSteem.xcodeproj/project.pbxproj @@ -1238,6 +1238,13 @@ remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 478F70212178F4DC00AB7885 /* libReact-Native-Webview-Bridge.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libReact-Native-Webview-Bridge.a"; + remoteRef = 478F70202178F4DC00AB7885 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -1438,11 +1445,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1472,11 +1474,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1565,11 +1562,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1607,11 +1599,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1648,11 +1635,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", @@ -1689,11 +1671,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", - "\"$(SRCROOT)/$(TARGET_NAME)\"", ); OTHER_LDFLAGS = ( "-ObjC", diff --git a/ios/eSteem/Info.plist b/ios/eSteem/Info.plist index 78de3ae99..6090a4a42 100644 --- a/ios/eSteem/Info.plist +++ b/ios/eSteem/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - esteem + eSteem CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -38,7 +38,21 @@ NSLocationWhenInUseUsageDescription - + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + UIAppFonts Entypo.ttf diff --git a/package-lock.json b/package-lock.json index 512dc1d2f..bf763075c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1512,7 +1512,7 @@ "dependencies": { "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { "ansi-styles": "^2.2.1", @@ -1705,7 +1705,7 @@ }, "babel-plugin-istanbul": { "version": "4.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", "dev": true, "requires": { @@ -1738,7 +1738,7 @@ }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" }, "babel-plugin-syntax-trailing-function-commas": { @@ -2291,7 +2291,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { "buffer-xor": "^1.0.3", @@ -2600,7 +2600,7 @@ }, "color": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/color/-/color-1.0.3.tgz", + "resolved": "http://registry.npmjs.org/color/-/color-1.0.3.tgz", "integrity": "sha1-5I6DLYXxTvaU+0aIEcLVz+cptV0=", "requires": { "color-convert": "^1.8.2", @@ -2779,7 +2779,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { "cipher-base": "^1.0.1", @@ -2791,7 +2791,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { "cipher-base": "^1.0.3", @@ -2985,7 +2985,7 @@ "dependencies": { "file-type": { "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" }, "get-stream": { @@ -3856,7 +3856,7 @@ }, "events": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz", "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" }, "evp_bytestokey": { @@ -3958,7 +3958,7 @@ }, "external-editor": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "requires": { "chardet": "^0.4.0", @@ -4834,7 +4834,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, "get-value": { @@ -5350,7 +5350,7 @@ }, "is-builtin-module": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "requires": { "builtin-modules": "^1.0.0" @@ -5495,7 +5495,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, @@ -6983,12 +6983,12 @@ }, "json5": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonfile": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "requires": { "graceful-fs": "^4.1.6" @@ -7538,7 +7538,7 @@ "dependencies": { "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -7584,7 +7584,7 @@ "dependencies": { "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -7634,7 +7634,7 @@ }, "load-json-file": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "requires": { "graceful-fs": "^4.1.2", @@ -7653,9 +7653,9 @@ } }, "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash-es": { "version": "4.17.11", @@ -8406,7 +8406,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "minipass": { @@ -8454,7 +8454,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -8462,7 +8462,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } @@ -8573,9 +8573,14 @@ "tween-functions": "^1.0.1" }, "dependencies": { + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + }, "react-native-keyboard-aware-scroll-view": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/react-native-keyboard-aware-scroll-view/-/react-native-keyboard-aware-scroll-view-0.5.0.tgz", + "resolved": "http://registry.npmjs.org/react-native-keyboard-aware-scroll-view/-/react-native-keyboard-aware-scroll-view-0.5.0.tgz", "integrity": "sha512-nGXsACZBCiWuwRrZy+UjiSJqb4tZ/6ePHUSY8M+09g4VfNm/ogvvWpwBa6B999NZ6DwhZTKBjVWeZxX9XG8bbQ==", "requires": { "prop-types": "^15.6.0", @@ -8979,7 +8984,7 @@ "dependencies": { "minimist": { "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" }, "wordwrap": { @@ -9432,7 +9437,7 @@ }, "regexpp": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", "dev": true }, @@ -9871,14 +9876,6 @@ "resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.4.2.tgz", "integrity": "sha512-6+efUAsLIn8jHwb861ftjNmw0QuIhKCeQ3vBgQvPDWDcdL1M7GbPmOUdATQfoPod+m+UGSjLf8Tez2QwYLAG+A==" }, - "react-native-markdown-editor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/react-native-markdown-editor/-/react-native-markdown-editor-1.0.1.tgz", - "integrity": "sha512-VUrRvg/Qm40cv5P6keShYQTqtkSk1IZo8RITuuzXldZo1gavOTHcaVe2OE4KHdGiiqrLMbL/mZj9NNt3I8FChA==", - "requires": { - "react-native-markdown-view": "^1.0.0" - } - }, "react-native-markdown-view": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/react-native-markdown-view/-/react-native-markdown-view-1.1.4.tgz", @@ -9967,7 +9964,7 @@ }, "react-native-vector-icons": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-4.6.0.tgz", + "resolved": "http://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-4.6.0.tgz", "integrity": "sha512-rpfhfPiXCK2PX1nrNhdxSMrEGB/Gw/SvKoPM0G2wAkSoqynnes19K0VYI+Up7DqR1rFIpE4hP2erpT1tNx2tfg==", "requires": { "lodash": "^4.0.0", @@ -10067,7 +10064,7 @@ }, "react-redux": { "version": "5.0.7", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz", + "resolved": "http://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz", "integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==", "requires": { "hoist-non-react-statics": "^2.5.0", @@ -10141,7 +10138,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -11031,7 +11028,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { "inherits": "^2.0.1", @@ -11546,7 +11543,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -11746,7 +11743,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -11861,7 +11858,7 @@ }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { @@ -12145,7 +12142,7 @@ }, "underscore.string": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "resolved": "http://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=" }, "unicode-canonical-property-names-ecmascript": { @@ -12494,7 +12491,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/package.json b/package.json index ed90197cf..67d7d6c8e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,12 @@ { - "name": "esteem", + "name": "eSteem", "version": "0.0.1", "private": true, + "rnpm": { + "assets": [ + "./assets/fonts" + ] + }, "scripts": { "start": "node node_modules/react-native/local-cli/cli.js start", "eject": "node node_modules/react-native/local-cli/cli.js eject", @@ -20,6 +25,7 @@ "@esteemapp/react-native-tags": "^1.3.1", "crypto-js": "^3.1.9-1", "dsteem": "^0.10.1", + "lodash": "^4.17.11", "moment": "^2.22.2", "native-base": "^2.8.1", "react": "^16.6.0-alpha.8af6728", @@ -29,7 +35,7 @@ "react-native-html-renderer": "^1.0.0", "react-native-keyboard-aware-scroll-view": "^0.7.2", "react-native-linear-gradient": "^2.4.2", - "react-native-markdown-editor": "^1.0.1", + "react-native-markdown-view": "^1.1.4", "react-native-modal": "^6.5.0", "react-native-modal-dropdown": "^0.6.2", "react-native-modal-popover": "0.0.10", diff --git a/src/assets/Fonts/RobotoMono-Regular.ttf b/src/assets/Fonts/RobotoMono-Regular.ttf new file mode 100755 index 000000000..b158a334e Binary files /dev/null and b/src/assets/Fonts/RobotoMono-Regular.ttf differ diff --git a/src/components/basicUIElements/index.js b/src/components/basicUIElements/index.js index d12184e17..84965cb30 100644 --- a/src/components/basicUIElements/index.js +++ b/src/components/basicUIElements/index.js @@ -5,7 +5,15 @@ import NoPost from './view/noPostView'; import PostPlaceHolder from './view/postPlaceHolderView'; import TextWithIcon from './view/textWithIconView'; import WalletLineItem from './view/walletLineItemView'; +import Chip from './view/chipView'; export { - Card, GrayWrapper, LineBreak, NoPost, PostPlaceHolder, TextWithIcon, WalletLineItem, + Card, + GrayWrapper, + Chip, + LineBreak, + NoPost, + PostPlaceHolder, + TextWithIcon, + WalletLineItem, }; diff --git a/src/components/basicUIElements/view/chipStyle.js b/src/components/basicUIElements/view/chipStyle.js new file mode 100644 index 000000000..5441b7c3f --- /dev/null +++ b/src/components/basicUIElements/view/chipStyle.js @@ -0,0 +1,17 @@ +import EStyleSheet from 'react-native-extended-stylesheet'; + +export default EStyleSheet.create({ + textInput: { + color: '$white', + fontSize: 10, + backgroundColor: '#c1c5c7', + borderRadius: 50, + maxHeight: 18, + padding: 5, + paddingHorizontal: 10, + marginRight: 8, + }, + isPin: { + backgroundColor: '$primaryBlue', + }, +}); diff --git a/src/components/basicUIElements/view/chipView.js b/src/components/basicUIElements/view/chipView.js new file mode 100644 index 000000000..b9257aa10 --- /dev/null +++ b/src/components/basicUIElements/view/chipView.js @@ -0,0 +1,16 @@ +import React, { Fragment } from 'react'; +import { TextInput } from 'react-native'; +import styles from './chipStyle'; + +const Chip = props => ( + + props.handleOnChange(text)} + onBlur={() => props.handleOnBlur()} + {...props} + /> + +); + +export default Chip; diff --git a/src/components/buttons/views/iconButtonStyles.js b/src/components/buttons/views/iconButtonStyles.js index 07f5b71b8..18bd17a51 100644 --- a/src/components/buttons/views/iconButtonStyles.js +++ b/src/components/buttons/views/iconButtonStyles.js @@ -1,14 +1,14 @@ -import EStyleSheet from "react-native-extended-stylesheet"; +import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ circleButton: { - alignItems: "center", - backgroundColor: "$white", + alignItems: 'center', + backgroundColor: '$white', height: 60, width: 60, borderRadius: 60 / 2, - justifyContent: "center", - borderColor: "$primaryBlue", + justifyContent: 'center', + borderColor: '$primaryBlue', borderWidth: 1, }, }); diff --git a/src/components/buttons/views/textButtonView.js b/src/components/buttons/views/textButtonView.js index 3d942f0f9..8f4a4f561 100644 --- a/src/components/buttons/views/textButtonView.js +++ b/src/components/buttons/views/textButtonView.js @@ -3,14 +3,13 @@ import { TouchableWithoutFeedback, Text, View } from 'react-native'; import styles from './textButtonStyles'; -const TextButtonView = ({ text, onPress, style }) => ( +const TextButtonView = ({ + text, onPress, style, textStyle, +}) => ( - onPress && onPress()} - > - - {text} + onPress && onPress()}> + + {text} diff --git a/src/components/dropdownButton/view/dropdownButtonStyles.js b/src/components/dropdownButton/view/dropdownButtonStyles.js index 76e043c62..040547bb4 100644 --- a/src/components/dropdownButton/view/dropdownButtonStyles.js +++ b/src/components/dropdownButton/view/dropdownButtonStyles.js @@ -8,14 +8,14 @@ export default EStyleSheet.create({ alignSelf: 'flex-start', height: 35, }, - dropdownText: { - fontSize: 9, - color: '$primaryDarkGray', - marginLeft: 25, - }, + // dropdownText: { + // fontSize: 9, + // color: '$primaryDarkGray', + // marginLeft: 25, + // }, dropdownIcon: { fontSize: 18, - color:"$iconColor", + color: '$iconColor', marginLeft: 7, marginTop: 1, }, diff --git a/src/components/dropdownButton/view/dropdownButtonView.js b/src/components/dropdownButton/view/dropdownButtonView.js index 00898bb08..03e161d92 100644 --- a/src/components/dropdownButton/view/dropdownButtonView.js +++ b/src/components/dropdownButton/view/dropdownButtonView.js @@ -30,15 +30,16 @@ const renderDropdownRow = (rowData, rowID, highlighted) => ( ); const DropdownButtonView = ({ - defaultText, - iconName, - options, - onSelect, - defaultIndex, - children, - style, - isHasChildIcon, childIconWrapperStyle, + children, + defaultIndex, + defaultText, + iconStyle, + iconName, + isHasChildIcon, + onSelect, + options, + style, }) => ( {isHasChildIcon && ( - + )} diff --git a/src/components/editorElements/index.js b/src/components/editorElements/index.js new file mode 100644 index 000000000..51b5ac968 --- /dev/null +++ b/src/components/editorElements/index.js @@ -0,0 +1,5 @@ +import TitleArea from './titleArea/view/titleAreaView'; +import TagArea from './tagArea/view/tagAreaView'; +import TextArea from './textArea/view/textAreaView'; + +export { TitleArea, TagArea, TextArea }; diff --git a/src/components/editorElements/tagArea/view/tagAreaStyles.js b/src/components/editorElements/tagArea/view/tagAreaStyles.js new file mode 100644 index 000000000..9d0b092e8 --- /dev/null +++ b/src/components/editorElements/tagArea/view/tagAreaStyles.js @@ -0,0 +1,21 @@ +import EStyleSheet from 'react-native-extended-stylesheet'; + +export default EStyleSheet.create({ + textInput: { + color: '$white', + fontSize: 10, + backgroundColor: '#c1c5c7', + borderRadius: 50, + maxHeight: 18, + padding: 5, + paddingHorizontal: 10, + marginRight: 8, + }, + tagWrapper: { + flexDirection: 'row', + marginTop: 14, + }, + firstTag: { + backgroundColor: '$primaryBlue', + }, +}); diff --git a/src/components/editorElements/tagArea/view/tagAreaView.js b/src/components/editorElements/tagArea/view/tagAreaView.js new file mode 100644 index 000000000..87e0586b2 --- /dev/null +++ b/src/components/editorElements/tagArea/view/tagAreaView.js @@ -0,0 +1,105 @@ +import React, { Component } from 'react'; +import { View } from 'react-native'; +// Constants + +// Components +import { Chip } from '../../../basicUIElements'; +// Styles +import styles from './tagAreaStyles'; +import globalStyles from '../../../../globalStyles'; + +export default class TagAreaView extends Component { + /* Props + * ------------------------------------------------ + * @prop { type } name - Description.... + */ + + constructor(props) { + super(props); + this.state = { + currentText: '', + chips: [' '], + chipsCount: props.chipsCount || 5, + }; + } + + // Component Life Cycles + + // Component Functions + _handleOnChange = (text, i) => { + this.setState({ currentText: text.trim() }); + + if (text.indexOf(' ') > 0 && text) { + this._handleTagAdded(); + } + + if (!text && i !== 0) { + this._handleTagRemove(i); + } + }; + + _handleOnBlur = (i) => { + this._handleTagAdded(i); + }; + + _handleTagAdded = (i) => { + const { currentText, chips, chipsCount } = this.state; + const { handleTagChanged } = this.props; + + if (currentText && currentText.trim() && chips && chips.length < chipsCount) { + this.setState({ + chips: [...chips, currentText.trim()], + currentText: '', + }); + } + + if (handleTagChanged && chips.length < chipsCount + 1) { + handleTagChanged([...chips, currentText.trim()]); + } + }; + + _handleTagRemove = (i) => { + const { chips } = this.state; + const { handleTagChanged } = this.props; + + this.setState({ + chips: chips.filter((_, _i) => _i !== i), + }); + + if (handleTagChanged) { + handleTagChanged(chips.filter((_, _i) => _i !== i)); + } + }; + + render() { + const { chipsData, isPreviewActive } = this.props; + const { chips } = this.state; + + return ( + + + {chips.map((chip, i) => ( + { + this.inputs[i] = input; + }} + isPin={i === 0 && chips[1]} + placeholderTextColor="#fff" + editable={!isPreviewActive} + maxLength={50} + placeholder="tags" + autoFocus={i !== 0 && chips.length - 1 === i} + multiline={false} + handleOnChange={text => this._handleOnChange(text, i)} + handleOnBlur={() => this._handleOnBlur(i)} + blurOnSubmit + autoCapitalize="none" + {...this.props} + /> + ))} + + + ); + } +} diff --git a/src/components/editorElements/textArea/view/textAreaStyles.js b/src/components/editorElements/textArea/view/textAreaStyles.js new file mode 100644 index 000000000..d0375023e --- /dev/null +++ b/src/components/editorElements/textArea/view/textAreaStyles.js @@ -0,0 +1,8 @@ +import EStyleSheet from 'react-native-extended-stylesheet'; + +export default EStyleSheet.create({ + container: { + flex: 1, + marginTop: 16, + }, +}); diff --git a/src/components/editorElements/textArea/view/textAreaView.js b/src/components/editorElements/textArea/view/textAreaView.js new file mode 100644 index 000000000..5c10dc284 --- /dev/null +++ b/src/components/editorElements/textArea/view/textAreaView.js @@ -0,0 +1,25 @@ +import React, { Component } from 'react'; +// Constants + +// Components +import { MarkdownEditor } from '../../../markdownEditor'; + +export default class TextAreaView extends Component { + /* Props + * ------------------------------------------------ + * @prop { type } name - Description.... + */ + + constructor(props) { + super(props); + this.state = {}; + } + + // Component Life Cycles + + // Component Functions + + render() { + return ; + } +} diff --git a/src/components/editorElements/titleArea/view/titleAreaStyles.js b/src/components/editorElements/titleArea/view/titleAreaStyles.js new file mode 100644 index 000000000..9655ddea8 --- /dev/null +++ b/src/components/editorElements/titleArea/view/titleAreaStyles.js @@ -0,0 +1,9 @@ +import EStyleSheet from 'react-native-extended-stylesheet'; + +export default EStyleSheet.create({ + textInput: { + color: '$primaryBlack', + fontWeight: 'bold', + fontSize: 24, + }, +}); diff --git a/src/components/editorElements/titleArea/view/titleAreaView.js b/src/components/editorElements/titleArea/view/titleAreaView.js new file mode 100644 index 000000000..8e9d82543 --- /dev/null +++ b/src/components/editorElements/titleArea/view/titleAreaView.js @@ -0,0 +1,57 @@ +import React, { Component } from 'react'; +import { TextInput, View } from 'react-native'; +// Constants + +// Components + +// Styles +import styles from './titleAreaStyles'; +import globalStyles from '../../../../globalStyles'; + +export default class TitleAreaView extends Component { + /* Props + * ------------------------------------------------ + * @prop { type } name - Description.... + */ + + constructor(props) { + super(props); + this.state = {}; + } + + // Component Life Cycles + + // Component Functions + _handleOnChange = (text) => { + const { onChange, handleIsValid, componentID } = this.props; + if (onChange) { + onChange(text); + } + + if (handleIsValid) { + handleIsValid(componentID, !!(text && text.length)); + } + }; + + render() { + const { value, isPreviewActive } = this.props; + + return ( + + this._handleOnChange(text)} + value={value} + {...this.props} + /> + + ); + } +} diff --git a/src/components/editorHeader/container/editorHeaderContainer.js b/src/components/editorHeader/container/editorHeaderContainer.js new file mode 100644 index 000000000..920d6e615 --- /dev/null +++ b/src/components/editorHeader/container/editorHeaderContainer.js @@ -0,0 +1,37 @@ +import React, { Component } from 'react'; +import { withNavigation } from 'react-navigation'; + +// Constants +import { default as ROUTES } from '../../../constants/routeNames'; + +// Components +import { EditorHeaderView } from '..'; + +class EditorHeaderContainer extends Component { + /* Props + * ------------------------------------------------ + * @prop { funtion } handleOnPressPreviewButton - Preview button active handler.... + */ + + constructor(props) { + super(props); + this.state = {}; + } + + // Component Life Cycles + + // Component Functions + _handleOnPressBackButton = () => { + const { navigation } = this.props; + + navigation.navigate(ROUTES.SCREENS.HOME); + }; + + render() { + return ( + + ); + } +} + +export default withNavigation(EditorHeaderContainer); diff --git a/src/components/editorHeader/index.js b/src/components/editorHeader/index.js new file mode 100644 index 000000000..8c1c2c68c --- /dev/null +++ b/src/components/editorHeader/index.js @@ -0,0 +1,5 @@ +import EditorHeaderView from './view/editorHeaderView'; +import EditorHeader from './container/editorHeaderContainer'; + +export { EditorHeaderView, EditorHeader }; +export default EditorHeader; diff --git a/src/components/editorHeader/view/editorHeaderStyles.js b/src/components/editorHeader/view/editorHeaderStyles.js new file mode 100644 index 000000000..69d9adfb9 --- /dev/null +++ b/src/components/editorHeader/view/editorHeaderStyles.js @@ -0,0 +1,43 @@ +import EStyleSheet from 'react-native-extended-stylesheet'; + +export default EStyleSheet.create({ + container: { + // flex: 1, + flexDirection: 'row', + justifyContent: 'space-between', + padding: 16, + width: '$deviceWidth', + backgroundColor: '$white', + }, + backIcon: { + fontSize: 24, + color: '$iconColor', + }, + quickTitle: { + flexGrow: 1, + fontSize: 10, + color: '$iconColor', + marginLeft: 24, + alignSelf: 'center', + }, + rightIcon: { + color: '$iconColor', + }, + iconButton: { + marginRight: 24, + justifyContent: 'center', + alignSelf: 'center', + }, + textButton: { + fontSize: 16, + }, + textButtonDisable: { + color: '$iconColor', + }, + textButtonEnable: { + color: '$primaryBlue', + }, + textButtonWrapper: { + justifyContent: 'center', + }, +}); diff --git a/src/components/editorHeader/view/editorHeaderView.js b/src/components/editorHeader/view/editorHeaderView.js new file mode 100644 index 000000000..ab7218383 --- /dev/null +++ b/src/components/editorHeader/view/editorHeaderView.js @@ -0,0 +1,82 @@ +import React, { Component } from 'react'; +import { View, SafeAreaView, Text } from 'react-native'; +import { TextButton } from '../..'; +import { IconButton } from '../../iconButton'; +// Constants + +// Components + +// Styles +import styles from './editorHeaderStyles'; + +class EditorHeaderView extends Component { + /* Props + * ------------------------------------------------ + * @prop { boolean } isFormValid - Righst button propertie + * @prop { string } quickTitle - Left side behind back button text + */ + + constructor(props) { + super(props); + this.state = {}; + } + + // Component Life Cycles + + // Component Functions + + _handleOnPress = () => { + const { handleOnSubmit } = this.props; + + if (handleOnSubmit) { + handleOnSubmit(); + } + }; + + render() { + const { + handleOnPressBackButton, + handleOnPressPreviewButton, + isPreviewActive, + quickTitle, + isFormValid, + } = this.props; + + return ( + + + handleOnPressBackButton()} + /> + {quickTitle} + + handleOnPressPreviewButton()} + iconStyle={styles.rightIcon} + name={isPreviewActive ? 'ios-eye' : 'ios-eye-off'} + /> + + + + ); + } +} + +export default EditorHeaderView; diff --git a/src/components/icon/index.js b/src/components/icon/index.js new file mode 100644 index 000000000..e61bb97df --- /dev/null +++ b/src/components/icon/index.js @@ -0,0 +1,4 @@ +import Icon from './view/iconView'; + +export { Icon }; +export default Icon; diff --git a/src/components/icon/view/iconStyles.js b/src/components/icon/view/iconStyles.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/components/icon/view/iconView.js b/src/components/icon/view/iconView.js new file mode 100644 index 000000000..8cdb5c864 --- /dev/null +++ b/src/components/icon/view/iconView.js @@ -0,0 +1,60 @@ +import React, { Component } from 'react'; +import { Platform } from 'react-native'; + +import Ionicons from 'react-native-vector-icons/Ionicons'; +import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; +import SimpleLineIcons from 'react-native-vector-icons/SimpleLineIcons'; +import FontAwesome from 'react-native-vector-icons/FontAwesome'; +import Feather from 'react-native-vector-icons/Feather'; + +class IconView extends Component { + constructor(props) { + super(props); + this.state = {}; + } + + // for ios its turn ios-eye-off-outline + // for android its turn to md-off-outline + _getIconName = () => { + const { name, androidName } = this.props; + + if (name) { + const isIos = Platform.OS === 'ios'; + let iconName; + + if (!isIos) { + iconName = androidName || `md-${name.split('ios-')}`; + } + return iconName; + } + return null; + }; + + _getIcon = () => { + const { iconType } = this.props; + const name = this._getIconName(); + + switch (iconType) { + case 'Feather': + return ; + case 'FontAwesome': + return ; + case 'SimpleLineIcons': + return {this.props.children}; + case 'MaterialCommunityIcons': + return ( + + {this.props.children} + + ); + default: + return ; + } + }; + + render() { + return this._getIcon(); + } +} + +export default IconView; diff --git a/src/components/iconButton/view/iconButtonStyles.js b/src/components/iconButton/view/iconButtonStyles.js index 72a06aff2..7bd2e1e4d 100644 --- a/src/components/iconButton/view/iconButtonStyles.js +++ b/src/components/iconButton/view/iconButtonStyles.js @@ -1,13 +1,12 @@ -import EStyleSheet from "react-native-extended-stylesheet"; +import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ iconButton: { width: 30, height: 30, borderRadius: 30 / 2, - justifyContent: "center", - }, - icon: { - textAlign: "center", + justifyContent: 'center', + alignItems: 'center', }, + icon: {}, }); diff --git a/src/components/iconButton/view/iconButtonView.js b/src/components/iconButton/view/iconButtonView.js index b47502428..b00dd094b 100644 --- a/src/components/iconButton/view/iconButtonView.js +++ b/src/components/iconButton/view/iconButtonView.js @@ -1,32 +1,43 @@ -import React from "react"; -import { View, TouchableHighlight } from "react-native"; -import Ionicons from "react-native-vector-icons/Ionicons"; +import React, { Fragment } from 'react'; +import { TouchableHighlight } from 'react-native'; +import { Icon } from '../../icon'; -import styles from "./iconButtonStyles"; +import styles from './iconButtonStyles'; /* Props * ------------------------------------------------ * @prop { type } name - Description.... */ -const IconButton = ({ name, color, size, onPress, backgroundColor, style }) => ( - +const IconButton = ({ + name, + color, + size, + onPress, + backgroundColor, + style, + iconStyle, + iconType, +}) => ( + onPress && onPress()} - underlayColor={backgroundColor} + underlayColor={backgroundColor || 'white'} > - - + ); export default IconButton; diff --git a/src/components/markdownEditor/index.js b/src/components/markdownEditor/index.js new file mode 100644 index 000000000..556fe1fce --- /dev/null +++ b/src/components/markdownEditor/index.js @@ -0,0 +1,4 @@ +import MarkdownEditor from './view/markdownEditorView'; + +export { MarkdownEditor }; +export default MarkdownEditor; diff --git a/src/components/markdownEditor/view/editorBarStyles.js b/src/components/markdownEditor/view/editorBarStyles.js new file mode 100644 index 000000000..223589db9 --- /dev/null +++ b/src/components/markdownEditor/view/editorBarStyles.js @@ -0,0 +1,14 @@ +import EStyleSheet from 'react-native-extended-stylesheet'; + +export default EStyleSheet.create({ + container: { + flexDirection: 'row', + backgroundColor: '$white', + alignItems: 'center', + height: 48, + shadowOpacity: 0.2, + shadowOffset: { + height: 1.5, + }, + }, +}); diff --git a/src/components/markdownEditor/view/formats/applyListFormat.js b/src/components/markdownEditor/view/formats/applyListFormat.js new file mode 100644 index 000000000..baee5f334 --- /dev/null +++ b/src/components/markdownEditor/view/formats/applyListFormat.js @@ -0,0 +1,32 @@ +import { replaceBetween } from './utils'; + +export default ({ getState, item, setState }) => { + let { text } = getState(); + const { selection } = getState(); + text = text || ''; + let newText; + let newSelection; + if (selection.start !== selection.end) { + newText = replaceBetween( + text, + selection, + `${item.prefix} ${text.substring(selection.start, selection.end)}\n`, + ); + newSelection = { start: selection.end + 3, end: selection.end + 3 }; + } else if ( + selection.start === selection.end + && text.substring(selection.end - 1, selection.end) === '\n' + ) { + newText = replaceBetween(text, selection, `${item.prefix} `); + newSelection = { start: selection.start + 2, end: selection.start + 2 }; + } else { + newText = replaceBetween(text, selection, `\n${item.prefix} `); + newSelection = { start: selection.start + 3, end: selection.start + 3 }; + } + + setState({ text: newText }, () => { + setTimeout(() => { + setState({ selection: newSelection }); + }, 300); + }); +}; diff --git a/src/components/markdownEditor/view/formats/applyWebLinkFormat.js b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js new file mode 100644 index 000000000..8e5d3d0d9 --- /dev/null +++ b/src/components/markdownEditor/view/formats/applyWebLinkFormat.js @@ -0,0 +1,35 @@ +import { isStringWebLink, replaceBetween } from './utils'; + +export const writeUrlTextHere = 'https://example.com'; +export const writeTextHereString = 'Text here!'; + +export default ({ getState, item, setState }) => { + const { selection, text } = getState(); + let newText; + let newSelection; + const selectedText = text.substring(selection.start, selection.end); + if (selection.start !== selection.end) { + if (isStringWebLink(selectedText)) { + newText = replaceBetween(text, selection, `[${writeTextHereString}](${selectedText})`); + newSelection = { + start: selection.start + 1, + end: selection.start + 1 + writeTextHereString.length, + }; + } else { + newText = replaceBetween(text, selection, `[${selectedText}](${writeUrlTextHere})`); + newSelection = { + start: selection.end + 3, + end: selection.end + 3 + writeUrlTextHere.length, + }; + } + } else { + newText = replaceBetween(text, selection, `[${writeTextHereString}](${writeUrlTextHere})`); + newSelection = { + start: selection.start + 1, + end: selection.start + 1 + writeTextHereString.length, + }; + } + setState({ text: newText }, () => { + setState({ selection: newSelection }); + }); +}; diff --git a/src/components/markdownEditor/view/formats/applyWrapFormat.js b/src/components/markdownEditor/view/formats/applyWrapFormat.js new file mode 100644 index 000000000..39a1f9a25 --- /dev/null +++ b/src/components/markdownEditor/view/formats/applyWrapFormat.js @@ -0,0 +1,27 @@ +import { replaceBetween } from './utils'; + +export default ({ getState, item, setState }) => { + const { text, selection } = getState(); + const newText = replaceBetween( + text, + selection, + item.wrapper.concat(text.substring(selection.start, selection.end), item.wrapper), + ); + let newPosition; + if (selection.start === selection.end) { + newPosition = selection.end + item.wrapper.length; + } else { + newPosition = selection.end + item.wrapper.length * 2; + } + const extra = { + selection: { + start: newPosition, + end: newPosition, + }, + }; + setState({ text: newText }, () => { + setTimeout(() => { + setState({ ...extra }); + }, 25); + }); +}; diff --git a/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js new file mode 100644 index 000000000..517284bb8 --- /dev/null +++ b/src/components/markdownEditor/view/formats/applyWrapFormatNewLines.js @@ -0,0 +1,55 @@ +import { replaceBetween } from './utils'; + +export default ({ getState, item, setState }) => { + const { text, selection } = getState(); + let newText = replaceBetween( + text, + selection, + `\n${item.wrapper.concat( + '\n', + text.substring(selection.start, selection.end), + '\n', + item.wrapper, + '\n', + )}`, + ); + let newPosition; + if (selection.start === selection.end) { + newPosition = selection.end + item.wrapper.length + 2; // +2 For two new lines + newText = replaceBetween( + text, + selection, + `\n${item.wrapper.concat( + '\n', + text.substring(selection.start, selection.end), + '\n', + item.wrapper, + '\n', + )}`, + ); + } else { + newPosition = selection.end + item.wrapper.length * 2 + 3; // +3 For three new lines + newText = replaceBetween( + text, + selection, + `${item.wrapper.concat( + '\n', + text.substring(selection.start, selection.end), + '\n', + item.wrapper, + '\n', + )}`, + ); + } + const extra = { + selection: { + start: newPosition, + end: newPosition, + }, + }; + setState({ text: newText }, () => { + setTimeout(() => { + setState({ ...extra }); + }, 25); + }); +}; diff --git a/src/components/markdownEditor/view/formats/formats.js b/src/components/markdownEditor/view/formats/formats.js new file mode 100644 index 000000000..e5db69689 --- /dev/null +++ b/src/components/markdownEditor/view/formats/formats.js @@ -0,0 +1,116 @@ +import applyWrapFormat from './applyWrapFormat'; +import applyWrapFormatNewLines from './applyWrapFormatNewLines'; +import applyListFormat from './applyListFormat'; +import applyWebLinkFormat from './applyWebLinkFormat'; + +export default [ + { + key: 'B', + title: 'B', + icon: 'bold', + iconType: 'Feather', + wrapper: '**', + onPress: applyWrapFormat, + // style: { fontWeight: 'bold' }, + }, + { + key: 'H1', + title: 'H1', + icon: 'format-size', + iconType: 'MaterialCommunityIcons', + prefix: '#', + onPress: applyListFormat, + }, + { + key: 'L', + title: 'L', + icon: 'list', + iconType: 'Feather', + prefix: '-', + onPress: applyListFormat, + }, + { + key: 'C', + title: 'C', + icon: 'ios-code', + wrapper: '`', + onPress: applyWrapFormat, + }, + { + key: 'I', + title: 'I', + icon: 'italic', + iconType: 'Feather', + wrapper: '*', + onPress: applyWrapFormat, + }, + { + key: 'U', + title: 'U', + icon: 'underline', + iconType: 'Feather', + wrapper: '__', + onPress: applyWrapFormat, + }, + { + key: 'S', + title: 'S', + wrapper: '~~', + icon: 'strikethrough', + iconType: 'FontAwesome', + onPress: applyWrapFormat, + }, + { + key: '>', + title: '>', + prefix: '>', + icon: 'ios-quote', + onPress: applyListFormat, + }, + + { + key: 'CC', + title: 'CC', + icon: 'ios-code-working', + wrapper: '```', + onPress: applyWrapFormatNewLines, + }, + + { + key: 'WEB', + title: 'WEB', + icon: 'link-2', + iconType: 'Feather', + onPress: applyWebLinkFormat, + }, + // { + // key: 'H2', + // title: 'H2', + // prefix: '##', + // onPress: applyListFormat, + // }, + // { + // key: 'H3', + // title: 'H3', + // prefix: '###', + // onPress: applyListFormat, + // }, + // { + // key: 'H4', + // title: 'H4', + // prefix: '####', + // onPress: applyListFormat, + // }, + // { + // key: 'H5', + // title: 'H5', + // prefix: '#####', + // onPress: applyListFormat, + // }, + // { + // key: 'H6', + // title: 'H6', + // prefix: '######', + // onPress: applyListFormat, + // }, +]; diff --git a/src/components/markdownEditor/view/formats/utils.js b/src/components/markdownEditor/view/formats/utils.js new file mode 100644 index 000000000..31428de0e --- /dev/null +++ b/src/components/markdownEditor/view/formats/utils.js @@ -0,0 +1,8 @@ +import regexValidator from './webLinkValidator'; + +export const replaceBetween = (text: string, selection: Object, what: string) => text.substring(0, selection.start) + what + text.substring(selection.end); + +export const isStringWebLink = (text: string): boolean => { + const pattern = regexValidator; + return pattern.test(text); +}; diff --git a/src/components/markdownEditor/view/formats/webLinkValidator.js b/src/components/markdownEditor/view/formats/webLinkValidator.js new file mode 100644 index 000000000..8e9ccd88b --- /dev/null +++ b/src/components/markdownEditor/view/formats/webLinkValidator.js @@ -0,0 +1,45 @@ +// Regular Expression for URL validation +// +// Author: Diego Perini +// Updated: 2010/12/05 +// License: MIT +// +// Copyright (c) 2010-2013 Diego Perini (http://www.iport.it) +// +export default new RegExp( + '^' + // protocol identifier + + '(?:(?:https?|ftp)://)' + // user:pass authentication + + '(?:\\S+(?::\\S*)?@)?' + + '(?:' + // IP address exclusion + // private & local networks + + '(?!(?:10|127)(?:\\.\\d{1,3}){3})' + + '(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})' + + '(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})' + // IP address dotted notation octets + // excludes loopback network 0.0.0.0 + // excludes reserved space >= 224.0.0.0 + // excludes network & broacast addresses + // (first & last IP address of each class) + + '(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])' + + '(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}' + + '(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))' + + '|' + // host name + + '(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)' + // domain name + + '(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*' + // TLD identifier + + '(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))' + // TLD may end with dot + + '\\.?' + + ')' + // port number + + '(?::\\d{2,5})?' + // resource path + + '(?:[/?#]\\S*)?' + + '$', + 'i', +); diff --git a/src/components/markdownEditor/view/markdownEditorStyles.js b/src/components/markdownEditor/view/markdownEditorStyles.js new file mode 100644 index 000000000..6675c5ece --- /dev/null +++ b/src/components/markdownEditor/view/markdownEditorStyles.js @@ -0,0 +1,56 @@ +import EStyleSheet from 'react-native-extended-stylesheet'; + +export default EStyleSheet.create({ + container: { + flex: 1, + flexDirection: 'column', + alignItems: 'stretch', + backgroundColor: '$white', + }, + textWrapper: { + flex: 1, + flexDirection: 'column', + fontSize: 12, + marginVertical: 16, + paddingHorizontal: 16, + }, + inlinePadding: { + padding: 8, + }, + editorButtons: { + flexDirection: 'row', + backgroundColor: '$white', + alignItems: 'center', + justifyContent: 'space-between', + height: 50, + shadowOpacity: 0.2, + shadowOffset: { + height: 1.5, + }, + }, + leftButtonsWrapper: { + marginLeft: 16, + flexDirection: 'row', + alignItems: 'center', + maxWidth: '$deviceWidth / 1.85', + }, + rightButtonsWrapper: { + marginRight: 16, + flexDirection: 'row', + alignItems: 'center', + }, + editorButton: { + color: '$primaryDarkGray', + paddingRight: 22, + height: 24, + }, + dropdownStyle: { + marginRight: 8, + }, + rightIcons: { + paddingRight: 21, + }, + dropdownIconStyle: { + color: '$primaryDarkGray', + }, +}); diff --git a/src/components/markdownEditor/view/markdownEditorView.js b/src/components/markdownEditor/view/markdownEditorView.js new file mode 100644 index 000000000..bab93f503 --- /dev/null +++ b/src/components/markdownEditor/view/markdownEditorView.js @@ -0,0 +1,152 @@ +import React, { Component } from 'react'; +import { + View, TextInput, KeyboardAvoidingView, ScrollView, FlatList, +} from 'react-native'; +import { MarkdownView } from 'react-native-markdown-view'; + +// Components +import Formats from './formats/formats'; +import { IconButton } from '../../iconButton'; +import { DropdownButton } from '../../dropdownButton'; + +// Styles +import styles from './markdownEditorStyles'; +import previewStyles from './markdownPreviewStyles'; + +export default class MarkdownEditorView extends Component { + constructor(props) { + super(props); + this.state = { + text: '', + selection: { start: 0, end: 0 }, + }; + } + + componentDidMount() { + this.textInput.focus(); + } + + changeText = (input) => { + const { + onChange, handleOnTextChange, handleIsValid, componentID, + } = this.props; + + this.setState({ text: input }); + + if (onChange) { + onChange(input); + } + + if (handleIsValid) { + handleIsValid(componentID, !!(input && input.length)); + } + + handleOnTextChange && handleOnTextChange(input); + }; + + _handleOnSelectionChange = (event) => { + this.setState({ + selection: event.nativeEvent.selection, + }); + }; + + _getState = () => { + this.setState({ + selection: { + start: 1, + end: 1, + }, + }); + return this.state; + }; + + _renderPreview = () => { + const { text } = this.state; + + return ( + + + {text === '' ? '...' : text} + + + ); + }; + + _renderMarkupButton = ({ item, getState, setState }) => ( + + item.onPress({ getState, setState, item })} + /> + + ); + + _renderEditorButtons = ({ getState, setState }) => ( + + + this._renderMarkupButton({ item, getState, setState })} + horizontal + /> + + + Formats[9].onPress({ getState, setState })} + /> + + + + + ); + + render() { + const { isPreviewActive } = this.props; + const { text, selection } = this.state; + + return ( + + {!isPreviewActive ? ( + this.changeText(text)} + onSelectionChange={this._handleOnSelectionChange} + placeholder="What would you like to write about today?" + placeholderTextColor="#c1c5c7" + ref={textInput => (this.textInput = textInput)} + selection={selection} + selectionColor="#357ce6" + style={styles.textWrapper} + underlineColorAndroid="transparent" + value={text} + {...this.props} + /> + ) : ( + this._renderPreview() + )} + {!isPreviewActive + && this._renderEditorButtons({ + getState: this._getState, + setState: (state, callback) => { + this.textInput.focus(); + this.setState(state, callback); + }, + })} + + ); + } +} diff --git a/src/components/markdownEditor/view/markdownPreviewStyles.js b/src/components/markdownEditor/view/markdownPreviewStyles.js new file mode 100644 index 000000000..b5d51057a --- /dev/null +++ b/src/components/markdownEditor/view/markdownPreviewStyles.js @@ -0,0 +1,16 @@ +export const markdownPreviewStyles = { + heading1: { + fontSize: 24, + color: 'red', + backgroundColor: 'red', + }, + link: { + color: 'pink', + }, + mailTo: { + color: 'orange', + }, + text: { + color: '#555555', + }, +}; diff --git a/src/components/markdownEditor/view/renderButtons.js b/src/components/markdownEditor/view/renderButtons.js new file mode 100644 index 000000000..edbe1dfd1 --- /dev/null +++ b/src/components/markdownEditor/view/renderButtons.js @@ -0,0 +1,31 @@ +import React from 'react'; +import { + FlatList, TouchableOpacity, Text, View, +} from 'react-native'; + +import Formats from './formats/formats'; + +import styles from './editorBarStyles'; + +const FOREGROUND_COLOR = '#788187'; +const defaultStyles = { padding: 8, color: FOREGROUND_COLOR, fontSize: 16 }; + +const defaultMarkdownButton = ({ item, getState, setState }) => ( + item.onPress({ getState, setState, item })}> + {item.title} + +); + +export const renderEditorButtons = ({ getState, setState }, formats, markdownButton) => ( + + (markdownButton + ? markdownButton({ item, getState, setState }) + : defaultMarkdownButton({ item, getState, setState })) + } + horizontal + /> + +); diff --git a/src/components/numericKeyboard/views/numericKeyboardView.js b/src/components/numericKeyboard/views/numericKeyboardView.js index b7590e263..3fcc9aaf8 100644 --- a/src/components/numericKeyboard/views/numericKeyboardView.js +++ b/src/components/numericKeyboard/views/numericKeyboardView.js @@ -1,15 +1,13 @@ -import React, { Fragment, Component } from "react"; -import { View } from "react-native"; +import React, { Component } from 'react'; +import { View } from 'react-native'; -import { CircularButton, IconButton } from "../../"; +import { CircularButton, IconButton } from '../..'; -import styles from "./numericKeyboardStyles"; +import styles from './numericKeyboardStyles'; class NumericKeyboard extends Component { /* Props - * * @prop { func } onPress - Function will trigger when any button clicked. - * */ constructor(props) { super(props); @@ -20,7 +18,7 @@ class NumericKeyboard extends Component { // Component Functions - _handleOnPress = value => { + _handleOnPress = (value) => { alert(value); }; @@ -98,7 +96,7 @@ class NumericKeyboard extends Component { /> onPress && onPress("clear")} + handleOnPress={() => onPress && onPress('clear')} isCircle style={styles.iconButton} name="close" diff --git a/src/components/postButton/container/postButtonContainer.js b/src/components/postButton/container/postButtonContainer.js new file mode 100644 index 000000000..b3ac01b76 --- /dev/null +++ b/src/components/postButton/container/postButtonContainer.js @@ -0,0 +1,28 @@ +import React, { Component } from 'react'; +import { withNavigation } from 'react-navigation'; + +// Components +import { PostButtonView } from '..'; + +class PostButtonContainer extends Component { + constructor(props) { + super(props); + this.state = {}; + } + + // Component Life Cycle Functions + + // Component Functions + + _handleSubButtonPress = (route) => { + const { navigation } = this.props; + + navigation.navigate(route); + }; + + render() { + return ; + } +} + +export default withNavigation(PostButtonContainer); diff --git a/src/components/postButton/index.js b/src/components/postButton/index.js index 2f4071e6b..f8f3f91ab 100644 --- a/src/components/postButton/index.js +++ b/src/components/postButton/index.js @@ -1,4 +1,5 @@ -import PostButton from './view/postButtonView'; +import PostButtonView from './view/postButtonView'; +import PostButton from './container/postButtonContainer'; -export { PostButton }; +export { PostButtonView, PostButton }; export default PostButton; diff --git a/src/components/postButton/view/postButtonView.js b/src/components/postButton/view/postButtonView.js index 2089e2bd6..937d1deec 100644 --- a/src/components/postButton/view/postButtonView.js +++ b/src/components/postButton/view/postButtonView.js @@ -81,15 +81,7 @@ class PostButtonView extends Component { outputRange: ['0deg', '45deg'], }); - // const bluring = this.mode.interpolate({ - // inputRange: [0, 1], - // outputRange: [10, 5], - // }); - - // const blurin2 = this.mode.interpolate({ - // inputRange: [0, 1], - // outputRange: [0, -20], - // }); + const { handleSubButtonPress } = this.props; return ( @@ -108,6 +100,7 @@ class PostButtonView extends Component { top: secondY, }} icon="pencil" + onPress={() => handleSubButtonPress('EditorScreen')} /> { + const { handleOnSubmit, isFormValid } = this.props; + + if (isFormValid && handleOnSubmit && returnKeyType === 'done') { + handleOnSubmit(); + } else if (returnKeyType === 'next' && inputElement) { + // TODO: its accept current input but its should be next input ref + inputElement.focus(); + } + }; + + _handleOnChange = (componentID, value, isValid = null) => { + const { handleFormUpdate } = this.props; + + handleFormUpdate(componentID, value, !!isValid || !!value); + }; + + render() { + const { children, isFormValid, isPreviewActive } = this.props; + + return ( + + {React.Children.map(children, (child) => { + if (child) { + return React.cloneElement(child, { + onSubmitEditing: item => this._handleOnSubmitEditing(child.props.returnKeyType, item), + onChange: value => this._handleOnChange(child.props.componentID, value), + returnKeyType: isFormValid ? 'done' : 'next', + isPreviewActive, + }); + } + })} + + ); + } +} + +export default PostFormView; diff --git a/src/components/sideMenu/container/sideMenuContainer.js b/src/components/sideMenu/container/sideMenuContainer.js index 8c63a2651..6e2e16348 100644 --- a/src/components/sideMenu/container/sideMenuContainer.js +++ b/src/components/sideMenu/container/sideMenuContainer.js @@ -29,7 +29,7 @@ class SideMenuContainer extends Component { // Component Functions - _navigateToRoute = (route) => { + _navigateToRoute = (route = null) => { const { navigation } = this.props; navigation.navigate(route); }; diff --git a/src/components/sideMenu/view/sideMenuView.js b/src/components/sideMenu/view/sideMenuView.js index 58eeb7ab7..8b42e167c 100644 --- a/src/components/sideMenu/view/sideMenuView.js +++ b/src/components/sideMenu/view/sideMenuView.js @@ -28,6 +28,7 @@ class SideMenuView extends Component { render() { const { isLoggedIn, userAvatar, navigateToRoute } = this.props; + return ( diff --git a/src/config/routes.js b/src/config/routes.js index a92b1e883..567744e82 100644 --- a/src/config/routes.js +++ b/src/config/routes.js @@ -3,7 +3,9 @@ import { BaseNavigator } from '../navigation'; import { default as ROUTES } from '../constants/routeNames'; // Screens -import { Splash, Login, PinCode } from '../screens'; +import { + Editor, Login, PinCode, Splash, +} from '../screens'; // Components import { SideMenu } from '../components'; @@ -23,8 +25,9 @@ const mainNavigation = DrawerNavigator( ); export default SwitchNavigator({ - [ROUTES.SCREENS.SPLASH]: { screen: Splash }, + [ROUTES.DRAWER.MAIN]: mainNavigation, + [ROUTES.SCREENS.EDITOR]: { screen: Editor }, [ROUTES.SCREENS.LOGIN]: { screen: Login }, [ROUTES.SCREENS.PINCODE]: { screen: PinCode }, - [ROUTES.DRAWER.MAIN]: mainNavigation, + [ROUTES.SCREENS.SPLASH]: { screen: Splash }, }); diff --git a/src/constants/routeNames.js b/src/constants/routeNames.js index 08ba2c339..fda0f0dad 100644 --- a/src/constants/routeNames.js +++ b/src/constants/routeNames.js @@ -3,10 +3,11 @@ const DRAWER_SUFFIX = 'Drawer'; export default { SCREENS: { - SPLASH: `Splash${SCREEN_SUFFIX}`, + EDITOR: `Editor${SCREEN_SUFFIX}`, + HOME: `Home${SCREEN_SUFFIX}`, LOGIN: `Login${SCREEN_SUFFIX}`, PINCODE: `PinCode${SCREEN_SUFFIX}`, - HOME: `Home${SCREEN_SUFFIX}`, + SPLASH: `Splash${SCREEN_SUFFIX}`, }, DRAWER: { MAIN: `Main${DRAWER_SUFFIX}`, diff --git a/src/globalStyles.js b/src/globalStyles.js index 2ffe35986..2f5877273 100644 --- a/src/globalStyles.js +++ b/src/globalStyles.js @@ -1,10 +1,11 @@ import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ - container: { + containerHorizontal16: { + paddingHorizontal: 16, + }, + defaultContainer: { flex: 1, - alignItems: 'center', - justifyContent: 'center', }, title: {}, text: { diff --git a/src/screens/editor/container/editorContainer.js b/src/screens/editor/container/editorContainer.js new file mode 100644 index 000000000..86ee14b85 --- /dev/null +++ b/src/screens/editor/container/editorContainer.js @@ -0,0 +1,76 @@ +import React, { Component } from 'react'; + +// Services and Actions +import { postContent } from '../../../providers/steem/dsteem'; +import { getUserData } from '../../../realm/realm'; + +// Middleware + +// Constants +import { default as ROUTES } from '../../../constants/routeNames'; + +// Utilities +import { generatePermlink } from '../../../utils/editor'; +import { decryptKey } from '../../../utils/crypto'; + +// Component +import { EditorScreen } from '../screen/editorScreen'; + +/* + * Props Name Description Value + *@props --> props name here description here Value Type Here + * + */ + +class ExampleContainer extends Component { + constructor(props) { + super(props); + this.state = {}; + } + + // Component Life Cycle Functions + + // Component Functions + + _submitPost = async (form) => { + const { navigation } = this.props; + let userData; + let postingKey; + const title = form.formFields['title-area'].content; + const permlink = generatePermlink(title); + + await getUserData().then((res) => { + userData = res && Array.from(res)[0]; + postingKey = decryptKey(userData.postingKey, '1234'); + }); + + if (userData) { + const post = { + body: form.formFields['text-area'].content, + title, + author: userData.username, + permlink: permlink && permlink, + tags: form.tags, + }; + + postContent(post, postingKey) + .then((result) => { + alert('Your post succesfully shared'); + navigation.navigate(ROUTES.SCREENS.HOME); + }) + .catch((error) => { + alert(`Opps! there is a problem${error}`); + }); + } + }; + + _handleSubmit = (form) => { + this._submitPost(form); + }; + + render() { + return ; + } +} + +export default ExampleContainer; diff --git a/src/screens/editor/editor.js b/src/screens/editor/editor.js deleted file mode 100644 index 816ad25b9..000000000 --- a/src/screens/editor/editor.js +++ /dev/null @@ -1,188 +0,0 @@ -import React from 'react'; -import { - Container, - Header, - Left, - Body, - Right, - Button, - Icon, - Title, - Content, -} from 'native-base'; -import { MarkdownEditor } from 'react-native-markdown-editor'; -import { - StatusBar, - View, - TextInput, - TouchableOpacity, - Text, -} from 'react-native'; -import Tags from '@esteemapp/react-native-tags'; -import { postContent } from '../../providers/steem/dsteem'; -import { getUserData, getAuthStatus } from '../../realm/realm'; -import { decryptKey } from '../../utils/crypto'; - -class EditorPage extends React.Component { - constructor(props) { - super(props); - this.onChangeBody = this.onChangeBody.bind(this); - this.onChangeTitle = this.onChangeTitle.bind(this); - this.onChangeTags = this.onChangeTags.bind(this); - - this.state = { - body: '', - title: '', - author: '', - permlink: '', - tags: ['esteem'], - }; - } - - componentDidMount() {} - - onChangeBody = (body) => { - this.setState({ - body, - }); - }; - - onChangeTitle = (title) => { - this.setState({ - title, - }); - }; - - onChangeTags = (tags) => { - this.setState({ - tags, - }); - }; - - generatePermlink = () => { - let title; - - title = this.state.title - .replace(/[^\w\s]/gi, '') - .replace(/\s\s+/g, '-') - .replace(/\s/g, '-') - .toLowerCase(); - title = `${title - }-id-${ - Math.random() - .toString(36) - .substr(2, 16)}`; - - return title; - }; - - submitPost = async () => { - let userData; - let postingKey; - - await getUserData().then((res) => { - userData = Array.from(res); - postingKey = decryptKey(userData[0].postingKey, 'pinCode'); - }); - - post = { - body: this.state.body, - title: this.state.title, - author: userData[0].username, - permlink: this.generatePermlink(), - tags: this.state.tags, - }; - - console.log(post); - - postContent(post, postingKey) - .then((result) => { - console.log(result); - }) - .catch((error) => { - console.log(error); - }); - }; - - render() { - return ( - - - this.onChangeTitle(title)} - style={{ - borderWidth: 1, - borderColor: 'lightgray', - height: 40, - margin: 10, - borderRadius: 10, - flex: 0.08, - }} - /> - this.onChangeTags(tags)} - onTagLongPress={(index, tagLabel, event, deleted) => console.log( - index, - tagLabel, - event, - deleted ? 'deleted' : 'not deleted', - ) - } - containerStyle={{ justifyContent: 'center' }} - inputStyle={{ backgroundColor: 'white' }} - maxNumberOfTags={5} - tagContainerStyle={{ - height: 25, - backgroundColor: '#284b78', - }} - tagTextStyle={{ fontWeight: '600', color: 'white' }} - style={{ - borderWidth: 1, - borderColor: 'lightgray', - flex: 0.12, - }} - /> - - { - this.onChangeBody(text); - }} - /> - - - - - Options - - - - - Submit - - - - - - - ); - } -} - -export default EditorPage; diff --git a/src/screens/editor/index.js b/src/screens/editor/index.js new file mode 100644 index 000000000..7380ead23 --- /dev/null +++ b/src/screens/editor/index.js @@ -0,0 +1,4 @@ +import Editor from './container/editorContainer'; + +export { Editor }; +export default Editor; diff --git a/src/screens/editor/screen/editorScreen.js b/src/screens/editor/screen/editorScreen.js new file mode 100644 index 000000000..c2c7ac042 --- /dev/null +++ b/src/screens/editor/screen/editorScreen.js @@ -0,0 +1,117 @@ +import React, { Component } from 'react'; +import { View } from 'react-native'; + +// Utils +import { getWordsCount } from '../../../utils/editor'; + +// Constants + +// Components +import { EditorHeader } from '../../../components/editorHeader'; +import { TitleArea, TagArea, TextArea } from '../../../components/editorElements'; +import { PostForm } from '../../../components/postForm'; +// Styles +import globalStyles from '../../../globalStyles'; + +export class EditorScreen extends Component { + /* Props + * ------------------------------------------------ + * @prop { type } name - Description.... + */ + + constructor(props) { + super(props); + this.state = { + isPreviewActive: false, + wordsCount: null, + formFields: {}, + isFormValid: false, + tags: [], + }; + } + + // Component Life Cycles + + // Component Functions + _handleOnPressPreviewButton = () => { + const { isPreviewActive } = this.state; + + this.setState({ isPreviewActive: !isPreviewActive }); + }; + + _setWordsCount = (content) => { + const _wordsCount = getWordsCount(content); + const { wordsCount } = this.state; + + if (_wordsCount !== wordsCount) { + this.setState({ wordsCount: _wordsCount }); + } + }; + + _handleOnSubmit = () => { + const { handleOnSubmit } = this.props; + const { formFields, tags } = this.state; + + if (handleOnSubmit) { + handleOnSubmit({ formFields, tags }); + } + }; + + _handleIsFormValid = () => { + const { formFields, tags } = this.state; + + this.setState({ + isFormValid: + formFields['title-area'] + && formFields['text-area'] + && formFields['title-area'].isValid + && formFields['text-area'].isValid + && tags + && tags.length > 0, + }); + }; + + _handleFormUpdate = (componentID, content, isValid) => { + const { formFields } = this.state; + const newFormFields = formFields; + + newFormFields[componentID] = { + content, + isValid, + }; + + this.setState({ formFields: newFormFields }); + + this._handleIsFormValid(); + }; + + _handleOnTagAdded = (tags) => { + this.setState({ tags: tags.filter(tag => tag && tag !== ' ') }); + }; + + render() { + const { isPreviewActive, wordsCount, isFormValid } = this.state; + + return ( + + 0 && `${wordsCount} words`} + handleOnPressPreviewButton={this._handleOnPressPreviewButton} + isFormValid={isFormValid} + handleOnSubmit={this._handleOnSubmit} + /> + + + +