├── .flowconfig ├── .gitignore ├── .idea ├── .name ├── cnodejs.iml ├── jsLibraryMappings.xml ├── libraries │ └── cnodejs_node_modules.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── .watchmanconfig ├── CnodeJs └── CnodeJs.xcodeproj │ └── project.pbxproj ├── README.md ├── Source └── logo │ └── IOS │ ├── noder-Icon-300px.png │ ├── noder-Icon-450px.png │ ├── noder-Icon.png │ └── noder-Icon.psd ├── android ├── .gradle │ └── 2.4 │ │ └── taskArtifacts │ │ ├── cache.properties │ │ ├── cache.properties.lock │ │ ├── fileHashes.bin │ │ ├── fileSnapshots.bin │ │ ├── outputFileStates.bin │ │ └── taskArtifacts.bin ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ ├── react.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── Fonts │ │ │ ├── Entypo.ttf │ │ │ ├── EvilIcons.ttf │ │ │ ├── FontAwesome.ttf │ │ │ ├── Foundation.ttf │ │ │ ├── Ionicons.ttf │ │ │ ├── MaterialIcons.ttf │ │ │ ├── Octicons.ttf │ │ │ ├── Zocial.ttf │ │ │ └── materialdesignicons-webfont.ttf │ │ ├── java │ │ └── com │ │ │ └── cnodejs │ │ │ └── MainActivity.java │ │ └── res │ │ ├── drawable │ │ ├── ic_create_black_48dp.png │ │ ├── ic_menu_black_24dp.png │ │ ├── ic_settings_black_48dp.png │ │ ├── launcher_icon.png │ │ ├── plus_dark.png │ │ ├── plus_white.png │ │ ├── uie_comment_highlighted.png │ │ ├── uie_comment_normal.png │ │ ├── uie_thumb_normal.png │ │ └── uie_thumb_selected.png │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── androidApp ├── actions │ ├── ActionTypes.js │ ├── HomeActions.js │ ├── MessageActions.js │ ├── TopicActions.js │ ├── UserActions.js │ └── index.js ├── components │ ├── ActivityIndicator.js │ ├── BarCodeModule │ │ ├── BarCode.android.js │ │ └── BarCode.ios.js │ ├── DefaultTabBar.js │ ├── Error.js │ ├── ImageCircle.js │ ├── Loading.js │ ├── MessageListView.js │ ├── PickerModule │ │ └── Picker.js │ ├── ScrollableTabView.js │ ├── ScrollableTabViewAndroid │ │ ├── DimensionsHelper.js │ │ ├── ViewPager.js │ │ ├── ViewPagerDots.js │ │ └── ViewPagerTabs.js │ ├── SwitchModule │ │ ├── Switch.android.js │ │ └── Switch.ios.js │ ├── ToolBar │ │ ├── BasicToolBar.js │ │ ├── MainScreenToolBar.js │ │ ├── PublishToolBar.js │ │ └── TopicToolBar.js │ ├── TopicListView.js │ ├── UserInfo.js │ ├── alertModule │ │ ├── alertLogin.js │ │ └── alertLogout.js │ ├── buttonModule │ │ ├── BasicButton.js │ │ └── PublishButton.js │ ├── htmlRender │ │ ├── CommentHtml.js │ │ └── HtmlContent.js │ ├── openUrlModule │ │ ├── openUrl.android.js │ │ └── openUrl.ios.js │ └── rowModule │ │ ├── CommentRow.js │ │ ├── MenuRow.js │ │ ├── MessageRow.js │ │ ├── ReplyRow.js │ │ ├── SettingsRow.js │ │ ├── SimpleRow.js │ │ ├── TopicInfoRow.js │ │ ├── TopicRow.js │ │ ├── UserRow.js │ │ └── loginRow.js ├── configs │ ├── Constants.js │ ├── Router.js │ ├── animation.js │ ├── config.js │ ├── initConfig.js │ └── sceneConfig.js ├── containers │ ├── About.js │ ├── BarCode.js │ ├── Home.js │ ├── Login.js │ ├── Message.js │ ├── NavigationList.js │ ├── Navitation.js │ ├── Settings.js │ ├── TopicInfoListView.js │ ├── User.js │ ├── WriteTopic.js │ ├── app.js │ └── cnodeApp.js ├── mocks │ ├── storage.js │ ├── topic.js │ └── userInfo.js ├── reducers │ ├── configReducer.js │ ├── index.js │ ├── topicReducer.js │ └── userReducer.js ├── services │ ├── ConfigService.js │ ├── MessageService.js │ ├── Request.js │ ├── Storage.js │ ├── TopicService.js │ └── UserService.js └── util │ ├── cnodeUtil.js │ ├── genColor.js │ └── window.js ├── image ├── about_header_bg.png ├── defaultUser.png ├── error.png ├── loading.gif └── user_detail_header_bg.png ├── index.android.js ├── index.ios.js ├── ios ├── cnodejs.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── cnodejs.xcscheme ├── cnodejs │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── main.m ├── cnodejsTests │ ├── Info.plist │ └── cnodejsTests.m └── main.jsbundle ├── logo_og.png ├── my-icon.png └── package.json /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | # We fork some components by platform. 4 | .*/*.web.js 5 | .*/*.android.js 6 | 7 | # Some modules have their own node_modules with overlap 8 | .*/node_modules/node-haste/.* 9 | 10 | # Ugh 11 | .*/node_modules/babel.* 12 | .*/node_modules/babylon.* 13 | .*/node_modules/invariant.* 14 | 15 | # Ignore react and fbjs where there are overlaps, but don't ignore 16 | # anything that react-native relies on 17 | .*/node_modules/fbjs/lib/Map.js 18 | .*/node_modules/fbjs/lib/Promise.js 19 | .*/node_modules/fbjs/lib/fetch.js 20 | .*/node_modules/fbjs/lib/ExecutionEnvironment.js 21 | .*/node_modules/fbjs/lib/isEmpty.js 22 | .*/node_modules/fbjs/lib/crc32.js 23 | .*/node_modules/fbjs/lib/ErrorUtils.js 24 | 25 | # Flow has a built-in definition for the 'react' module which we prefer to use 26 | # over the currently-untyped source 27 | .*/node_modules/react/react.js 28 | .*/node_modules/react/lib/React.js 29 | .*/node_modules/react/lib/ReactDOM.js 30 | 31 | # Ignore commoner tests 32 | .*/node_modules/commoner/test/.* 33 | 34 | # See https://github.com/facebook/flow/issues/442 35 | .*/react-tools/node_modules/commoner/lib/reader.js 36 | 37 | # Ignore jest 38 | .*/node_modules/jest-cli/.* 39 | 40 | # Ignore Website 41 | .*/website/.* 42 | 43 | [include] 44 | 45 | [libs] 46 | node_modules/react-native/Libraries/react-native/react-native-interface.js 47 | 48 | [options] 49 | module.system=haste 50 | 51 | munge_underscores=true 52 | 53 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 54 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub' 55 | 56 | suppress_type=$FlowIssue 57 | suppress_type=$FlowFixMe 58 | suppress_type=$FixMe 59 | 60 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-0]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 61 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-0]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 62 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 63 | 64 | [version] 65 | 0.20.1 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IJ 26 | # 27 | .idea 28 | .gradle 29 | local.properties 30 | 31 | # node.js 32 | # 33 | node_modules/ 34 | npm-debug.log 35 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | cnodejs -------------------------------------------------------------------------------- /.idea/cnodejs.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/libraries/cnodejs_node_modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /CnodeJs/CnodeJs.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXFileReference section */ 10 | 5EDD47CF1C4E6D7E00037FFC /* CNodeJs */ = {isa = PBXFileReference; lastKnownFileType = folder; name = CNodeJs; path = ..; sourceTree = ""; }; 11 | /* End PBXFileReference section */ 12 | 13 | /* Begin PBXGroup section */ 14 | 5EDD47C81C4E6D6900037FFC = { 15 | isa = PBXGroup; 16 | children = ( 17 | 5EDD47CF1C4E6D7E00037FFC /* CNodeJs */, 18 | ); 19 | sourceTree = ""; 20 | }; 21 | /* End PBXGroup section */ 22 | 23 | /* Begin PBXProject section */ 24 | 5EDD47C91C4E6D6900037FFC /* Project object */ = { 25 | isa = PBXProject; 26 | attributes = { 27 | LastUpgradeCheck = 0700; 28 | }; 29 | buildConfigurationList = 5EDD47CC1C4E6D6900037FFC /* Build configuration list for PBXProject "CnodeJs" */; 30 | compatibilityVersion = "Xcode 3.2"; 31 | developmentRegion = English; 32 | hasScannedForEncodings = 0; 33 | knownRegions = ( 34 | en, 35 | ); 36 | mainGroup = 5EDD47C81C4E6D6900037FFC; 37 | projectDirPath = ""; 38 | projectRoot = ""; 39 | targets = ( 40 | ); 41 | }; 42 | /* End PBXProject section */ 43 | 44 | /* Begin XCBuildConfiguration section */ 45 | 5EDD47CD1C4E6D6900037FFC /* Debug */ = { 46 | isa = XCBuildConfiguration; 47 | buildSettings = { 48 | }; 49 | name = Debug; 50 | }; 51 | 5EDD47CE1C4E6D6900037FFC /* Release */ = { 52 | isa = XCBuildConfiguration; 53 | buildSettings = { 54 | }; 55 | name = Release; 56 | }; 57 | /* End XCBuildConfiguration section */ 58 | 59 | /* Begin XCConfigurationList section */ 60 | 5EDD47CC1C4E6D6900037FFC /* Build configuration list for PBXProject "CnodeJs" */ = { 61 | isa = XCConfigurationList; 62 | buildConfigurations = ( 63 | 5EDD47CD1C4E6D6900037FFC /* Debug */, 64 | 5EDD47CE1C4E6D6900037FFC /* Release */, 65 | ); 66 | defaultConfigurationIsVisible = 0; 67 | defaultConfigurationName = Release; 68 | }; 69 | /* End XCConfigurationList section */ 70 | }; 71 | rootObject = 5EDD47C91C4E6D6900037FFC /* Project object */; 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-cnodejs - A React-Native Client for [cnodejs.org](http://cnodejs.org) 2 | 3 | > A [cnodejs.org](http://cnodejs.org) mobile app powered by [React-Native](http://facebook.github.io/react-native/) and [Redux](https://github.com/gaearon/redux). 4 | >This project is inspired by [Noder](https://github.com/soliury/noder-react-native).I rewrited by ES6 and lastest RN version to adapted both android and ios. 5 | 6 | 7 | ## Develop 8 | 9 | For local development you need to follow the below commands: 10 | 11 | ``` 12 | git clone https://github.com/marsprince/react-native-cnodejs.git 13 | npm install 14 | ``` 15 | 16 | Then follow official [guides](https://facebook.github.io/react-native/docs/getting-started.html). 17 | 18 | ## Screenshots 19 | 20 | TODO 21 | 22 | 23 | ## React-Native Modules In Using 24 | 25 | * [react-native-barcodescanner](https://github.com/ideacreation/react-native-barcodescanner) 26 | * [react-native-camera](https://github.com/lwansbrough/react-native-camera) 27 | * [react-native-drawer-layout](https://github.com/iodine/react-native-drawer-layout) 28 | * [react-native-html-render](https://github.com/soliury/react-native-html-render) 29 | * [react-native-scrollable-tab-view](https://github.com/brentvatne/react-native-scrollable-tab-view) 30 | * [react-native-vector-icons](https://github.com/oblador/react-native-vector-icons) 31 | 32 | This project is heavily influenced by the above modules. 33 | 34 | ## ToDo List 35 | 36 | * IOS adapted 37 | * markdown textinput 38 | * settings 39 | * and more 40 | 41 | ## Contribute 42 | 43 | If you find any issues, just solve it and make a PR. 44 | 45 | Thanks! 46 | 47 | ## License 48 | 49 | [MIT License](http://en.wikipedia.org/wiki/MIT_License) 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Source/logo/IOS/noder-Icon-300px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/Source/logo/IOS/noder-Icon-300px.png -------------------------------------------------------------------------------- /Source/logo/IOS/noder-Icon-450px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/Source/logo/IOS/noder-Icon-450px.png -------------------------------------------------------------------------------- /Source/logo/IOS/noder-Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/Source/logo/IOS/noder-Icon.png -------------------------------------------------------------------------------- /Source/logo/IOS/noder-Icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/Source/logo/IOS/noder-Icon.psd -------------------------------------------------------------------------------- /android/.gradle/2.4/taskArtifacts/cache.properties: -------------------------------------------------------------------------------- 1 | #Sat Oct 10 13:36:20 CST 2015 2 | -------------------------------------------------------------------------------- /android/.gradle/2.4/taskArtifacts/cache.properties.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/.gradle/2.4/taskArtifacts/cache.properties.lock -------------------------------------------------------------------------------- /android/.gradle/2.4/taskArtifacts/fileHashes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/.gradle/2.4/taskArtifacts/fileHashes.bin -------------------------------------------------------------------------------- /android/.gradle/2.4/taskArtifacts/fileSnapshots.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/.gradle/2.4/taskArtifacts/fileSnapshots.bin -------------------------------------------------------------------------------- /android/.gradle/2.4/taskArtifacts/outputFileStates.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/.gradle/2.4/taskArtifacts/outputFileStates.bin -------------------------------------------------------------------------------- /android/.gradle/2.4/taskArtifacts/taskArtifacts.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/.gradle/2.4/taskArtifacts/taskArtifacts.bin -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | /** 4 | * The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets. 5 | * These basically call `react-native bundle` with the correct arguments during the Android build 6 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 7 | * bundle directly from the development server. Below you can see all the possible configurations 8 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 9 | * `apply from: "react.gradle"` line. 10 | * 11 | * project.ext.react = [ 12 | * // the name of the generated asset file containing your JS bundle 13 | * bundleAssetName: "index.android.bundle", 14 | * 15 | * // the entry file for bundle generation 16 | * entryFile: "index.android.js", 17 | * 18 | * // whether to bundle JS and assets in debug mode 19 | * bundleInDebug: false, 20 | * 21 | * // whether to bundle JS and assets in release mode 22 | * bundleInRelease: true, 23 | * 24 | * // the root of your project, i.e. where "package.json" lives 25 | * root: "../../", 26 | * 27 | * // where to put the JS bundle asset in debug mode 28 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 29 | * 30 | * // where to put the JS bundle asset in release mode 31 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 32 | * 33 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 34 | * // require('./image.png')), in debug mode 35 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 36 | * 37 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 38 | * // require('./image.png')), in release mode 39 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 40 | * 41 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 42 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 43 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 44 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 45 | * // for example, you might want to remove it from here. 46 | * inputExcludes: ["android/**", "ios/**"] 47 | * ] 48 | */ 49 | 50 | apply from: "react.gradle" 51 | 52 | android { 53 | compileSdkVersion 23 54 | buildToolsVersion "23.0.1" 55 | 56 | defaultConfig { 57 | applicationId "com.cnodejs" 58 | minSdkVersion 16 59 | targetSdkVersion 22 60 | versionCode 1 61 | versionName "1.0" 62 | ndk { 63 | abiFilters "armeabi-v7a", "x86" 64 | } 65 | } 66 | buildTypes { 67 | release { 68 | minifyEnabled false // Set this to true to enable Proguard 69 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 70 | } 71 | } 72 | } 73 | 74 | dependencies { 75 | compile fileTree(dir: "libs", include: ["*.jar"]) 76 | compile "com.android.support:appcompat-v7:23.0.1" 77 | compile "com.facebook.react:react-native:0.19.+" 78 | 79 | compile project(':ReactNativeBarcodescanner') 80 | compile project(':react-native-vector-icons') 81 | } 82 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | 30 | # Do not strip any method/class that is annotated with @DoNotStrip 31 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 32 | -keepclassmembers class * { 33 | @com.facebook.proguard.annotations.DoNotStrip *; 34 | } 35 | 36 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 37 | void set*(***); 38 | *** get*(); 39 | } 40 | 41 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 42 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 43 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 44 | -keepclassmembers class * { @com.facebook.react.uimanager.ReactProp ; } 45 | -keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup ; } 46 | 47 | # okhttp 48 | 49 | -keepattributes Signature 50 | -keepattributes *Annotation* 51 | -keep class com.squareup.okhttp.** { *; } 52 | -keep interface com.squareup.okhttp.** { *; } 53 | -dontwarn com.squareup.okhttp.** 54 | 55 | # okio 56 | 57 | -keep class sun.misc.Unsafe { *; } 58 | -dontwarn java.nio.file.* 59 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 60 | -dontwarn okio.** 61 | -------------------------------------------------------------------------------- /android/app/react.gradle: -------------------------------------------------------------------------------- 1 | import org.apache.tools.ant.taskdefs.condition.Os 2 | 3 | def config = project.hasProperty("react") ? project.react : []; 4 | 5 | def bundleAssetName = config.bundleAssetName ?: "index.android.bundle" 6 | def entryFile = config.entryFile ?: "index.android.js" 7 | 8 | // because elvis operator 9 | def elvisFile(thing) { 10 | return thing ? file(thing) : null; 11 | } 12 | 13 | def reactRoot = elvisFile(config.root) ?: file("../../") 14 | def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"] 15 | 16 | void runBefore(String dependentTaskName, Task task) { 17 | Task dependentTask = tasks.findByPath(dependentTaskName); 18 | if (dependentTask != null) { 19 | dependentTask.dependsOn task 20 | } 21 | } 22 | 23 | gradle.projectsEvaluated { 24 | // Grab all build types and product flavors 25 | def buildTypes = android.buildTypes.collect { type -> type.name } 26 | def productFlavors = android.productFlavors.collect { flavor -> flavor.name } 27 | 28 | // When no product flavors defined, use empty 29 | if (!productFlavors) productFlavors.add('') 30 | 31 | productFlavors.each { productFlavorName -> 32 | buildTypes.each { buildTypeName -> 33 | // Create variant and source names 34 | def sourceName = "${buildTypeName}" 35 | def targetName = "${sourceName.capitalize()}" 36 | if (productFlavorName) { 37 | sourceName = "${productFlavorName}${targetName}" 38 | } 39 | 40 | // React js bundle directories 41 | def jsBundleDirConfigName = "jsBundleDir${targetName}" 42 | def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?: 43 | file("$buildDir/intermediates/assets/${sourceName}") 44 | 45 | def resourcesDirConfigName = "jsBundleDir${targetName}" 46 | def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?: 47 | file("$buildDir/intermediates/res/merged/${sourceName}") 48 | def jsBundleFile = file("$jsBundleDir/$bundleAssetName") 49 | 50 | // Bundle task name for variant 51 | def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets" 52 | 53 | def currentBundleTask = tasks.create( 54 | name: bundleJsAndAssetsTaskName, 55 | type: Exec) { 56 | group = "react" 57 | description = "bundle JS and assets for ${targetName}." 58 | 59 | // Create dirs if they are not there (e.g. the "clean" task just ran) 60 | doFirst { 61 | jsBundleDir.mkdirs() 62 | resourcesDir.mkdirs() 63 | } 64 | 65 | // Set up inputs and outputs so gradle can cache the result 66 | inputs.files fileTree(dir: reactRoot, excludes: inputExcludes) 67 | outputs.dir jsBundleDir 68 | outputs.dir resourcesDir 69 | 70 | // Set up the call to the react-native cli 71 | workingDir reactRoot 72 | 73 | // Set up dev mode 74 | def devEnabled = !targetName.toLowerCase().contains("release") 75 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 76 | commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}", 77 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir 78 | } else { 79 | commandLine "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}", 80 | "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir 81 | } 82 | 83 | enabled config."bundleIn${targetName}" ?: targetName.toLowerCase().contains("release") 84 | } 85 | 86 | // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process 87 | currentBundleTask.dependsOn("merge${targetName}Resources") 88 | currentBundleTask.dependsOn("merge${targetName}Assets") 89 | 90 | runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask) 91 | runBefore("processX86${targetName}Resources", currentBundleTask) 92 | runBefore("processUniversal${targetName}Resources", currentBundleTask) 93 | runBefore("process${targetName}Resources", currentBundleTask) 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /android/app/src/main/assets/Fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/assets/Fonts/Entypo.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/Fonts/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/assets/Fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/Fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/assets/Fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/Fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/assets/Fonts/Foundation.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/Fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/assets/Fonts/Ionicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/Fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/assets/Fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/Fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/assets/Fonts/Octicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/Fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/assets/Fonts/Zocial.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/Fonts/materialdesignicons-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/assets/Fonts/materialdesignicons-webfont.ttf -------------------------------------------------------------------------------- /android/app/src/main/java/com/cnodejs/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.cnodejs; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.KeyEvent; 6 | 7 | import com.facebook.react.LifecycleState; 8 | import com.facebook.react.ReactInstanceManager; 9 | import com.facebook.react.ReactRootView; 10 | import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; 11 | import com.facebook.react.shell.MainReactPackage; 12 | import com.facebook.soloader.SoLoader; 13 | 14 | import com.eguma.barcodescanner.BarcodeScanner; 15 | import com.oblador.vectoricons.VectorIconsPackage; 16 | 17 | public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { 18 | 19 | private ReactInstanceManager mReactInstanceManager; 20 | private ReactRootView mReactRootView; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | mReactRootView = new ReactRootView(this); 26 | 27 | mReactInstanceManager = ReactInstanceManager.builder() 28 | .setApplication(getApplication()) 29 | .setBundleAssetName("index.android.bundle") 30 | .setJSMainModuleName("index.android") 31 | .addPackage(new MainReactPackage()) 32 | 33 | .addPackage(new BarcodeScanner()) 34 | .addPackage(new VectorIconsPackage()) 35 | 36 | .setUseDeveloperSupport(BuildConfig.DEBUG) 37 | .setInitialLifecycleState(LifecycleState.RESUMED) 38 | .build(); 39 | 40 | mReactRootView.startReactApplication(mReactInstanceManager, "cnodejs", null); 41 | 42 | setContentView(mReactRootView); 43 | } 44 | 45 | @Override 46 | public boolean onKeyUp(int keyCode, KeyEvent event) { 47 | if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { 48 | mReactInstanceManager.showDevOptionsDialog(); 49 | return true; 50 | } 51 | return super.onKeyUp(keyCode, event); 52 | } 53 | 54 | @Override 55 | public void onBackPressed() { 56 | if (mReactInstanceManager != null) { 57 | mReactInstanceManager.onBackPressed(); 58 | } else { 59 | super.onBackPressed(); 60 | } 61 | } 62 | 63 | @Override 64 | public void invokeDefaultOnBackPressed() { 65 | super.onBackPressed(); 66 | } 67 | 68 | @Override 69 | protected void onPause() { 70 | super.onPause(); 71 | 72 | if (mReactInstanceManager != null) { 73 | mReactInstanceManager.onPause(); 74 | } 75 | } 76 | 77 | @Override 78 | protected void onResume() { 79 | super.onResume(); 80 | 81 | if (mReactInstanceManager != null) { 82 | mReactInstanceManager.onResume(this, this); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_create_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/ic_create_black_48dp.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_menu_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/ic_menu_black_24dp.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_settings_black_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/ic_settings_black_48dp.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launcher_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/launcher_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/plus_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/plus_dark.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/plus_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/plus_white.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/uie_comment_highlighted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/uie_comment_highlighted.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/uie_comment_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/uie_comment_normal.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/uie_thumb_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/uie_thumb_normal.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/uie_thumb_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/app/src/main/res/drawable/uie_thumb_selected.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | cnodejs 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'cnodejs' 2 | 3 | include ':app' 4 | 5 | include ':ReactNativeBarcodescanner' 6 | project(':ReactNativeBarcodescanner').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-barcodescanner/android') 7 | 8 | include ':react-native-vector-icons' 9 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') -------------------------------------------------------------------------------- /androidApp/actions/ActionTypes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/10/15. 3 | */ 4 | 5 | exports.LOAD_CONFIG_SUCCESS='LOAD_CONFIG_SUCCESS' 6 | exports.INIT_CONFIG_SUCCESS='INIT_CONFIG_SUCCESS' 7 | exports.SET_CONFIG_SUCCESS='SET_CONFIG_SUCCESS' 8 | exports.RESTORE_CONFIG_SUCCESS='RESTORE_CONFIG_SUCCESS' 9 | 10 | exports.LOAD_USER_SUCCESS = 'LOAD_USER_SUCCESS' 11 | exports.LOAD_USER_FAILED='LOAD_USER_FAILED' 12 | exports.LOGOUT='LOGOUT' 13 | 14 | exports.LOAD_TOKEN_SUCCESS='LOAD_TOKEN_SUCCESS' 15 | exports.CHECK_TOKEN_SUCCESS = 'CHECK_TOKEN_SUCCESS' 16 | exports.CHECK_TOKEN_FAILED = 'CHECK_TOKEN_FAILED' 17 | 18 | exports.UP_COMMENT_SUCCESS='UP_COMMENT_SUCCESS' 19 | exports.UP_COMMENT_FAILED='UP_COMMENT_FAILED' 20 | exports.LOAD_USERID_SUCCESS='LOAD_USERID_SUCCESS' 21 | 22 | exports.REPLY_SUCCESS='REPLY_SUCCESS' 23 | exports.REPLY_SET_FALSE='REPLY_SET_FALSE' 24 | 25 | exports.PUBLISH_SUCCESS='PUBLISH_SUCCESS' 26 | exports.PUBLISH_SET_FALSE='PUBLISH_SET_FALSE' 27 | 28 | exports.GET_USER = 'GET_USER' 29 | 30 | 31 | exports.GET_LOGIN_USER_FROM_STORAGE = 'GET_LOGIN_USER_FROM_STORAGE' 32 | exports.GET_USER_FROM_STORAGE_FAILED = 'GET_USER_FROM_STORAGE_FAILED' 33 | exports.FETCH_USER = 'FETCH_USER' 34 | 35 | exports.LOGIN_SUCCESS = 'LOGIN_SUCCESS' 36 | exports.QR_SUCCESS = 'QR_SUCCESS' 37 | 38 | exports.CLEAR='CLEAR' 39 | 40 | 41 | exports.GET_UNREAD_MESSAGE_COUNT_SUCCESS = 'GET_UNREAD_MESSAGE_COUNT_SUCCESS' 42 | exports.GET_MESSAGES = 'GET_MESSAGES' 43 | exports.FETCH_MESSAGES_FAILED = 'FETCH_MESSAGES_FAILED' 44 | exports.FETCH_MESSAGES_REQUEST = 'FETCH_MESSAGES_REQUEST' 45 | exports.FETCH_MESSAGES_SUCCESS = 'FETCH_MESSAGES_SUCCESS' 46 | exports.MARK_AS_READ_SUCCESS = 'MARK_AS_READ_SUCCESS' 47 | exports.MARK_AS_READ_FAILED = 'MARK_AS_READ_FAILED' 48 | exports.MARK_AS_READ_REQUEST = 'MARK_AS_READ_REQUEST' 49 | 50 | 51 | exports.GET_ALL_TOPICS_FROM_STORAGE = 'GET_ALL_TOPICS_FROM_STORAGE' 52 | exports.FETCH_TOPICS_BY_TAB_REQUEST = 'FETCH_TOPICS_BY_TAB_REQUEST' 53 | exports.FETCH_TOPICS_BY_TAB_SUCCESS = 'FETCH_TOPICS_BY_TAB_SUCCESS' 54 | exports.FETCH_TOPICS_BY_TAB_FAILED = 'FETCH_TOPICS_BY_TAB_FAILED' 55 | 56 | 57 | exports.GET_TOPICS = 'GET_TOPICS' 58 | exports.UPDATE_TOPICS = 'UPDATE_TOPICS' 59 | 60 | -------------------------------------------------------------------------------- /androidApp/actions/HomeActions.js: -------------------------------------------------------------------------------- 1 | var types = require('./ActionTypes') 2 | var UserService = require('../services/UserService') 3 | var window = require('../util/window') 4 | import {configService} from "../services/ConfigService" 5 | 6 | exports.loadConfig=function loadConfig(){ 7 | return dispatch=> { 8 | configService.loadConfig() 9 | .then(results=> { 10 | dispatch({ 11 | type: types.LOAD_CONFIG_SUCCESS, 12 | results: results 13 | }) 14 | }) 15 | .catch(err=> { 16 | 17 | }) 18 | .done() 19 | } 20 | } 21 | 22 | exports.initConfig=function initConfig(){ 23 | return dispatch=> { 24 | configService.initConfig() 25 | .then(results=> { 26 | dispatch({ 27 | type: types.INIT_CONFIG_SUCCESS, 28 | results: results 29 | }) 30 | }) 31 | .catch(err=> { 32 | 33 | }) 34 | .done() 35 | } 36 | } 37 | 38 | exports.setConfig=function setConfig(value){ 39 | return dispatch=> { 40 | configService.setConfig(value) 41 | .then(results=> { 42 | dispatch({ 43 | type: types.SET_CONFIG_SUCCESS, 44 | results: results 45 | }) 46 | }) 47 | .catch(err=> { 48 | 49 | }) 50 | .done() 51 | } 52 | } 53 | 54 | exports.restoreConfig=function restoreConfig(value){ 55 | return dispatch=> { 56 | configService.restoreConfig() 57 | .then(results=> { 58 | dispatch({ 59 | type: types.RESTORE_CONFIG_SUCCESS, 60 | results: results 61 | }) 62 | }) 63 | .catch(err=> { 64 | 65 | }) 66 | .done() 67 | } 68 | } 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /androidApp/actions/MessageActions.js: -------------------------------------------------------------------------------- 1 | var types = require('./ActionTypes') 2 | var MessageService = require('../services/MessageService') 3 | 4 | 5 | var window = require('../util/window') 6 | 7 | 8 | function getMessages(messages) { 9 | return { 10 | type: types.GET_MESSAGES, 11 | hasRead: messages.has_read_messages, 12 | hasNotRead: messages.hasnot_read_messages, 13 | isLoading: true 14 | } 15 | } 16 | 17 | function fetchMessagesRequest() { 18 | return { 19 | type: types.FETCH_MESSAGES_REQUEST, 20 | isLoading: true 21 | } 22 | } 23 | 24 | function fetchMessagesSuccess(messages) { 25 | return { 26 | type: types.FETCH_MESSAGES_SUCCESS, 27 | isLoading: false, 28 | hasRead: messages.has_read_messages, 29 | hasNotRead: messages.hasnot_read_messages, 30 | } 31 | } 32 | 33 | function fetchMessagesFailed(err) { 34 | return { 35 | type: types.FETCH_MESSAGES_FAILED, 36 | isLoading: false, 37 | err: err 38 | } 39 | } 40 | 41 | exports.getUnreadMessageCount = function (token) { 42 | return dispatch=> { 43 | MessageService.req.getUnreadMessageCount(token) 44 | .then(count=> { 45 | dispatch({ 46 | type: types.GET_UNREAD_MESSAGE_COUNT_SUCCESS, 47 | count: count 48 | }) 49 | }) 50 | .catch(err=> { 51 | console.warn(err) 52 | }) 53 | .done() 54 | } 55 | } 56 | 57 | 58 | exports.getMessages = function (token) { 59 | return dispatch=> { 60 | 61 | dispatch(fetchMessagesRequest()) 62 | 63 | MessageService.storage.get() 64 | .then(messages=> { 65 | if (messages) { 66 | dispatch(getMessages(messages)) 67 | } 68 | return MessageService.req.get(token) 69 | }) 70 | .then(messages=> { 71 | if (messages) { 72 | dispatch(fetchMessagesSuccess(messages)) 73 | } 74 | else { 75 | throw 'FETCH_MESSAGES_FAILED' 76 | } 77 | }) 78 | .catch(err=> { 79 | dispatch(fetchMessagesFailed(err)) 80 | }) 81 | .done() 82 | } 83 | } 84 | 85 | 86 | exports.fetchMessages = function (token) { 87 | return dispatch=> { 88 | dispatch(fetchMessagesRequest()) 89 | 90 | MessageService.req.get(token) 91 | .then(messages=> { 92 | if (messages) { 93 | dispatch(fetchMessagesSuccess(messages)) 94 | } 95 | else { 96 | throw 'FETCH_MESSAGES_FAILED' 97 | } 98 | }) 99 | .catch(err=> { 100 | dispatch(fetchMessagesFailed(err)) 101 | }) 102 | .done() 103 | } 104 | } 105 | 106 | 107 | exports.markAsRead = function (token) { 108 | return dispatch=> { 109 | dispatch({ 110 | type: types.MARK_AS_READ_REQUEST 111 | }) 112 | MessageService.req.markAsRead(token) 113 | .then(()=> { 114 | dispatch({ 115 | type: types.MARK_AS_READ_SUCCESS 116 | }) 117 | window.alert('已全部标记为已读!') 118 | }) 119 | .catch(()=> { 120 | dispatch({ 121 | type: types.MARK_AS_READ_FAILED 122 | }) 123 | window.alert('标记失败!') 124 | }) 125 | .done() 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /androidApp/actions/TopicActions.js: -------------------------------------------------------------------------------- 1 | var types = require('./ActionTypes') 2 | var TopicService = require('../services/TopicService') 3 | 4 | 5 | exports.getAllTopicsFromStorage = function () { 6 | return dispatch=> { 7 | TopicService.storage.getAll() 8 | .then(results=> { 9 | dispatch({ 10 | type: types.GET_ALL_TOPICS_FROM_STORAGE, 11 | results: results 12 | }) 13 | }) 14 | .catch(err=> { 15 | 16 | }) 17 | .done() 18 | } 19 | } 20 | 21 | 22 | exports.getTopicsByTab = function (topics, tab) { 23 | return { 24 | type: types.GET_TOPICS, 25 | topics: topics, 26 | tab: tab 27 | } 28 | } 29 | 30 | 31 | exports.updateTopicsByTab = function (topics, tab) { 32 | return { 33 | type: types.UPDATE_TOPICS, 34 | topics: topics, 35 | tab: tab 36 | } 37 | } 38 | 39 | 40 | exports.upComment=function upComment(replyId,token){ 41 | return dispatch=>{ 42 | TopicService.req.upComment(replyId,token) 43 | .then(results=> { 44 | dispatch({ 45 | type: types.UP_COMMENT_SUCCESS, 46 | replyId:replyId, 47 | isUp:results 48 | }) 49 | }) 50 | .catch(err=> { 51 | 52 | }) 53 | } 54 | } 55 | 56 | exports.setUpSuccessFalse=function setCommentFalse(){ 57 | return { 58 | type: types.UP_COMMENT_FAILED 59 | } 60 | } 61 | 62 | exports.reply=function reply(topicId, content, token, replyId) 63 | { 64 | return dispatch=>{ 65 | TopicService.req.reply(topicId, content, token, replyId) 66 | .then(results=> { 67 | dispatch 68 | ({ 69 | type: types.REPLY_SUCCESS, 70 | }) 71 | dispatch 72 | ({ 73 | type: types.REPLY_SET_FALSE, 74 | }) 75 | }) 76 | .catch(err=> { 77 | 78 | }) 79 | } 80 | } 81 | 82 | exports.publish=function publish(title, tab, content, token) 83 | { 84 | return dispatch=>{ 85 | TopicService.req.publish(title, tab, content, token) 86 | .then(results=> { 87 | dispatch 88 | ({ 89 | type: types.PUBLISH_SUCCESS, 90 | }) 91 | dispatch 92 | ({ 93 | type: types.PUBLISH_SET_FALSE, 94 | }) 95 | }) 96 | .catch(err=> { 97 | console.warn(err) 98 | }) 99 | } 100 | } -------------------------------------------------------------------------------- /androidApp/actions/UserActions.js: -------------------------------------------------------------------------------- 1 | var types = require('./ActionTypes') 2 | var UserService = require('../services/UserService') 3 | var TopicService = require('../services/TopicService') 4 | var MessageService = require('../services/MessageService') 5 | var Storage = require('../services/Storage') 6 | import React,{DeviceEventEmitter} from "react-native" 7 | 8 | function getUser(user) { 9 | return { 10 | type: types.GET_USER, 11 | user: user 12 | } 13 | } 14 | 15 | exports.getLoginUserFromStorage = function () { 16 | return dispatch=> { 17 | var userTemp = {} 18 | UserService.storage.getUser() 19 | .then((user)=> { 20 | // console.log('haveLoadedUser'); 21 | if (user) { 22 | dispatch(getUser(user)) 23 | userTemp = user 24 | return UserService.req.getLoginUserInfo(user) 25 | } 26 | else { 27 | throw 'GET_LOGIN_USER_FROM_STORAGE_FAILED' 28 | } 29 | 30 | }) 31 | .then(userFetched=> { 32 | // console.log('fetchUser'); 33 | if (userFetched) { 34 | var userUpdated = Object.assign(userTemp, userFetched) 35 | UserService.storage.saveUser(userUpdated) 36 | dispatch(getUser(userTemp)) 37 | } 38 | }) 39 | .catch((err)=> { 40 | console.warn(err) 41 | }) 42 | .done() 43 | } 44 | } 45 | 46 | 47 | exports.fetchUser = function fetchUser(user) { 48 | return dispatch => { 49 | UserService.req.getLoginUserInfo(user) 50 | .then(userInfo=> { 51 | if (userInfo) { 52 | Object.assign(user, userInfo) 53 | UserService.storage.saveUser(user) 54 | dispatch(getUser(user)) 55 | } 56 | }) 57 | .catch(err=> { 58 | console.warn(err) 59 | }) 60 | .done() 61 | } 62 | } 63 | 64 | 65 | exports.checkToken = function (token) { 66 | return dispatch=> { 67 | UserService.req.checkToken(token) 68 | .then(user=> { 69 | return UserService.req.getLoginUserInfo(user) 70 | }) 71 | .then((userInfo)=> { 72 | if (userInfo) { 73 | // dispatch(getUser(userInfo)) 74 | dispatch({ 75 | type: types.CHECK_TOKEN_SUCCESS, 76 | userData:userInfo, 77 | accesstoken:token 78 | }) 79 | } 80 | else { 81 | throw 'CHECK_TOKEN_FAILED' 82 | } 83 | }) 84 | .catch(function (err) { 85 | dispatch({ 86 | type: types.CHECK_TOKEN_FAILED, 87 | err: err 88 | }) 89 | }) 90 | .done() 91 | } 92 | } 93 | 94 | exports.logout = function () { 95 | UserService.storage.logout() 96 | return { 97 | type: types.LOGOUT 98 | } 99 | } 100 | 101 | 102 | exports.clear = function () { 103 | TopicService.storage.remove() 104 | MessageService.storage.remove() 105 | return { 106 | type: types.CLEAR 107 | } 108 | } 109 | 110 | exports.loadAccessToken=function(){ 111 | return dispatch=>{ 112 | UserService.req.loadToken() 113 | .then(results=>{ 114 | dispatch({ 115 | type: types.LOAD_TOKEN_SUCCESS, 116 | accesstoken:results 117 | }) 118 | }) 119 | .catch(err=>{ 120 | 121 | }) 122 | .done() 123 | } 124 | } 125 | 126 | exports.loadUserId=function(){ 127 | return dispatch=>{ 128 | UserService.req.loadUserId() 129 | .then(results=>{ 130 | dispatch({ 131 | type: types.LOAD_USERID_SUCCESS, 132 | userId:results 133 | }) 134 | }) 135 | .catch(err=>{ 136 | 137 | }) 138 | .done() 139 | } 140 | } 141 | 142 | exports.loadUser=function loadUser(){ 143 | return dispatch=> { 144 | UserService.req.loadUser() 145 | .then(results=> { 146 | if(results) 147 | { 148 | dispatch({ 149 | type: types.LOAD_USER_SUCCESS, 150 | results: results 151 | }) 152 | } 153 | else{ 154 | dispatch({ 155 | type: types.LOAD_USER_FAILED, 156 | results: results 157 | }) 158 | } 159 | 160 | }) 161 | .catch(err=> { 162 | 163 | }) 164 | .done() 165 | } 166 | } 167 | 168 | -------------------------------------------------------------------------------- /androidApp/actions/index.js: -------------------------------------------------------------------------------- 1 | var user = require('./UserActions') 2 | var home = require('./HomeActions') 3 | var message = require('./MessageActions') 4 | var topic = require('./TopicActions') 5 | 6 | var actions = {} 7 | 8 | Object.assign(actions, user, home, message, topic) 9 | 10 | module.exports = actions 11 | -------------------------------------------------------------------------------- /androidApp/components/BarCodeModule/BarCode.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/11/20. 3 | */ 4 | 'use strict'; 5 | 6 | var React = require('react-native'); 7 | var { 8 | Component 9 | } = React; 10 | 11 | var BarCodeNative=require("react-native-barcodescanner") 12 | 13 | class BarCode extends Component { 14 | 15 | render() { 16 | return ( 17 | 18 | 19 | 20 | ); 21 | } 22 | } 23 | 24 | module.exports = BarCode; -------------------------------------------------------------------------------- /androidApp/components/BarCodeModule/BarCode.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/11/20. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component 10 | } = React; 11 | 12 | var BarCodeNative=require("react-native-camera") 13 | 14 | class BarCode extends Component { 15 | 16 | render() { 17 | return ( 18 | 19 | 20 | 21 | ); 22 | } 23 | } 24 | 25 | module.exports = BarCode; 26 | -------------------------------------------------------------------------------- /androidApp/components/DefaultTabBar.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react-native'); 4 | var { 5 | Dimensions, 6 | StyleSheet, 7 | Text, 8 | TouchableOpacity, 9 | View, 10 | Animated, 11 | } = React; 12 | 13 | var deviceWidth = Dimensions.get('window').width; 14 | 15 | var styles = StyleSheet.create({ 16 | tab: { 17 | flex: 1, 18 | alignItems: 'center', 19 | justifyContent: 'center', 20 | paddingBottom: 10, 21 | }, 22 | 23 | tabs: { 24 | backgroundColor:'#2C2C2C', 25 | height: 50, 26 | flexDirection: 'row', 27 | justifyContent: 'space-around', 28 | //marginTop: 20, 29 | borderWidth: 1, 30 | borderTopWidth: 0, 31 | borderLeftWidth: 0, 32 | borderRightWidth: 0, 33 | borderBottomColor: '#ccc', 34 | }, 35 | }); 36 | 37 | var DefaultTabBar = React.createClass({ 38 | propTypes: { 39 | goToPage: React.PropTypes.func, 40 | activeTab: React.PropTypes.number, 41 | tabs: React.PropTypes.array 42 | }, 43 | 44 | renderTabOption(name, page) { 45 | var isTabActive = this.props.activeTab === page; 46 | 47 | return ( 48 | this.props.goToPage(page)}> 49 | 50 | {name} 51 | 52 | 53 | ); 54 | }, 55 | 56 | render() { 57 | var numberOfTabs = this.props.tabs.length; 58 | var tabUnderlineStyle = { 59 | position: 'absolute', 60 | width: deviceWidth / numberOfTabs, 61 | height: 3, 62 | backgroundColor: 'gray', 63 | bottom: 0, 64 | }; 65 | 66 | var left = this.props.scrollValue.interpolate({ 67 | inputRange: [0, 1], outputRange: [0, deviceWidth / numberOfTabs] 68 | }); 69 | 70 | return ( 71 | 72 | {this.props.tabs.map((tab, i) => this.renderTabOption(tab, i))} 73 | 74 | 75 | ); 76 | }, 77 | }); 78 | 79 | module.exports = DefaultTabBar; 80 | -------------------------------------------------------------------------------- /androidApp/components/Error.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/12/21. 3 | */ 4 | 5 | import React,{ 6 | Component,Image,View,Text 7 | } from "react-native" 8 | 9 | class Error extends Component{ 10 | constructor(porps) { 11 | super(porps); 12 | } 13 | _renderText(){ 14 | const {text}=this.props 15 | if(text) 16 | { 17 | return( 18 | 19 | {text} 20 | 21 | ) 22 | } 23 | } 24 | render() { 25 | return( 26 | 27 | 28 | 29 | {this._renderText()} 30 | 31 | 32 | ) 33 | } 34 | } 35 | 36 | module.exports=Error -------------------------------------------------------------------------------- /androidApp/components/ImageCircle.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/androidApp/components/ImageCircle.js -------------------------------------------------------------------------------- /androidApp/components/Loading.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/12/1. 3 | */ 4 | 5 | import React,{ 6 | Component,Image,View 7 | } from "react-native" 8 | 9 | class Loading extends Component{ 10 | constructor(porps) { 11 | super(porps); 12 | } 13 | render() { 14 | return( 15 | 16 | 17 | ) 18 | } 19 | } 20 | 21 | module.exports=Loading -------------------------------------------------------------------------------- /androidApp/components/MessageListView.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/17. 3 | */ 4 | 5 | var React = require('react-native') 6 | var moment = require('moment') 7 | 8 | var MessageService = require('../services/MessageService') 9 | var MessageRow = require('./rowModule/MessageRow') 10 | 11 | var window = require('../util/window') 12 | 13 | var { width, height } = window.get() 14 | 15 | var { 16 | View, 17 | StyleSheet, 18 | ScrollView, 19 | Component, 20 | Text, 21 | Image, 22 | ListView, 23 | TouchableHighlight, 24 | TouchableOpacity, 25 | InteractionManager 26 | } = React 27 | 28 | import Loading from "./Loading.js"; 29 | 30 | class MessageListView extends Component { 31 | constructor(porps) { 32 | super(porps) 33 | var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) 34 | this.page=1 35 | this.data=[] 36 | this.state = { 37 | ds: ds.cloneWithRows(this.data), 38 | isLoading: true, 39 | } 40 | } 41 | 42 | _genRows(){ 43 | MessageService.req.get(this.props.state.userState.accesstoken) 44 | .then(messages=> { 45 | var newData=this.data.concat(this.props.isRead ? messages.has_read_messages : messages.hasnot_read_messages) 46 | this.setState({ 47 | isLoading: false, 48 | ds: this.state.ds.cloneWithRows(newData), 49 | }) 50 | this.data=newData 51 | }) 52 | .catch(err=> { 53 | console.warn(err) 54 | }) 55 | .done((err)=> { 56 | this.setState({ 57 | isLoading: false, 58 | err: err 59 | }) 60 | }) 61 | } 62 | 63 | componentDidMount() { 64 | InteractionManager.runAfterInteractions(() => { 65 | this.setState({isReady: true}); 66 | this._genRows() 67 | }) 68 | } 69 | 70 | _renderRow(message, sectionId, rowId, highlightRow) { 71 | return ( 72 | this.listRows[rowId.toString()]=view} 74 | message={message} 75 | router={this.props.router} 76 | > 77 | 78 | ) 79 | } 80 | 81 | _onEndReached() 82 | { 83 | this.page=this.page+1; 84 | this._genRows(); 85 | } 86 | render() { 87 | if (this.state.isLoading) { 88 | return ( 89 | 90 | 91 | 92 | 93 | ) 94 | } 95 | return ( 96 | {this._listView = view}} 98 | style={styles.listStyle} 99 | //onScroll={()=>onScroll()} 100 | showsVerticalScrollIndicator={true} 101 | initialListSize={10} 102 | pagingEnabled={false} 103 | removeClippedSubviews={true} 104 | dataSource={this.state.ds} 105 | renderRow={this._renderRow.bind(this)} 106 | //onEndReached={this._onEndReached.bind(this)} 107 | onEndReachedThreshold={20} 108 | /> 109 | ) 110 | } 111 | } 112 | 113 | 114 | var styles = StyleSheet.create({ 115 | "listStyle":{ 116 | backgroundColor:'rgba(255,255,255,1)', 117 | flex:1 118 | } 119 | }) 120 | 121 | module.exports = MessageListView; 122 | -------------------------------------------------------------------------------- /androidApp/components/PickerModule/Picker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2016/1/26. 3 | */ 4 | 5 | import React,{ 6 | Component, 7 | Picker, 8 | PickerIOS, 9 | Platform 10 | } from "react-native" 11 | 12 | const PickerNative=Platform.OS=="ios"?PickerIOS:Picker; 13 | const Item =PickerNative.Item; 14 | 15 | class PickerModule extends Component{ 16 | constructor(porps) { 17 | super(porps); 18 | this.state={ 19 | selectIndex:0 20 | } 21 | this.onSelect=this.onSelect.bind(this) 22 | } 23 | 24 | onSelect(index){ 25 | this.setState({ 26 | selectIndex:index 27 | }) 28 | this.props.valueChange && this.props.valueChange(index) 29 | } 30 | 31 | render() 32 | { 33 | const {valueArray,...props}=this.props 34 | return( 35 | 36 | {valueArray.map((value,i) => ( 37 | 41 | ))} 42 | 43 | ) 44 | } 45 | } 46 | 47 | module.exports = PickerModule; -------------------------------------------------------------------------------- /androidApp/components/ScrollableTabView.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author brentvatne 3 | * @github https://github.com/brentvatne/react-native-scrollable-tab-view 4 | * @name CustomTabBar 5 | * @added marsprince 6 | */ 7 | 'use strict'; 8 | 9 | var React = require('react-native'); 10 | 11 | var deviceWidth = require('Dimensions').get('window').width; 12 | var { 13 | Component, 14 | StyleSheet, 15 | Text, 16 | View, 17 | ScrollView, 18 | Platform, 19 | ToastAndroid 20 | } = React; 21 | 22 | var TopicListView=require('./TopicListView'); 23 | //var ScrollableTabView = Platform.OS=="android"?require("./ScrollableTabViewAndroid/ViewPager"):require('react-native-scrollable-tab-view'); 24 | var ScrollableTabView=require('react-native-scrollable-tab-view') 25 | var DefaultTabBar=require("./DefaultTabBar") 26 | 27 | var cnodeUtil=require('../util/cnodeUtil') 28 | 29 | class ScrollableTabViewExample extends Component{ 30 | constructor(porps) { 31 | super(porps) 32 | this.data=[ 33 | {tab:""}, 34 | {tab:"share"}, 35 | {tab:"ask"}, 36 | {tab:"job"}, 37 | ]; 38 | this.state={ 39 | tabData:this.data, 40 | selectedTab:0, 41 | } 42 | } 43 | 44 | _renderTab() 45 | { 46 | return this.state.tabData.map((tab,i) => { 47 | if(!tab['tab']) 48 | { 49 | return ( 50 | 51 | 52 | 53 | 54 | 55 | ) 56 | } 57 | else 58 | { 59 | return ( 60 | 61 | 62 | 63 | 64 | 65 | ) 66 | } 67 | 68 | }) 69 | } 70 | 71 | _onChangeTab({i,ref}){ 72 | setTimeout(()=>{ 73 | this.setState({ 74 | selectedTab:i 75 | }) 76 | },400) 77 | } 78 | 79 | render() { 80 | 81 | return ( 82 | 83 | } style={{flex:1}} > 84 | {this._renderTab()} 85 | 86 | 87 | ); 88 | } 89 | }; 90 | 91 | var styles = StyleSheet.create({ 92 | container: { 93 | flex: 1, 94 | }, 95 | tabView: { 96 | flex: 1, 97 | backgroundColor: 'rgba(0,0,0,0.01)', 98 | }, 99 | }); 100 | 101 | module.exports=ScrollableTabViewExample -------------------------------------------------------------------------------- /androidApp/components/ScrollableTabViewAndroid/DimensionsHelper.js: -------------------------------------------------------------------------------- 1 | 'use-strict' 2 | 3 | var React = require('react-native'); 4 | var { 5 | Dimensions 6 | } = React; 7 | 8 | var DimensionsHelper = { 9 | init : function() { 10 | this.SCREEN_WIDTH = Dimensions.get("window").width; 11 | this.SCREEN_HEIGHT = Dimensions.get("window").height; 12 | } 13 | } 14 | DimensionsHelper.init(); 15 | module.exports = DimensionsHelper -------------------------------------------------------------------------------- /androidApp/components/ScrollableTabViewAndroid/ViewPager.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react-native'); 4 | var { 5 | View, 6 | ViewPagerAndroid, 7 | Text 8 | } = React; 9 | 10 | var ViewPagerTabs = require("./ViewPagerTabs"); 11 | var ViewPagerDots = require("./ViewPagerDots"); 12 | var DimensionsHelper = require("./DimensionsHelper"); 13 | 14 | var ViewPager = React.createClass({ 15 | componentDidMount(){ 16 | 17 | }, 18 | 19 | getDefaultProps: function(){ 20 | }, 21 | 22 | getInitialState: function(){ 23 | return { 24 | activeTab:0 25 | } 26 | }, 27 | 28 | goToPage: function(page){ 29 | 30 | this.setState({activeTab: page}); 31 | this.viewPager.setPage(page); 32 | this.props.onChangeTab && this.props.onChangeTab({ 33 | i:page, 34 | ref: this.props.children[page] 35 | }); 36 | }, 37 | 38 | onPageScroll: function(e){ 39 | this.tabs.onPageScroll(e); 40 | }, 41 | 42 | onPageSelected: function(e){ 43 | this.tabs.onPageSelected(e); 44 | this.props.onChangeTab && this.props.onChangeTab({ 45 | i:e.nativeEvent.position, 46 | ref: this.props.children[e.nativeEvent.position] 47 | }); 48 | }, 49 | 50 | renderTabBar() { 51 | if (this.props.bar === 'tabs') { 52 | return {return this.viewPager}} ref={(comp) => {this.tabs = comp}} />;; 53 | } else { 54 | return {return this.viewPager}} ref={(comp) => {this.tabs = comp}} />;; 55 | } 56 | }, 57 | 58 | render() { 59 | return ( 60 | 61 | {this.props.position == 'top' ? this.renderTabBar() : null} 62 | {this.viewPager = comp}} 63 | onPageScroll={this.onPageScroll} 64 | onPageSelected={this.onPageSelected} 65 | style={{ 66 | flexDirection:'row', 67 | backgroundColor:'#ccc', 68 | height: this.props.height || DimensionsHelper.SCREEN_HEIGHT, 69 | width: this.props.width || DimensionsHelper.SCREEN_WIDTH 70 | }} 71 | > 72 | {this.props.children} 73 | 74 | {this.props.position == 'bottom' ? this.renderTabBar() : null} 75 | 76 | ); 77 | } 78 | }); 79 | 80 | 81 | 82 | module.exports = ViewPager; 83 | -------------------------------------------------------------------------------- /androidApp/components/ScrollableTabViewAndroid/ViewPagerDots.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react-native'); 4 | var { 5 | View, 6 | Text, 7 | ViewPagerAndroid, 8 | StyleSheet, 9 | TouchableOpacity 10 | } = React; 11 | var DimensionsHelper = require("./DimensionsHelper"); 12 | 13 | var ViewPagerDots = React.createClass({ 14 | 15 | getDefaultProps: function(){ 16 | }, 17 | 18 | getInitialState: function(){ 19 | return { activeTab:0 } 20 | }, 21 | 22 | // called from ViewPager 23 | onPageScroll: function(e){ 24 | this.setState({random:1}) 25 | }, 26 | 27 | // called from ViewPager 28 | onPageSelected: function(e){ 29 | this.setState({activeTab: e.nativeEvent.position}); 30 | }, 31 | 32 | // goto(2) 33 | goToPage: function(page){ 34 | console.log("goToPage", page); 35 | this.props.viewPager().setPage(page); 36 | this.setState({activeTab: page}); 37 | }, 38 | 39 | renderTab(child, page){ 40 | var isTabActive = this.state.activeTab === page; 41 | return ( 42 | this.goToPage(page)}> 43 | 44 | 45 | ) 46 | }, 47 | 48 | render() { 49 | return ( 50 | 51 | {this.props.children.map((child, i) => this.renderTab(child, i))} 52 | 53 | ); 54 | } 55 | }); 56 | 57 | var styles = StyleSheet.create({ 58 | dots: { 59 | height:40, 60 | flex:1, 61 | flexDirection: 'row', 62 | alignItems:'center', 63 | justifyContent: 'center' 64 | }, 65 | dot: { 66 | width: 10, 67 | height: 10, 68 | marginHorizontal: 3, 69 | borderRadius: 5, 70 | borderWidth: 1, 71 | borderColor: "#ccc", 72 | backgroundColor: "#fff" 73 | }, 74 | active: { 75 | backgroundColor: "#ccc" 76 | }, 77 | intactive: { 78 | backgroundColor: "#fff" 79 | } 80 | }); 81 | 82 | module.exports = ViewPagerDots; 83 | -------------------------------------------------------------------------------- /androidApp/components/ScrollableTabViewAndroid/ViewPagerTabs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require('react-native'); 4 | var { 5 | View, 6 | Text, 7 | ViewPagerAndroid, 8 | StyleSheet, 9 | TouchableOpacity 10 | } = React; 11 | var DimensionsHelper = require("./DimensionsHelper"); 12 | 13 | var ViewPagerTabs = React.createClass({ 14 | 15 | getDefaultProps: function(){ 16 | }, 17 | 18 | getInitialState: function(){ 19 | return { 20 | activeTab:0, 21 | left: 0 22 | } 23 | }, 24 | 25 | moveActiveLine:function(e){ 26 | var width = DimensionsHelper.SCREEN_WIDTH 27 | var tabWidth = width / this.props.children.length; 28 | var left = (tabWidth * (e.nativeEvent.offset || 0)) + (tabWidth * e.nativeEvent.position); 29 | if(!e.nativeEvent.position || left) this.setState({left: left}); 30 | }, 31 | 32 | // called from ViewPager 33 | onPageScroll: function(e){ 34 | this.moveActiveLine(e); 35 | }, 36 | 37 | // called from ViewPager 38 | onPageSelected: function(e){ 39 | // this.moveActiveLine(e); 40 | this.setState({activeTab: e.nativeEvent.position}); 41 | }, 42 | 43 | // goto(2) 44 | /* goToPage: function(page){ 45 | this.props.viewPager().setPage(page); 46 | this.setState({activeTab: page}); 47 | },*/ 48 | 49 | renderTab(child, page){ 50 | var isTabActive = this.state.activeTab === page; 51 | var textStyle = { 52 | color: isTabActive ? '#666' : '#999', 53 | fontWeight: isTabActive ? 'bold' : 'normal', 54 | flex:1 55 | } 56 | return ( 57 | this.props.goToPage(page)}> 63 | 64 | {child.props.tabLabel} 65 | 66 | 67 | ) 68 | }, 69 | 70 | render() { 71 | return ( 72 | 73 | {this.props.children.map((child, i) => this.renderTab(child, i))} 74 | {this.activeLine = comp}} 76 | style={[styles.activeLine, {left: this.state.left, width: DimensionsHelper.SCREEN_WIDTH/this.props.children.length}]} /> 77 | 78 | ); 79 | } 80 | }); 81 | 82 | var styles = StyleSheet.create({ 83 | tabs:{ 84 | flex: 1, 85 | flexDirection: 'row', 86 | alignItems: 'center', 87 | borderBottomWidth: 1, 88 | borderColor: '#eee', 89 | backgroundColor:'2C2C2C' 90 | }, 91 | tab:{ 92 | height: 35, 93 | paddingBottom: 5, 94 | justifyContent: 'center', 95 | alignItems: 'center' 96 | }, 97 | activeLine:{ 98 | height: 4, 99 | backgroundColor: '#999', 100 | position:'absolute', 101 | top: 32, 102 | left: 0 103 | } 104 | }) 105 | 106 | module.exports = ViewPagerTabs; 107 | -------------------------------------------------------------------------------- /androidApp/components/SwitchModule/Switch.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/4. 3 | */ 4 | 5 | import React,{ 6 | Component, 7 | SwitchAndroid 8 | } from "react-native" 9 | 10 | class Switch extends Component{ 11 | render() 12 | { 13 | return( 14 | 15 | 16 | ) 17 | } 18 | } 19 | 20 | module.exports = Switch; -------------------------------------------------------------------------------- /androidApp/components/SwitchModule/Switch.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/4. 3 | */ 4 | 5 | import React,{ 6 | Component, 7 | SwitchIOS 8 | } from "react-native" 9 | 10 | class Switch extends Component{ 11 | render() 12 | { 13 | return( 14 | 15 | 16 | ) 17 | } 18 | } 19 | 20 | module.exports = Switch; -------------------------------------------------------------------------------- /androidApp/components/ToolBar/BasicToolBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/11/16. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component, 10 | StyleSheet, 11 | Text, 12 | View, 13 | Image, 14 | TouchableHighlight 15 | } = React; 16 | 17 | var Icon = require('react-native-vector-icons/MaterialIcons'); 18 | 19 | var styles = StyleSheet.create({ 20 | navBar:{ 21 | backgroundColor: '#2C2C2C', 22 | height:56, 23 | flexDirection:"row", 24 | paddingLeft:10, 25 | }, 26 | text:{ 27 | flex:10, 28 | fontSize: 19, 29 | color: '#FFFFFF', 30 | marginTop:10, 31 | marginLeft:10, 32 | textAlign:'left', 33 | }, 34 | back:{ 35 | marginTop:7, 36 | } 37 | }); 38 | 39 | class NavigationTitleBar extends Component{ 40 | constructor(props) { 41 | super(props); 42 | } 43 | 44 | _onPress() 45 | { 46 | if (this.props.router && this.props.router.length > 1) { 47 | this.props.router.pop(); 48 | } 49 | } 50 | 51 | render() 52 | { 53 | return ( 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | {this.props.text} 63 | 64 | 65 | 66 | ) 67 | } 68 | } 69 | 70 | module.exports=NavigationTitleBar -------------------------------------------------------------------------------- /androidApp/components/ToolBar/MainScreenToolBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/11/24. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component, 10 | StyleSheet, 11 | Text, 12 | View, 13 | Image, 14 | TouchableHighlight 15 | } = React; 16 | 17 | var Icon = require('react-native-vector-icons/MaterialIcons'); 18 | 19 | var styles = StyleSheet.create({ 20 | navBar:{ 21 | backgroundColor: '#2C2C2C', 22 | height:56, 23 | flexDirection:"row", 24 | paddingLeft:10, 25 | paddingRight:10, 26 | }, 27 | text:{ 28 | flex:10, 29 | fontSize: 19, 30 | color: '#FFFFFF', 31 | marginTop:10, 32 | marginLeft:10, 33 | textAlign:'left', 34 | }, 35 | back:{ 36 | marginTop:7, 37 | }, 38 | write:{ 39 | marginTop:7, 40 | } 41 | }); 42 | 43 | class MainScreenToolBar extends Component{ 44 | constructor(props) { 45 | super(props); 46 | } 47 | 48 | _onPress() 49 | { 50 | if (this.props.router && this.props.router.length > 1) { 51 | this.props.router.pop(); 52 | } 53 | } 54 | 55 | _renderText(text) 56 | { 57 | return( 58 | 59 | {text} 60 | 61 | ) 62 | } 63 | 64 | render() 65 | { 66 | const {drawerOpen,writeTopic} =this.props 67 | return ( 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | {this.props.text ? this._renderText(this.props.text) : null} 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | ) 84 | } 85 | } 86 | 87 | module.exports=MainScreenToolBar -------------------------------------------------------------------------------- /androidApp/components/ToolBar/PublishToolBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/8. 3 | */ 4 | 5 | 6 | 'use strict'; 7 | 8 | var React = require('react-native'); 9 | var { 10 | Component, 11 | StyleSheet, 12 | Text, 13 | View, 14 | Image, 15 | TouchableHighlight, 16 | TouchableOpacity 17 | } = React; 18 | 19 | var Icon = require('react-native-vector-icons/MaterialIcons'); 20 | import PublishButton from '../buttonModule/PublishButton' 21 | 22 | var styles = StyleSheet.create({ 23 | navBar:{ 24 | backgroundColor: '#2C2C2C', 25 | height:56, 26 | flexDirection:"row", 27 | paddingLeft:10, 28 | }, 29 | text:{ 30 | flex:10, 31 | fontSize: 19, 32 | color: '#FFFFFF', 33 | marginTop:10, 34 | marginLeft:10, 35 | textAlign:'left', 36 | }, 37 | back:{ 38 | marginTop: 7, 39 | }, 40 | replyButton:{ 41 | flex:1, 42 | marginVertical:8, 43 | }, 44 | }); 45 | 46 | class PublishToolar extends Component{ 47 | constructor(props) { 48 | super(props); 49 | } 50 | 51 | _onPress() 52 | { 53 | if (this.props.router && this.props.router.length > 1) { 54 | this.props.router.pop(); 55 | } 56 | } 57 | 58 | render() 59 | { 60 | const {disabled,onPress} =this.props 61 | return ( 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {this.props.text} 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | ) 79 | } 80 | } 81 | 82 | module.exports=PublishToolar -------------------------------------------------------------------------------- /androidApp/components/ToolBar/TopicToolBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/12/16. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component, 10 | StyleSheet, 11 | Text, 12 | View, 13 | Image, 14 | TouchableHighlight 15 | } = React; 16 | 17 | var Icon = require('react-native-vector-icons/MaterialIcons'); 18 | 19 | var styles = StyleSheet.create({ 20 | navBar:{ 21 | backgroundColor: '#2C2C2C', 22 | height:56, 23 | flexDirection:"row", 24 | paddingLeft:10, 25 | }, 26 | text:{ 27 | flex:10, 28 | fontSize: 19, 29 | color: '#FFFFFF', 30 | marginTop:10, 31 | marginLeft:10, 32 | textAlign:'left', 33 | }, 34 | back:{ 35 | marginTop:7, 36 | } 37 | }); 38 | 39 | class TopicToolBar extends Component{ 40 | constructor(props) { 41 | super(props); 42 | } 43 | 44 | _onPress() 45 | { 46 | if (this.props.router && this.props.router.length > 1) { 47 | this.props.router.pop(); 48 | } 49 | } 50 | 51 | render() 52 | { 53 | return ( 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | {this.props.text} 63 | 64 | 65 | 66 | ) 67 | } 68 | } 69 | 70 | module.exports=TopicToolBar -------------------------------------------------------------------------------- /androidApp/components/TopicListView.js: -------------------------------------------------------------------------------- 1 | var React = require('react-native') 2 | var moment = require('moment') 3 | 4 | var TopicService = require('../services/TopicService') 5 | var TopicRow = require('./rowModule/TopicRow') 6 | 7 | var window = require('../util/window') 8 | 9 | var { width, height } = window.get() 10 | 11 | var { 12 | View, 13 | StyleSheet, 14 | ScrollView, 15 | Component, 16 | Text, 17 | Image, 18 | ListView, 19 | ActivityIndicatorIOS, 20 | TouchableHighlight, 21 | TouchableOpacity, 22 | ToastAndroid 23 | } = React 24 | 25 | import Loading from "./Loading.js"; 26 | 27 | class TopicListView extends Component { 28 | constructor(porps) { 29 | super(porps) 30 | var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}) 31 | this.page=1 32 | this.data=[] 33 | this.state = { 34 | ds: ds.cloneWithRows(this.data), 35 | isLoading: true, 36 | loadingPosition: 'top', 37 | getTopicError: null 38 | } 39 | } 40 | 41 | _genRows(){ 42 | //get from storage,if not exist,call get from network 43 | var params={ 44 | page: this.page, 45 | limit: 10 46 | } 47 | if(this.props.tab) params['tab']=this.props.tab; 48 | 49 | TopicService.req.getTopicsByTab(params) 50 | .then(topics=> { 51 | var newData=this.data.concat(topics) 52 | this.setState({ 53 | isLoading: false, 54 | ds: this.state.ds.cloneWithRows(newData), 55 | }) 56 | this.data=newData 57 | }) 58 | .catch(err=> { 59 | console.warn(err) 60 | }) 61 | .done((err)=> { 62 | this.isFreshing = false 63 | this.setState({ 64 | isLoading: false, 65 | err: err 66 | }) 67 | }) 68 | } 69 | 70 | componentDidMount() { 71 | this._genRows(); 72 | } 73 | 74 | _renderRow(topic, sectionId, rowId, highlightRow) { 75 | return ( 76 | this.listRows[rowId.toString()]=view} 78 | topic={topic} 79 | router={this.props.router} 80 | > 81 | 82 | ) 83 | } 84 | 85 | _onEndReached() 86 | { 87 | this.page=this.page+1; 88 | this._genRows(); 89 | } 90 | render() { 91 | if(!this.props.isRender) 92 | { 93 | return null 94 | } 95 | if (this.state.isLoading) { 96 | return ( 97 | 98 | 99 | 100 | 101 | ) 102 | } 103 | return ( 104 | {this._listView = view}} 106 | style={styles.listStyle} 107 | //onScroll={()=>onScroll()} 108 | showsVerticalScrollIndicator={true} 109 | initialListSize={10} 110 | pagingEnabled={false} 111 | removeClippedSubviews={true} 112 | dataSource={this.state.ds} 113 | renderRow={this._renderRow.bind(this)} 114 | onEndReached={this._onEndReached.bind(this)} 115 | onEndReachedThreshold={20} 116 | /> 117 | ) 118 | } 119 | } 120 | 121 | 122 | var styles = StyleSheet.create({ 123 | "listStyle":{ 124 | backgroundColor:'rgba(255,255,255,1)', 125 | flex:1 126 | } 127 | }) 128 | 129 | module.exports = TopicListView; 130 | -------------------------------------------------------------------------------- /androidApp/components/UserInfo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/11/6. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | import React, { 8 | Component, 9 | StyleSheet, 10 | Text, 11 | View, 12 | Image, 13 | TouchableHighlight, 14 | TouchableOpacity, 15 | } 16 | from 'react-native'; 17 | 18 | import { connect } from '../../node_modules/react-redux/native'; 19 | import { getLoginUserFromStorage } from '../actions/UserActions.js'; 20 | import {alertLogout} from './alertModule/alertLogout' 21 | import BasicButton from './buttonModule/BasicButton.js' 22 | var styles = StyleSheet.create({ 23 | userInfo:{ 24 | backgroundColor:'pink' 25 | }, 26 | textUnLogin:{ 27 | fontSize: 14, 28 | color: '#888888', 29 | lineHeight: 20, 30 | marginLeft:10, 31 | justifyContent:'center' 32 | }, 33 | textLogin:{ 34 | fontSize: 14, 35 | color: '#888888', 36 | lineHeight: 20, 37 | marginLeft:15, 38 | justifyContent:'center' 39 | }, 40 | image:{ 41 | flex:1, 42 | }, 43 | userAvatar:{ 44 | marginTop:10, 45 | marginLeft:10, 46 | width:80, 47 | height:80, 48 | borderRadius:40 49 | } 50 | }); 51 | 52 | class UserInfo extends Component{ 53 | constructor(props) { 54 | super(props); 55 | } 56 | 57 | componentDidMount(){ 58 | this.props.actions.loadUser() 59 | this.props.actions.loadUserId() 60 | this.props.actions.loadAccessToken() 61 | } 62 | 63 | _login(){ 64 | this.props.router.toLogin() 65 | } 66 | 67 | _notLoginRender() 68 | { 69 | return( 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 点击头像登录 78 | 79 | 80 | ) 81 | } 82 | _logout(){ 83 | alertLogout(this.props.actions) 84 | } 85 | 86 | _userInfo(){ 87 | this.props.router.toUser({ 88 | loginname:this.props.state.userState.userData.loginname 89 | }) 90 | } 91 | 92 | _loginRender() 93 | { 94 | const userData=this.props.state.userState.userData 95 | return( 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | {userData.loginname} 105 | 106 | 107 | 积分:{userData.score} 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | ) 116 | } 117 | 118 | render() 119 | { 120 | const userState=this.props.state.userState 121 | if(userState.isLogin) 122 | { 123 | return this._loginRender() 124 | } 125 | else{ 126 | return this._notLoginRender() 127 | } 128 | } 129 | } 130 | 131 | module.exports=UserInfo 132 | -------------------------------------------------------------------------------- /androidApp/components/alertModule/alertLogin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2016/1/6. 3 | */ 4 | 5 | import React,{Alert} from 'react-native' 6 | 7 | export function alertLogin(router){ 8 | Alert.alert( 9 | null, 10 | '您还未登录,是否登录?', 11 | [ 12 | {text: '取消'}, 13 | {text: '确认',onPress:()=>router.toLogin()}, 14 | ] 15 | ) 16 | } -------------------------------------------------------------------------------- /androidApp/components/alertModule/alertLogout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2016/1/6. 3 | */ 4 | 5 | import React,{Alert} from 'react-native' 6 | 7 | export function alertLogout(actions){ 8 | Alert.alert( 9 | null, 10 | '确定要注销吗?', 11 | [ 12 | {text: '取消'}, 13 | {text: '确认', onPress: () => actions.logout()}, 14 | ] 15 | ) 16 | } -------------------------------------------------------------------------------- /androidApp/components/buttonModule/BasicButton.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2016/1/26. 3 | */ 4 | 5 | import React,{ 6 | Component, 7 | TouchableHighlight, 8 | StyleSheet, 9 | Text, 10 | View 11 | } from "react-native" 12 | 13 | var styles = StyleSheet.create({ 14 | textStyle:{ 15 | margin:10, 16 | textAlign:'center' 17 | }, 18 | }); 19 | 20 | class BasicButton extends Component{ 21 | render() 22 | { 23 | let {value,onPress}=this.props 24 | return( 25 | 26 | {value} 27 | 28 | ) 29 | } 30 | } 31 | 32 | module.exports = BasicButton; -------------------------------------------------------------------------------- /androidApp/components/buttonModule/PublishButton.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2016/1/12. 3 | */ 4 | 5 | import React,{ 6 | Component, 7 | TouchableOpacity, 8 | StyleSheet, 9 | Text, 10 | View 11 | } from "react-native" 12 | 13 | var styles = StyleSheet.create({ 14 | button:{ 15 | flex:1, 16 | borderWidth:1, 17 | borderRadius:5, 18 | alignItems:'center', 19 | justifyContent:'center', 20 | backgroundColor:'#4987E4' 21 | }, 22 | buttonText:{ 23 | fontSize: 16, 24 | lineHeight:22 25 | } 26 | }); 27 | 28 | class PublishButton extends Component{ 29 | render() 30 | { 31 | let {value,disabled,onPress}=this.props 32 | return( 33 | 34 | 35 | {value} 36 | 37 | 38 | ) 39 | } 40 | } 41 | 42 | module.exports = PublishButton; -------------------------------------------------------------------------------- /androidApp/components/htmlRender/CommentHtml.js: -------------------------------------------------------------------------------- 1 | var React = require('react-native') 2 | var HtmlContent = require('./HtmlContent') 3 | 4 | var window = require('../../util/window') 5 | var { width, height } = window.get() 6 | 7 | var { 8 | Component, 9 | View, 10 | Text, 11 | StyleSheet, 12 | Image 13 | }=React 14 | 15 | 16 | class CommentHtml extends Component { 17 | constructor(props) { 18 | super(props) 19 | if (this.props.style) { 20 | this.styles = Object.assign({}, styles, this.props.style) 21 | } 22 | } 23 | 24 | render() { 25 | return ( 26 | 31 | ) 32 | } 33 | } 34 | 35 | 36 | var fontSize = 14 37 | var titleMargin = 5 38 | var liFontSize = fontSize - 2 39 | 40 | var styles = StyleSheet.create({ 41 | p: { 42 | lineHeight: fontSize * 1.4, 43 | fontSize: fontSize, 44 | color: 'rgba(0,0,0,0.8)' 45 | }, 46 | pwrapper: { 47 | marginTop: 5, 48 | marginBottom: 5 49 | }, 50 | 51 | a: { 52 | color: '#3498DB', 53 | fontSize: fontSize, 54 | paddingLeft: 4, 55 | paddingRight: 4, 56 | marginRight: 10, 57 | marginLeft: 10 58 | }, 59 | h1: { 60 | fontSize: fontSize * 1.6, 61 | fontWeight: "bold", 62 | color: 'rgba(0,0,0,0.8)' 63 | }, 64 | h1wrapper: { 65 | marginTop: titleMargin, 66 | marginBottom: titleMargin 67 | }, 68 | h2: { 69 | fontSize: fontSize * 1.5, 70 | fontWeight: 'bold', 71 | color: 'rgba(0,0,0,0.85)' 72 | }, 73 | h2wrapper: { 74 | marginBottom: titleMargin, 75 | marginTop: titleMargin 76 | }, 77 | h3: { 78 | fontWeight: 'bold', 79 | fontSize: fontSize * 1.4, 80 | color: 'rgba(0,0,0,0.8)' 81 | }, 82 | h3wrapper: { 83 | marginBottom: titleMargin - 2, 84 | marginTop: titleMargin - 2 85 | }, 86 | h4: { 87 | fontSize: fontSize * 1.3, 88 | color: 'rgba(0,0,0,0.7)', 89 | fontWeight: 'bold' 90 | }, 91 | h4wrapper: { 92 | marginBottom: titleMargin - 2, 93 | marginTop: titleMargin - 2, 94 | }, 95 | h5: { 96 | fontSize: fontSize * 1.2, 97 | color: 'rgba(0,0,0,0.7)', 98 | fontWeight: 'bold' 99 | }, 100 | h5wrapper: { 101 | marginBottom: titleMargin - 3, 102 | marginTop: titleMargin - 3, 103 | }, 104 | h6: { 105 | fontSize: fontSize * 1.1, 106 | color: 'rgba(0,0,0,0.7)', 107 | fontWeight: 'bold' 108 | }, 109 | h6wrapper: { 110 | marginBottom: titleMargin - 3, 111 | marginTop: titleMargin - 3, 112 | }, 113 | li: { 114 | fontSize: fontSize * 0.9, 115 | color: 'rgba(0,0,0,0.7)' 116 | }, 117 | liwrapper: { 118 | paddingLeft: 20, 119 | marginBottom: 10 120 | }, 121 | strong: { 122 | fontWeight: 'bold' 123 | }, 124 | em: { 125 | fontStyle: 'italic' 126 | }, 127 | codeScrollView: { 128 | backgroundColor: '#333', 129 | flexDirection: 'column', 130 | marginBottom: 15 131 | }, 132 | codeRow: { 133 | flex: 1, 134 | flexDirection: 'row', 135 | height: 25, 136 | alignItems: 'center' 137 | }, 138 | codeFirstRow: { 139 | paddingTop: 20, 140 | height: 25 + 20 141 | }, 142 | codeLastRow: { 143 | paddingBottom: 20, 144 | height: 25 + 20 145 | }, 146 | codeFirstAndLastRow: { 147 | paddingBottom: 20, 148 | height: 25 + 40, 149 | paddingTop: 20 150 | }, 151 | lineNum: { 152 | width: 55, 153 | color: 'rgba(255,255,255,0.5)', 154 | }, 155 | lineNumWrapper: { 156 | width: 55, 157 | height: 25, 158 | backgroundColor: 'rgba(0,0,0,0.1)', 159 | flexDirection: 'row', 160 | alignItems: 'center', 161 | paddingLeft: 20 162 | }, 163 | codeWrapper: { 164 | flexDirection: 'column' 165 | }, 166 | codeLineWrapper: { 167 | height: 25, 168 | flexDirection: 'row', 169 | alignItems: 'center', 170 | paddingLeft: 20, 171 | paddingRight: 20 172 | }, 173 | blockquotewrapper: { 174 | paddingLeft: 20, 175 | borderLeftColor: '#3498DB', 176 | borderLeftWidth: 3 177 | }, 178 | img:{ 179 | width: width - 80, 180 | height: width - 80, 181 | resizeMode: Image.resizeMode.contain 182 | } 183 | }) 184 | 185 | module.exports = CommentHtml 186 | -------------------------------------------------------------------------------- /androidApp/components/htmlRender/HtmlContent.js: -------------------------------------------------------------------------------- 1 | var React = require('react-native') 2 | 3 | var HtmlRender = require('react-native-html-render') 4 | 5 | var window = require('../../util/window') 6 | 7 | 8 | var { width, height } = window.get() 9 | 10 | var { 11 | Platform, 12 | Component, 13 | View, 14 | Text, 15 | StyleSheet, 16 | Image, 17 | LinkingIOS, 18 | Navigator, 19 | IntentAndroid 20 | }=React 21 | 22 | import {openUrl} from '../openUrlModule/openUrl' 23 | var contentFontSize = 16 24 | 25 | 26 | var styles = StyleSheet.create({ 27 | img: { 28 | width: width - 30, 29 | height: width - 30, 30 | resizeMode: Image.resizeMode.contain 31 | } 32 | }) 33 | 34 | 35 | var regs = { 36 | http: { 37 | topic: /^https?:\/\/cnodejs\.org\/topic\/\w*/, 38 | user: /^https?:\/\/cnodejs\.org\/user\/\w*/ 39 | } 40 | } 41 | 42 | 43 | class HtmlContent extends Component { 44 | constructor(props) { 45 | super(props) 46 | } 47 | 48 | 49 | _onLinkPress(url) { 50 | let router = this.props.router 51 | 52 | if (/^\/user\/\w*/.test(url)) { 53 | let authorName = url.replace(/^\/user\//, '') 54 | 55 | router.toUser({ 56 | loginname: authorName 57 | }) 58 | } 59 | 60 | if (/^https?:\/\/.*/.test(url)) { 61 | if (regs.http.topic.test(url)) { 62 | let topicId = url.replace(/^https?:\/\/cnodejs\.org\/topic\//, '') 63 | 64 | return router.toTopicInfoListView({ 65 | id: topicId, 66 | from: 'html' 67 | }) 68 | } 69 | 70 | if (regs.http.user.test(url)) { 71 | let userName = url.replace(/^https?:\/\/cnodejs\.org\/user\//, '') 72 | 73 | return router.toUser({ 74 | loginname: userName 75 | }) 76 | } 77 | openUrl(url) 78 | } 79 | 80 | if (/^mailto:\w*/.test(url)) { 81 | openUrl(url) 82 | } 83 | } 84 | 85 | 86 | _renderNode(node, index, parent, type) { 87 | var name = node.name 88 | 89 | var imgStyle = (this.props.style && this.props.style.img) || styles.img 90 | 91 | if (node.type == 'block' && type == 'block') { 92 | if (name == 'img') { 93 | var uri = window.parseImgUrl(node.attribs.src) 94 | if (/.*\.gif$/.test(uri)) return null 95 | return ( 96 | 100 | 101 | ) 102 | } 103 | } 104 | } 105 | 106 | 107 | render() { 108 | return ( 109 | 115 | ) 116 | } 117 | 118 | } 119 | 120 | module.exports = HtmlContent 121 | -------------------------------------------------------------------------------- /androidApp/components/openUrlModule/openUrl.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/12/15. 3 | */ 4 | import React,{IntentAndroid} from 'react-native' 5 | 6 | export function openUrl(url){ 7 | IntentAndroid.canOpenURL(url, (supported) => { 8 | if (supported) { 9 | IntentAndroid.openURL(url); 10 | } else { 11 | console.log('Don\'t know how to open URI: ' + this.props.url); 12 | } 13 | }); 14 | } -------------------------------------------------------------------------------- /androidApp/components/openUrlModule/openUrl.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/12/15. 3 | */ 4 | 5 | import React,{LinkingIOS} from 'react-native' 6 | 7 | export function openUrl(url){ 8 | LinkingIOS.canOpenURL(url, (supported) => { 9 | if (supported) { 10 | LinkingIOS.openURL(url); 11 | } else { 12 | console.log('Don\'t know how to open URI: ' + this.props.url); 13 | } 14 | }); 15 | } -------------------------------------------------------------------------------- /androidApp/components/rowModule/CommentRow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/11/2. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component, 10 | StyleSheet, 11 | Text, 12 | View, 13 | TouchableHighlight, 14 | PixelRatio, 15 | Image, 16 | ToastAndroid 17 | } = React; 18 | 19 | var ImageCircle=require('./../ImageCircle') 20 | 21 | import CommentHtml from "./../htmlRender/CommentHtml.js" 22 | var Icon=require("react-native-vector-icons/MaterialIcons") 23 | import {alertLogin} from './../alertModule/alertLogin' 24 | 25 | /*moment*/ 26 | import moment from "moment" 27 | import zh_cn from "moment/locale/zh-cn.js" 28 | moment.locale('zh-cn',zh_cn) 29 | 30 | var styles = StyleSheet.create({ 31 | row:{ 32 | paddingLeft:15, 33 | paddingRight:15, 34 | marginTop:10, 35 | flex:1, 36 | backgroundColor: 'white', 37 | flexDirection:'row', 38 | }, 39 | separator:{ 40 | height: 1 / PixelRatio.get(), 41 | backgroundColor: '#bbbbbb', 42 | }, 43 | titleText:{ 44 | fontSize: 16, 45 | fontWeight: '500', 46 | textAlign:'left' 47 | }, 48 | info:{ 49 | flex:5, 50 | paddingLeft:10 51 | }, 52 | avatar:{ 53 | flex:1, 54 | }, 55 | action:{ 56 | flex:3, 57 | flexDirection:'row', 58 | }, 59 | authorText:{ 60 | flex:3, 61 | fontSize: 14, 62 | color: '#888888', 63 | lineHeight: 20, 64 | }, 65 | countText:{ 66 | flex:3, 67 | fontSize: 14, 68 | color: '#888888', 69 | lineHeight: 20, 70 | }, 71 | agreeText:{ 72 | textAlign :'left', 73 | fontSize: 20, 74 | color: '#888888', 75 | lineHeight:26, 76 | //marginTop:10 77 | }, 78 | webView:{ 79 | paddingLeft:15, 80 | paddingRight:15, 81 | flex:1 82 | } 83 | }); 84 | 85 | class CommentRow extends Component{ 86 | constructor(props) { 87 | super(props); 88 | const {reply} =this.props; 89 | const {userId}=this.props.state.userState 90 | this.state={ 91 | isUp:reply.ups.indexOf(userId)!==-1, 92 | upLength:reply.ups.length 93 | } 94 | } 95 | _upPress(){ 96 | 97 | if(this.props.state.userState.accesstoken) 98 | { 99 | this.setState({ 100 | isUp:!this.state.isUp, 101 | upLength:this.state.isUp?this.state.upLength-1:this.state.upLength+1 102 | }) 103 | this.props.actions.upComment(this.props.reply.id,this.props.state.userState.accesstoken) 104 | } 105 | else{ 106 | alertLogin(this.props.router) 107 | } 108 | 109 | } 110 | 111 | 112 | render() 113 | { 114 | const {reply,row,replyOnePress} =this.props; 115 | 116 | return ( 117 | 118 | 119 | 120 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | {reply.author.loginname} 129 | 130 | 131 | {row}楼 {moment(reply.create_at).startOf('hour').fromNow()} 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | {this.state.upLength} 142 | 143 | replyOnePress()}> 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | ) 156 | } 157 | } 158 | 159 | module.exports=CommentRow -------------------------------------------------------------------------------- /androidApp/components/rowModule/MenuRow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2016/1/13. 3 | * a row with a left icon 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var React = require('react-native'); 9 | var { 10 | Component, 11 | StyleSheet, 12 | Text, 13 | View, 14 | TouchableOpacity, 15 | PixelRatio, 16 | } = React; 17 | 18 | var Icon = require('react-native-vector-icons/MaterialIcons'); 19 | 20 | var styles = StyleSheet.create({ 21 | row:{ 22 | height:56, 23 | backgroundColor: 'white', 24 | }, 25 | text:{ 26 | fontSize: 16, 27 | color: '#888888', 28 | lineHeight: 20, 29 | }, 30 | separator:{ 31 | height: 1 / PixelRatio.get(), 32 | backgroundColor: '#bbbbbb', 33 | }, 34 | textRow:{ 35 | flex:1, 36 | flexDirection:'row', 37 | paddingHorizontal: 15, 38 | paddingVertical: 10, 39 | }, 40 | 41 | }); 42 | 43 | class MenuRow extends Component{ 44 | constructor(props) { 45 | super(props); 46 | } 47 | render() 48 | { 49 | var {text,onPress,icon}=this.props; 50 | return ( 51 | onPress?onPress():null}> 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {text} 60 | 61 | 62 | 63 | 64 | 65 | 66 | ) 67 | } 68 | } 69 | 70 | module.exports=MenuRow -------------------------------------------------------------------------------- /androidApp/components/rowModule/MessageRow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/17. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component, 10 | StyleSheet, 11 | Text, 12 | View, 13 | TouchableHighlight, 14 | TouchableOpacity, 15 | PixelRatio, 16 | Image 17 | } = React; 18 | 19 | var ImageCircle=require('./../ImageCircle') 20 | import {getCategory} from "../../util/cnodeUtil" 21 | import CommentHtml from "./../htmlRender/CommentHtml" 22 | /*moment*/ 23 | import moment from "moment" 24 | import zh_cn from "moment/locale/zh-cn.js" 25 | moment.locale('zh-cn',zh_cn) 26 | 27 | var styles = StyleSheet.create({ 28 | row:{ 29 | paddingLeft:15, 30 | paddingRight:15, 31 | paddingTop:10, 32 | backgroundColor: 'white', 33 | flexDirection:'row', 34 | }, 35 | separator:{ 36 | height: 1 / PixelRatio.get(), 37 | backgroundColor: '#bbbbbb', 38 | }, 39 | categoryText:{ 40 | fontSize: 14, 41 | textAlign:'center', 42 | }, 43 | avatar:{ 44 | flex:1, 45 | alignItems:"center" 46 | }, 47 | info:{ 48 | flex:8, 49 | marginBottom:10, 50 | marginLeft:10 51 | }, 52 | author:{ 53 | flexDirection:'row', 54 | }, 55 | authorText:{ 56 | flex:1, 57 | fontSize: 14, 58 | color: '#888888', 59 | lineHeight: 20, 60 | }, 61 | timeText:{ 62 | flex:2, 63 | fontSize: 14, 64 | color: '#888888', 65 | lineHeight: 20, 66 | }, 67 | topicText:{ 68 | flex:1, 69 | fontSize: 14, 70 | lineHeight: 20, 71 | }, 72 | webView:{ 73 | paddingLeft:15, 74 | paddingRight:15, 75 | flex:1 76 | }, 77 | topic:{ 78 | marginLeft:15, 79 | marginRight:15, 80 | marginBottom:15, 81 | paddingTop:10, 82 | paddingBottom:10, 83 | paddingRight:10, 84 | paddingLeft:10, 85 | backgroundColor: 'lightgray', 86 | } 87 | }); 88 | 89 | class MessageRow extends Component{ 90 | constructor(props) { 91 | super(props); 92 | } 93 | _onPress(id) 94 | { 95 | this.props.router.toTopicInfoListView({ 96 | id:id 97 | }) 98 | } 99 | render() 100 | { 101 | var {message} =this.props; 102 | return ( 103 | 104 | 105 | 106 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | {message.author.loginname} 115 | 116 | 117 | {moment(message.reply.create_at).startOf('hour').fromNow()} 118 | 119 | 120 | 121 | 122 | 在回复中@了您 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | {message.topic.title} 135 | 136 | 137 | 138 | 139 | ) 140 | } 141 | } 142 | 143 | module.exports=MessageRow -------------------------------------------------------------------------------- /androidApp/components/rowModule/ReplyRow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/11/2. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component, 10 | StyleSheet, 11 | Text, 12 | View, 13 | TextInput, 14 | Dimensions, 15 | DeviceEventEmitter, 16 | LayoutAnimation, 17 | Platform 18 | } = React; 19 | import BasicButton from '../buttonModule/BasicButton.js' 20 | var styles = StyleSheet.create({ 21 | row:{ 22 | backgroundColor:'white', 23 | paddingHorizontal: 5, 24 | paddingVertical: 5, 25 | flex:1, 26 | height:60, 27 | flexDirection:'row', 28 | position:'absolute', 29 | right:0, 30 | left:0, 31 | borderTopWidth:1, 32 | borderTopColor:'#bbbbbb' 33 | }, 34 | replyButton:{ 35 | flex:1, 36 | borderWidth:1, 37 | marginTop:5, 38 | borderRadius:5, 39 | borderColor:'#bbbbbb' 40 | }, 41 | textInput:{ 42 | marginTop:5, 43 | marginRight:5, 44 | borderWidth:1, 45 | borderColor:'#bbbbbb', 46 | borderRadius:5, 47 | flex:6, 48 | justifyContent:'center' 49 | } 50 | }); 51 | 52 | var deviceWidth = Dimensions.get('window').width; 53 | 54 | class ReplyRow extends Component{ 55 | constructor(props) { 56 | super(props); 57 | this.state={ 58 | bottom:0 59 | } 60 | this.keyboardWillShow=this.keyboardWillShow.bind(this) 61 | this.keyboardWillHide=this.keyboardWillHide.bind(this) 62 | } 63 | 64 | componentDidMount(){ 65 | if(Platform.OS==="ios") 66 | { 67 | DeviceEventEmitter.addListener('keyboardWillShow',this.keyboardWillShow) 68 | DeviceEventEmitter.addListener('keyboardWillHide', this.keyboardWillHide); 69 | } 70 | } 71 | 72 | componentWillUnmount(){ 73 | if(Platform.OS==="ios") 74 | { 75 | DeviceEventEmitter.removeAllListeners('keyboardWillShow') 76 | DeviceEventEmitter.removeAllListeners('keyboardWillHide'); 77 | } 78 | } 79 | 80 | keyboardWillShow(e){ 81 | LayoutAnimation.configureNext(LayoutAnimation.create( 82 | e.duration, 83 | LayoutAnimation.Types[e.easing] 84 | )); 85 | this.setState({ 86 | bottom: e.endCoordinates.height 87 | }); 88 | } 89 | 90 | keyboardWillHide(e){ 91 | LayoutAnimation.configureNext(LayoutAnimation.create( 92 | e.duration, 93 | LayoutAnimation.Types[e.easing] 94 | )); 95 | this.setState({ 96 | bottom: 0 97 | }); 98 | } 99 | 100 | render() 101 | { 102 | var {text,onPress,onChangeText}=this.props; 103 | return ( 104 | 105 | 106 | onChangeText(value)} placeholder="说点什么吧" style={{ borderWidth: Platform.OS=='ios'?1:5,height:56}}> 107 | 108 | 109 | 110 | onPress()}/> 111 | 112 | 113 | ) 114 | } 115 | } 116 | 117 | module.exports=ReplyRow 118 | -------------------------------------------------------------------------------- /androidApp/components/rowModule/SettingsRow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/4. 3 | * a row with two line and a switch 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var React = require('react-native'); 9 | var { 10 | Component, 11 | StyleSheet, 12 | Text, 13 | View, 14 | TouchableHighlight, 15 | PixelRatio 16 | } = React; 17 | 18 | import Switch from "./../SwitchModule/Switch" 19 | var styles = StyleSheet.create({ 20 | row:{ 21 | backgroundColor: 'white', 22 | }, 23 | textRow:{ 24 | flex:5, 25 | justifyContent: 'center', 26 | paddingHorizontal: 15, 27 | paddingVertical: 10, 28 | }, 29 | text:{ 30 | fontSize: 18, 31 | lineHeight: 24, 32 | }, 33 | subtext:{ 34 | fontSize: 12, 35 | lineHeight: 18, 36 | }, 37 | separator:{ 38 | height: 1 / PixelRatio.get(), 39 | backgroundColor: '#bbbbbb', 40 | }, 41 | actions:{ 42 | flex:1, 43 | paddingVertical: 10, 44 | alignItems:'center', 45 | } 46 | }); 47 | 48 | class SettingsRow extends Component{ 49 | constructor(props) { 50 | super(props); 51 | } 52 | render() 53 | { 54 | var {text,subText,switchPress,switchValue}=this.props; 55 | return ( 56 | {switchPress?switchPress():null}}> 57 | 58 | 59 | 60 | 61 | {text} 62 | 63 | 64 | {subText} 65 | 66 | 67 | 68 | {switchPress?switchPress():null}}> 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | ) 77 | } 78 | } 79 | 80 | module.exports=SettingsRow -------------------------------------------------------------------------------- /androidApp/components/rowModule/SimpleRow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/11/2. 3 | *a simple row with sepeator 4 | */ 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component, 10 | StyleSheet, 11 | Text, 12 | View, 13 | TouchableOpacity, 14 | PixelRatio, 15 | } = React; 16 | 17 | var styles = StyleSheet.create({ 18 | row:{ 19 | height:56, 20 | backgroundColor: 'white', 21 | }, 22 | text:{ 23 | fontSize: 16, 24 | color: '#888888', 25 | lineHeight: 20, 26 | }, 27 | separator:{ 28 | height: 1 / PixelRatio.get(), 29 | backgroundColor: '#bbbbbb', 30 | }, 31 | textRow:{ 32 | flex:1, 33 | justifyContent:'center', 34 | paddingHorizontal: 15, 35 | paddingVertical: 10, 36 | } 37 | }); 38 | 39 | class SimpleRow extends Component{ 40 | constructor(props) { 41 | super(props); 42 | } 43 | render() 44 | { 45 | var {text,onPress}=this.props; 46 | return ( 47 | onPress?onPress():null}> 48 | 49 | 50 | 51 | {text} 52 | 53 | 54 | 55 | 56 | 57 | ) 58 | } 59 | } 60 | 61 | module.exports=SimpleRow -------------------------------------------------------------------------------- /androidApp/components/rowModule/TopicInfoRow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/11/16. 3 | * 主题详细信息的楼主部分 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var React = require('react-native'); 9 | var { 10 | Component, 11 | StyleSheet, 12 | Text, 13 | View, 14 | TouchableHighlight, 15 | PixelRatio, 16 | Image 17 | } = React; 18 | 19 | var ImageCircle=require('./../ImageCircle') 20 | import {getCategory} from "../../util/cnodeUtil" 21 | 22 | /*moment*/ 23 | import moment from "moment" 24 | import zh_cn from "moment/locale/zh-cn.js" 25 | moment.locale('zh-cn',zh_cn) 26 | 27 | import CommentHtml from "./../htmlRender/CommentHtml.js" 28 | 29 | var styles = StyleSheet.create({ 30 | row:{ 31 | paddingLeft:15, 32 | paddingRight:15, 33 | flex:1, 34 | backgroundColor: 'white', 35 | }, 36 | separator:{ 37 | height: 1 / PixelRatio.get(), 38 | backgroundColor: '#bbbbbb', 39 | }, 40 | titleRow:{ 41 | flex:1, 42 | marginTop:10, 43 | flexDirection:'row', 44 | }, 45 | category:{ 46 | flex:1, 47 | borderRadius:10, 48 | marginBottom:5 49 | }, 50 | title:{ 51 | flex:1, 52 | paddingTop:15, 53 | paddingLeft:15, 54 | marginBottom:10 55 | }, 56 | categoryText:{ 57 | fontSize: 14, 58 | textAlign:'center', 59 | }, 60 | titleText:{ 61 | fontSize: 16, 62 | fontWeight: '500', 63 | textAlign:'left' 64 | }, 65 | infoRow:{ 66 | height:40, 67 | marginBottom:5, 68 | flexDirection:'row', 69 | }, 70 | avatar:{ 71 | flex:1, 72 | alignItems:"center" 73 | }, 74 | info:{ 75 | flex:8, 76 | marginBottom:10, 77 | marginLeft:10 78 | }, 79 | author:{ 80 | flexDirection:'row', 81 | }, 82 | authorText:{ 83 | flex:7, 84 | fontSize: 14, 85 | color: '#888888', 86 | lineHeight: 20, 87 | }, 88 | timeText:{ 89 | flex:2, 90 | fontSize: 14, 91 | color: '#888888', 92 | lineHeight: 20, 93 | }, 94 | countText:{ 95 | flex:1, 96 | fontSize: 14, 97 | color: 'lightgreen', 98 | lineHeight: 20, 99 | textAlign:'right', 100 | }, 101 | webView:{ 102 | paddingLeft:15, 103 | paddingRight:15, 104 | flex:1 105 | } 106 | }); 107 | 108 | class TopicInfoRow extends Component{ 109 | constructor(props) { 110 | super(props); 111 | } 112 | render() 113 | { 114 | var {topic} =this.props;//https://cnodejs.org/api/v1/topics 115 | return ( 116 | 117 | 118 | 119 | {topic.title} 120 | 121 | 122 | 123 | 124 | 125 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | {topic.author.loginname} 134 | 135 | 136 | 137 | {topic.top?"置顶":(topic.good?"精华":getCategory(topic.tab))} 138 | 139 | 140 | 141 | 142 | 143 | 发布于:{moment(topic.create_at).startOf('hour').fromNow()} 144 | 145 | 146 | {topic.visit_count}次浏览 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | ) 160 | } 161 | } 162 | 163 | module.exports=TopicInfoRow -------------------------------------------------------------------------------- /androidApp/components/rowModule/TopicRow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/11/2. 3 | * 主题正文行 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var React = require('react-native'); 9 | var { 10 | Component, 11 | StyleSheet, 12 | Text, 13 | View, 14 | TouchableHighlight, 15 | PixelRatio, 16 | Image 17 | } = React; 18 | 19 | var ImageCircle=require('./../ImageCircle') 20 | import {getCategory} from "../../util/cnodeUtil" 21 | 22 | /*moment*/ 23 | import moment from "moment" 24 | import zh_cn from "moment/locale/zh-cn.js" 25 | moment.locale('zh-cn',zh_cn) 26 | 27 | var styles = StyleSheet.create({ 28 | row:{ 29 | paddingLeft:10, 30 | paddingRight:10, 31 | flex:1, 32 | backgroundColor: 'white', 33 | }, 34 | separator:{ 35 | height: 1 / PixelRatio.get(), 36 | backgroundColor: '#bbbbbb', 37 | }, 38 | titleRow:{ 39 | flex:1, 40 | marginTop:10, 41 | flexDirection:'row', 42 | }, 43 | category:{ 44 | flex:1, 45 | borderRadius:10, 46 | marginBottom:5 47 | }, 48 | title:{ 49 | flex:8, 50 | marginLeft:10, 51 | }, 52 | categoryText:{ 53 | fontSize: 14, 54 | marginTop:2, 55 | textAlign:'center', 56 | }, 57 | titleText:{ 58 | fontSize: 16, 59 | fontWeight: '500', 60 | textAlign:'left' 61 | }, 62 | infoRow:{ 63 | height:40, 64 | marginBottom:10, 65 | flexDirection:'row', 66 | }, 67 | avatar:{ 68 | flex:1, 69 | alignItems:"center" 70 | }, 71 | info:{ 72 | flex:8, 73 | marginBottom:10, 74 | marginLeft:10 75 | }, 76 | author:{ 77 | flexDirection:'row', 78 | }, 79 | authorText:{ 80 | flex:3, 81 | fontSize: 14, 82 | color: '#888888', 83 | lineHeight: 20, 84 | }, 85 | countText:{ 86 | flex:1, 87 | fontSize: 14, 88 | color: '#888888', 89 | lineHeight: 20, 90 | textAlign:'right', 91 | } 92 | }); 93 | 94 | class TopicRow extends Component{ 95 | constructor(props) { 96 | super(props); 97 | } 98 | _onPress(id) 99 | { 100 | this.props.router.toTopicInfoListView({ 101 | id:id 102 | }) 103 | } 104 | render() 105 | { 106 | 107 | //var moment=require('moment'); 108 | var {topic} =this.props;//https://cnodejs.org/api/v1/topics 109 | 110 | 111 | return ( 112 | {this._onPress(topic.id)}}> 113 | 114 | 115 | 116 | 117 | 118 | {topic.top?"置顶":(topic.good?"精华":getCategory(topic.tab))} 119 | 120 | 121 | 122 | 123 | {topic.title} 124 | 125 | 126 | 127 | 128 | 129 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | {topic.author.loginname} 138 | 139 | 140 | {topic.reply_count}/{topic.visit_count} 141 | 142 | 143 | 144 | 145 | 创建于:{moment(topic.create_at).format('YYYY-MM-DD hh:mm:ss')} 146 | 147 | 148 | {moment(topic.last_reply_at).startOf('hour').fromNow()} 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | ) 158 | } 159 | } 160 | 161 | module.exports=TopicRow -------------------------------------------------------------------------------- /androidApp/components/rowModule/UserRow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/12/21. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component, 10 | StyleSheet, 11 | Text, 12 | View, 13 | TouchableHighlight, 14 | PixelRatio, 15 | Image 16 | } = React; 17 | 18 | var ImageCircle=require('./../ImageCircle') 19 | import {getCategory} from "../../util/cnodeUtil" 20 | 21 | /*moment*/ 22 | import moment from "moment" 23 | import zh_cn from "moment/locale/zh-cn.js" 24 | moment.locale('zh-cn',zh_cn) 25 | 26 | var styles = StyleSheet.create({ 27 | row:{ 28 | paddingLeft:15, 29 | paddingRight:15, 30 | paddingTop:10, 31 | paddingBottom:10, 32 | backgroundColor: 'white', 33 | flexDirection:'row', 34 | }, 35 | separator:{ 36 | height: 1 / PixelRatio.get(), 37 | backgroundColor: '#bbbbbb', 38 | }, 39 | avatar:{ 40 | flex:1, 41 | alignItems:"center" 42 | }, 43 | info:{ 44 | flex:8, 45 | marginLeft:10 46 | }, 47 | author:{ 48 | flexDirection:'row', 49 | }, 50 | authorText:{ 51 | flex:1, 52 | fontSize: 14, 53 | color: '#888888', 54 | lineHeight: 20, 55 | }, 56 | timeText:{ 57 | flex:1, 58 | fontSize: 14, 59 | color: '#888888', 60 | lineHeight: 20, 61 | textAlign:'right' 62 | }, 63 | topicText:{ 64 | flex:1, 65 | fontSize: 14, 66 | lineHeight: 20, 67 | }, 68 | }); 69 | 70 | class UserRow extends Component{ 71 | constructor(props) { 72 | super(props); 73 | } 74 | _onPress(id) 75 | { 76 | this.props.router.toTopicInfoListView({ 77 | id:id 78 | }) 79 | } 80 | render() 81 | { 82 | const {topic} =this.props; 83 | 84 | return ( 85 | {this._onPress(topic.id)}}> 86 | 87 | 88 | 89 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | {topic.title} 98 | 99 | 100 | 101 | 102 | {topic.author.loginname} 103 | 104 | 105 | {moment(topic.last_reply_at).startOf('hour').fromNow()} 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | ) 115 | } 116 | } 117 | 118 | module.exports=UserRow -------------------------------------------------------------------------------- /androidApp/components/rowModule/loginRow.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/androidApp/components/rowModule/loginRow.js -------------------------------------------------------------------------------- /androidApp/configs/Constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/8. 3 | */ 4 | 5 | export const STORAGE_KEY_CONFIG='config' 6 | export const STORAGE_KEY_USER='user' 7 | export const STORAGE_KEY_TAB_SHARE='tab_share' 8 | export const STORAGE_KEY_TAB_JOB='tab_job' 9 | export const STORAGE_KEY_TAB_ASK='tab_ask' -------------------------------------------------------------------------------- /androidApp/configs/Router.js: -------------------------------------------------------------------------------- 1 | var React = require('react-native') 2 | 3 | // Components 4 | //var User = require('../containers/User') 5 | //var Topic = require('../containers/Topic') 6 | //var Comments = require('../containers/Comments') 7 | var Message = require('../containers/Message') 8 | var About = require('../containers/About') 9 | //var Publish = require('../containers/Publish') 10 | var BarCode=require('../containers/BarCode') 11 | var TopicInfoListView=require('../containers/TopicInfoListView') 12 | // Config 13 | import {customFloatFromRight,basePushFromRight} from './sceneConfig' 14 | var WriteTopic =require('../containers/WriteTopic') 15 | var Settings=require('../containers/Settings') 16 | var Login=require('../containers/Login') 17 | import User from '../containers/User' 18 | 19 | var { 20 | Navigator 21 | } = React 22 | 23 | class Router { 24 | constructor(navigator) { 25 | this.navigator = navigator 26 | this.length=this.navigator.getCurrentRoutes().length 27 | } 28 | 29 | push(props, route) { 30 | let routesList = this.navigator.getCurrentRoutes() 31 | let nextIndex = routesList[routesList.length - 1].index + 1 32 | route.props = props 33 | route.index = nextIndex 34 | this.navigator.push(route) 35 | } 36 | 37 | 38 | pop() { 39 | this.navigator.pop() 40 | } 41 | 42 | popToTop() 43 | { 44 | this.navigator.popToTop() 45 | } 46 | 47 | 48 | toUser(props) { 49 | this.push(props, { 50 | component: User, 51 | name: 'user', 52 | sceneConfig: basePushFromRight 53 | }) 54 | } 55 | 56 | toTopicInfoListView(props) { 57 | this.push(props, { 58 | component: TopicInfoListView, 59 | name: 'topic', 60 | sceneConfig: customFloatFromRight 61 | }) 62 | } 63 | 64 | toBarCode(props) 65 | { 66 | this.push(props, { 67 | component: BarCode, 68 | name: 'barCode', 69 | sceneConfig: customFloatFromRight 70 | }) 71 | } 72 | 73 | toAbout() { 74 | this.push({}, { 75 | component: About, 76 | name: 'about', 77 | sceneConfig: customFloatFromRight 78 | }) 79 | } 80 | 81 | toComments(props) { 82 | this.push(props, { 83 | component: Comments, 84 | name: 'comments', 85 | sceneConfig: customFloatFromRight 86 | }) 87 | } 88 | 89 | toMessage(props) { 90 | this.push(props, { 91 | component: Message, 92 | name: 'message', 93 | sceneConfig: basePushFromRight 94 | }) 95 | } 96 | 97 | toPublish() { 98 | this.push({}, { 99 | component: Publish, 100 | name: 'publish', 101 | sceneConfig: customFloatFromRight 102 | }) 103 | } 104 | 105 | toWriteTopic() { 106 | this.push({}, { 107 | component: WriteTopic, 108 | name: 'WriteTopic', 109 | sceneConfig: basePushFromRight 110 | }) 111 | } 112 | 113 | toSettings(){ 114 | this.push({}, { 115 | component: Settings, 116 | name: 'Settings', 117 | sceneConfig: customFloatFromRight 118 | }) 119 | } 120 | 121 | toLogin(){ 122 | this.push({}, { 123 | component: Login, 124 | name: 'Login', 125 | sceneConfig: customFloatFromRight 126 | }) 127 | } 128 | } 129 | 130 | module.exports = Router 131 | 132 | -------------------------------------------------------------------------------- /androidApp/configs/animation.js: -------------------------------------------------------------------------------- 1 | var React = require('react-native') 2 | 3 | var { 4 | LayoutAnimation 5 | } = React 6 | 7 | var animations = {} 8 | 9 | animations.keyboard = { 10 | layout: { 11 | spring: { 12 | duration: 400, 13 | create: { 14 | duration: 300, 15 | type: LayoutAnimation.Types.easeInEaseOut, 16 | property: LayoutAnimation.Properties.opacity, 17 | }, 18 | update: { 19 | type: LayoutAnimation.Types.spring, 20 | springDamping: 400 21 | } 22 | }, 23 | easeInEaseOut: { 24 | duration: 400, 25 | create: { 26 | type: LayoutAnimation.Types.easeInEaseOut, 27 | property: LayoutAnimation.Properties.scaleXY, 28 | }, 29 | update: { 30 | type: LayoutAnimation.Types.easeInEaseOut, 31 | } 32 | } 33 | } 34 | } 35 | 36 | module.exports = animations -------------------------------------------------------------------------------- /androidApp/configs/config.js: -------------------------------------------------------------------------------- 1 | var packageObj = require('../../package.json') 2 | 3 | module.exports = { 4 | domain: 'https://cnodejs.org', 5 | apiPath: '/api/v1', 6 | bgImgUri: 'http://7lrzfj.com1.z0.glb.clouddn.com/soliury213H.png', 7 | //replySuffix: '\n\nFrom\040[Noder](https://github.com/soliury/noder-react-native)', 8 | sourceInGithub: 'https://github.com/soliury/noder-react-native', 9 | sourceNameInGithub: 'noder-react-native', 10 | package: packageObj, 11 | author: { 12 | blog: 'http://lingyong.me/about', 13 | cnodeName: 'soliury' 14 | }, 15 | cnodeAbout: 'https://cnodejs.org/about', 16 | RNWebPage: 'http://facebook.github.io/react-native/' 17 | } 18 | -------------------------------------------------------------------------------- /androidApp/configs/initConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/11/18. 3 | * default config 4 | */ 5 | 6 | var initConfig=[ 7 | { 8 | name:'topicTail', 9 | text:"话题小尾巴", 10 | subText:"开启后可以定义小尾巴", 11 | value:true 12 | }, 13 | /* { 14 | name:'saveDraft', 15 | text:"保存草稿", 16 | subText:"没有发布的话题草稿会被保存", 17 | value:true 18 | }*/ 19 | ] 20 | 21 | module.exports=initConfig -------------------------------------------------------------------------------- /androidApp/configs/sceneConfig.js: -------------------------------------------------------------------------------- 1 | var React = require('react-native') 2 | var Dimensions = require('Dimensions'); 3 | 4 | var { 5 | Navigator 6 | } = React 7 | 8 | var { width, height } = Dimensions.get('window'); 9 | 10 | 11 | var baseConfig = Navigator.SceneConfigs.PushFromRight; 12 | var popGestureConfig = Object.assign({}, baseConfig.gestures.pop, { 13 | edgeHitWidth: width / 3 14 | }); 15 | 16 | 17 | var fullPopGestureConfig = Object.assign({}, Navigator.SceneConfigs.FloatFromBottom.gestures.pop, { 18 | edgeHitWidth: width 19 | }) 20 | 21 | exports.basePushFromRight=baseConfig 22 | 23 | exports.customFloatFromRight = Object.assign({}, baseConfig, { 24 | gestures: { 25 | pop: popGestureConfig 26 | } 27 | }) 28 | 29 | 30 | exports.customFloatFromBottom = Object.assign({}, Navigator.SceneConfigs.FloatFromBottom, { 31 | gestures: { 32 | pop: fullPopGestureConfig 33 | } 34 | }) 35 | -------------------------------------------------------------------------------- /androidApp/containers/About.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/11/2. 3 | */ 4 | 5 | 'use strict' 6 | 7 | var React = require('react-native'); 8 | 9 | var { 10 | View, 11 | Component 12 | }=React 13 | 14 | var NavBar=require('./../components/ToolBar/BasicToolBar'); 15 | var SimpleRow=require('./../components/rowModule/SimpleRow'); 16 | 17 | class About extends Component{ 18 | constructor(props) { 19 | super(props); 20 | } 21 | 22 | render() { 23 | return ( 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | }; 34 | 35 | module.exports=About -------------------------------------------------------------------------------- /androidApp/containers/BarCode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/11/20. 3 | */ 4 | 5 | 'use strict' 6 | 7 | //var React = require('react-native'); 8 | import React,{ 9 | View, 10 | Component, 11 | ToastAndroid 12 | } 13 | from 'react-native'; 14 | 15 | var BarcodeScanner = require('../components/BarCodeModule/BarCode'); 16 | var NavBar=require('./../components/ToolBar/BasicToolBar') 17 | 18 | import { checkToken } from '../actions/UserActions.js'; 19 | 20 | class BarCode extends Component{ 21 | constructor(porps) { 22 | super(porps); 23 | this.state={ 24 | torchMode: 'off', 25 | cameraType: 'back', 26 | } 27 | } 28 | componentDidUpdate(){ 29 | if(this.props.state.userState.isLogin) 30 | { 31 | this.props.router.popToTop() 32 | } 33 | } 34 | 35 | _barcodeReceived(e) { 36 | this.props.actions.checkToken(e.data) 37 | // this.props.router.popToTop() 38 | } 39 | 40 | render() { 41 | return ( 42 | 43 | 44 | 45 | 51 | 52 | 53 | 54 | ); 55 | } 56 | }; 57 | 58 | module.exports=BarCode -------------------------------------------------------------------------------- /androidApp/containers/Home.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/10/11. 3 | */ 4 | 5 | 'use strict'; 6 | var React = require('react-native'); 7 | var { 8 | DeviceEventEmitter, 9 | Component, 10 | Dimensions, 11 | StyleSheet, 12 | View, 13 | Text, 14 | } = React; 15 | 16 | var Scroll=require('./../components/ScrollableTabView'); 17 | var NavigationList=require('./NavigationList'); 18 | var MainScreenToolBar=require('./../components/ToolBar/MainScreenToolBar') 19 | import {alertLogin} from './../components/alertModule/alertLogin' 20 | import DrawerLayout from 'react-native-drawer-layout' 21 | 22 | var DRAWER_WIDTH_LEFT = require('Dimensions').get('window').width / 4; 23 | var styles = StyleSheet.create({ 24 | container: { 25 | flex: 1, 26 | }, 27 | navigationList: { 28 | //backgroundColor: '#E9EAED', 29 | backgroundColor:'white', 30 | flex:1 31 | }, 32 | }); 33 | 34 | class Home extends Component{ 35 | constructor(props) { 36 | super(props); 37 | } 38 | componentDidMount() 39 | { 40 | } 41 | 42 | _writeTopic(){ 43 | if(this.props.state.userState.isLogin) 44 | { 45 | this.props.router.toWriteTopic() 46 | } 47 | else{ 48 | alertLogin(this.props.router) 49 | } 50 | 51 | } 52 | _renderNavigation(){ 53 | return ( 54 | 55 | this.drawer.openDrawer()} 57 | writeTopic={()=>this._writeTopic()} 58 | > 59 | 60 | 61 | 62 | 63 | ) 64 | } 65 | _renderNavigationView(){ 66 | return ( 67 | 68 | 69 | 70 | 71 | ) 72 | } 73 | render() 74 | { 75 | return ( 76 | { this.drawer = drawer; }} 81 | renderNavigationView={this._renderNavigationView.bind(this)}> 82 | {this._renderNavigation()} 83 | 84 | ); 85 | } 86 | } 87 | 88 | module.exports=Home -------------------------------------------------------------------------------- /androidApp/containers/Login.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/11/2. 3 | * 鐧诲綍鐣岄潰 4 | */ 5 | 'use strict' 6 | 7 | var React = require('react-native'); 8 | 9 | var { 10 | View, 11 | Component, 12 | Image, 13 | StyleSheet, 14 | TouchableHighlight, 15 | Text, 16 | TextInput, 17 | ToastAndroid 18 | }=React 19 | 20 | var Icon = require('react-native-vector-icons/MaterialIcons'); 21 | var deviceWidth = require('Dimensions').get('window').width; 22 | import BasicButton from '../components/buttonModule/BasicButton.js' 23 | 24 | var styles = StyleSheet.create({ 25 | navBar:{ 26 | position:'absolute', 27 | top:0, 28 | backgroundColor: '#2C2C2C', 29 | height:56, 30 | flexDirection:"row", 31 | paddingLeft:10, 32 | }, 33 | text:{ 34 | flex:10, 35 | fontSize: 19, 36 | color: '#FFFFFF', 37 | marginTop:10, 38 | marginLeft:10, 39 | textAlign:'left', 40 | }, 41 | back:{ 42 | marginTop:7, 43 | }, 44 | loginButton:{ 45 | flex:1, 46 | borderWidth:2, 47 | borderRadius:10, 48 | borderColor:'lightGreen', 49 | marginHorizontal:5, 50 | marginTop:5 51 | } 52 | }); 53 | 54 | class Login extends Component{ 55 | constructor(props) { 56 | super(props); 57 | this.state={ 58 | loginDisabled:true 59 | } 60 | } 61 | componentDidUpdate(){ 62 | if(this.props.state.userState.isLogin) 63 | { 64 | this.props.router.pop() 65 | } 66 | } 67 | 68 | _onPress(){ 69 | if (this.props.router && this.props.router.length > 1) { 70 | this.props.router.pop(); 71 | } 72 | } 73 | 74 | _onPressBarcode() { 75 | this.props.router.toBarCode() 76 | } 77 | 78 | _onPressLogin(){ 79 | this.props.actions.checkToken(this.state.token) 80 | } 81 | 82 | _onChangeText(value) { 83 | this.setState({ 84 | loginDisabled: value ? false : true, 85 | token:value 86 | }) 87 | } 88 | render() { 89 | return ( 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 登录 103 | 104 | 105 | 106 | 107 | 108 | 109 | this._onChangeText(value)}> 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | ); 125 | } 126 | }; 127 | 128 | module.exports=Login -------------------------------------------------------------------------------- /androidApp/containers/Message.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/17. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | 9 | var deviceWidth = require('Dimensions').get('window').width; 10 | var { 11 | Component, 12 | StyleSheet, 13 | Text, 14 | View, 15 | ScrollView, 16 | Platform, 17 | ToastAndroid 18 | } = React; 19 | 20 | var MessageListView=require('../components/MessageListView'); 21 | //var ScrollableTabView = Platform.OS=="android"?require("./ScrollableTabViewAndroid/ViewPager"):require('react-native-scrollable-tab-view'); 22 | var ScrollableTabView=require('react-native-scrollable-tab-view') 23 | var DefaultTabBar=require("../components/DefaultTabBar") 24 | var NavigationTitleBar=require("./../components/ToolBar/TopicToolBar"); 25 | 26 | class Message extends Component{ 27 | constructor(porps) { 28 | super(porps) 29 | } 30 | _onChangeTab(){ 31 | 32 | } 33 | componentDidMount() { 34 | this.props.actions.loadAccessToken() 35 | } 36 | 37 | render() { 38 | 39 | return ( 40 | 41 | 42 | 43 | 44 | } style={{flex:1}} > 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | ); 59 | } 60 | }; 61 | 62 | var styles = StyleSheet.create({ 63 | container: { 64 | flex: 1, 65 | }, 66 | tabView: { 67 | flex: 1, 68 | backgroundColor: 'rgba(0,0,0,0.01)', 69 | }, 70 | }); 71 | 72 | module.exports=Message -------------------------------------------------------------------------------- /androidApp/containers/NavigationList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/10/15. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var React = require('react-native'); 8 | var { 9 | Component, 10 | StyleSheet, 11 | Text, 12 | View, 13 | ListView, 14 | TouchableOpacity, 15 | } = React; 16 | 17 | var Userinfo=require('./../components/UserInfo') 18 | import MenuRow from '../components/rowModule/MenuRow' 19 | var TopicListView=require('./../components/TopicListView') 20 | import {alertLogin} from '../components/alertModule/alertLogin' 21 | 22 | var styles = StyleSheet.create({ 23 | refresh:{ 24 | width: 136, 25 | height: 136, 26 | position:'absolute', 27 | top:100, 28 | left:100, 29 | 30 | borderWidth: 10, 31 | borderRadius: 10, 32 | //borderColor: 'cyan', 33 | 34 | //borderRightWidth:24, 35 | borderRightColor:'black', 36 | //borderRightColor:'#03ade0', 37 | //borderRightColor : '#transparent', 38 | 39 | } 40 | }); 41 | 42 | class NavigationList extends Component{ 43 | constructor(props) { 44 | super(props); 45 | } 46 | _onPressAbout(){ 47 | this.props.router.toAbout() 48 | } 49 | 50 | _onPressMessage(){ 51 | if(this.props.state.userState.isLogin) 52 | { 53 | this.props.router.toMessage() 54 | } 55 | else{ 56 | alertLogin(this.props.router) 57 | } 58 | } 59 | 60 | _onPressSettings(){ 61 | this.props.router.toSettings() 62 | } 63 | render() 64 | { 65 | return ( 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | ) 77 | } 78 | } 79 | 80 | module.exports=NavigationList -------------------------------------------------------------------------------- /androidApp/containers/Navitation.js: -------------------------------------------------------------------------------- 1 | var React = require('react-native') 2 | var Home = require('./Home') 3 | var Router = require('../configs/Router') 4 | 5 | var { 6 | PropTypes, 7 | Component, 8 | Navigator, 9 | BackAndroid, 10 | StyleSheet, 11 | ToastAndroid 12 | } = React 13 | 14 | var Storage=require('../services/Storage'); 15 | 16 | class Navitation extends Component { 17 | constructor(props) { 18 | super(props) 19 | this.backCount=0; 20 | this.initialRoute = { 21 | name: 'home', 22 | index: 0, 23 | component: Home 24 | } 25 | } 26 | 27 | componentDidMount() { 28 | BackAndroid.addEventListener('hardwareBackPress',()=> { 29 | if (this.router && this.router.length > 1) { 30 | this.router.pop(); 31 | return true; 32 | } 33 | else{ 34 | if(this.backCount==0) 35 | { 36 | ToastAndroid.show("再点击一次返回桌面",ToastAndroid.SHORT); 37 | this.backCount++; 38 | return true; 39 | } 40 | else{ 41 | this.backCount=0; 42 | return false; 43 | } 44 | } 45 | return false; 46 | }) 47 | // this.props.actions.getLoginUserFromStorage() 48 | //this.props.actions.getAllTopicsFromStorage() 49 | 50 | this.navigator.navigationContext.addListener('didfocus', e => { 51 | this.backCount=0; 52 | let route = e.data.route 53 | this[route.name] && this[route.name].componentDidFocus && this[route.name].componentDidFocus() 54 | }) 55 | } 56 | 57 | 58 | renderScene(route, navigator) { 59 | this.router =this.props.router || new Router(navigator) 60 | if (route.component) { 61 | return React.createElement(route.component, Object.assign({}, route.props, 62 | { 63 | ref: view=>this[route.name] = view, 64 | actions: this.props.actions, 65 | state: this.props.state, 66 | router: this.router 67 | } 68 | )) 69 | } 70 | } 71 | 72 | 73 | configureScene(route) { 74 | if (route.sceneConfig) { 75 | return route.sceneConfig 76 | } 77 | return Navigator.SceneConfigs.FloatFromRight 78 | } 79 | 80 | 81 | render() { 82 | return ( 83 | this.navigator=view} 85 | initialRoute={this.initialRoute} 86 | style={styles.navigator} 87 | configureScene={this.configureScene.bind(this)} 88 | renderScene={this.renderScene.bind(this)} 89 | /> 90 | ) 91 | } 92 | } 93 | 94 | 95 | var styles = StyleSheet.create({ 96 | "navigator":{ 97 | flex:1 98 | } 99 | }) 100 | 101 | Navitation.propTypes = { 102 | actions: PropTypes.object 103 | } 104 | 105 | 106 | module.exports = Navitation 107 | -------------------------------------------------------------------------------- /androidApp/containers/Settings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/4. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | 8 | var React = require('react-native'); 9 | var { 10 | Component, 11 | StyleSheet, 12 | Text,AsyncStorage, 13 | View, 14 | ListView, 15 | TouchableOpacity, 16 | } = React; 17 | 18 | var SimpleRow=require('./../components/rowModule/SimpleRow') 19 | var NavBar=require('./../components/ToolBar/BasicToolBar') 20 | import SettingsRow from "./../components/rowModule/SettingsRow.js" 21 | 22 | class Settings extends Component{ 23 | constructor(props) { 24 | super(props); 25 | } 26 | 27 | componentDidMount() 28 | { 29 | //AsyncStorage.removeItem('config') 30 | this.props.actions.initConfig() 31 | this.props.actions.loadConfig() 32 | } 33 | 34 | _switchPress(index){ 35 | //update value in storage,then update config in redux 36 | var {config} =this.props.state.configState 37 | config[index].value=!config[index].value 38 | this.props.actions.setConfig(config) 39 | } 40 | 41 | render() 42 | { 43 | var {config} =this.props.state.configState 44 | 45 | return ( 46 | 47 | 48 | 49 | {config?config.map((item,index)=>{ 50 | return( 51 | 56 | 57 | ) 58 | }):null} 59 | 60 | 61 | ) 62 | } 63 | } 64 | 65 | module.exports=Settings -------------------------------------------------------------------------------- /androidApp/containers/WriteTopic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/11/2. 3 | */ 4 | 5 | 'use strict' 6 | 7 | //var React = require('react-native'); 8 | import React,{ 9 | View, 10 | Component, 11 | TextInput, 12 | Text, 13 | StyleSheet, 14 | ToastAndroid 15 | } 16 | from 'react-native'; 17 | 18 | var dismissKeyboard = require('dismissKeyboard'); 19 | var NavBar=require('./../components/ToolBar/PublishToolBar') 20 | import PickerModule from '../components/PickerModule/Picker' 21 | import {getCategory} from '../util/cnodeUtil.js' 22 | import {alertLogin} from './../components/alertModule/alertLogin' 23 | 24 | class WriteTopic extends Component{ 25 | constructor(porps) { 26 | super(porps); 27 | this.state = { 28 | label:['ask','share','job'], 29 | selectedLabel:0, 30 | writeDisabled:true, 31 | title:"", 32 | content:"" 33 | }; 34 | this.onSelect=this.onSelect.bind(this) 35 | } 36 | 37 | componentDidMount() { 38 | 39 | } 40 | 41 | componentDidUpdate(){ 42 | if(this.props.state.topicState.publishSuccess) 43 | { 44 | ToastAndroid.show("发布成功!",ToastAndroid.SHORT) 45 | dismissKeyboard(); 46 | } 47 | } 48 | _titleOnChangeText(value){ 49 | this.setState({ 50 | title:value, 51 | writeDisabled:(value && this.state.content)?false:true 52 | }) 53 | } 54 | _contentOnChangeText(value){ 55 | this.setState({ 56 | content:value, 57 | writeDisabled:(value && this.state.title)?false:true 58 | }) 59 | } 60 | 61 | _publishButtonPress(){ 62 | if(this.props.state.userState.isLogin) 63 | { 64 | const {title,content,selectedLabel}=this.state 65 | const tab=this.state.label[selectedLabel] 66 | this.props.actions.publish(title,tab,content,this.props.state.userState.accesstoken) 67 | } 68 | else{ 69 | alertLogin(this.props.router) 70 | } 71 | } 72 | 73 | onSelect(index) 74 | { 75 | this.setState({selectedLabel:index}) 76 | } 77 | 78 | render() { 79 | return ( 80 | 81 | 82 | 83 | this._titleOnChangeText(value)}> 84 | 85 | 86 | 87 | 请选择分类 88 | 89 | 90 | 91 | 92 | 93 | 94 | this._contentOnChangeText(value)}> 95 | 96 | 97 | 98 | 99 | ); 100 | } 101 | }; 102 | 103 | var styles = StyleSheet.create({ 104 | text:{ 105 | textAlign:'left', 106 | fontSize: 18, 107 | lineHeight: 24, 108 | }, 109 | }); 110 | 111 | module.exports=WriteTopic -------------------------------------------------------------------------------- /androidApp/containers/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/10/12. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | import React, { Component } from 'react-native'; 8 | import { createStore, applyMiddleware } from 'redux'; 9 | import { Provider } from 'react-redux/native'; 10 | import thunk from 'redux-thunk'; 11 | 12 | import rootReducer from '../reducers'; 13 | import CnodeApp from './cnodeApp'; 14 | 15 | const createStoreWithMiddleware = applyMiddleware(thunk)(createStore); 16 | const store = createStoreWithMiddleware(rootReducer); 17 | 18 | class App extends Component { 19 | //load default config 20 | componentDidMount(){ 21 | 22 | } 23 | render() { 24 | return ( 25 | 26 | {() => } 27 | 28 | ); 29 | } 30 | } 31 | 32 | module.exports=App 33 | -------------------------------------------------------------------------------- /androidApp/containers/cnodeApp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import React, { Component } from 'react-native'; 4 | import {bindActionCreators} from 'redux'; 5 | import * as cnodeActions from '../actions/index.js'; 6 | import { connect } from 'react-redux/native'; 7 | 8 | var Navitation=require('./Navitation'); 9 | 10 | class HomePage extends Component{ 11 | constructor(props) { 12 | super(props); 13 | } 14 | render() 15 | { 16 | const {state,dispatch } = this.props; 17 | const actions = bindActionCreators(cnodeActions, dispatch); 18 | return ( 19 | 20 | 21 | ) 22 | } 23 | } 24 | 25 | function mapStateToProps(state) { 26 | return { 27 | state: state 28 | }; 29 | } 30 | export default connect(mapStateToProps)(HomePage); 31 | -------------------------------------------------------------------------------- /androidApp/mocks/storage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/4. 3 | */ 4 | 5 | var storage={ 6 | config:{ 7 | 8 | }, 9 | user:{ 10 | 11 | }, 12 | userInfo:{ 13 | 14 | }, 15 | tab_share:{ 16 | 17 | }, 18 | tab_ask:{ 19 | 20 | }, 21 | tab_job:{ 22 | 23 | }, 24 | messages:{ 25 | 26 | }, 27 | } -------------------------------------------------------------------------------- /androidApp/reducers/configReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/7. 3 | */ 4 | 5 | var types = require('../actions/ActionTypes') 6 | 7 | var initialState = { 8 | initComplete: false 9 | } 10 | 11 | export default function configReducer(state = initialState, action={}) { 12 | switch (action.type) { 13 | case types.LOAD_CONFIG_SUCCESS: 14 | return { 15 | ...state, 16 | config:action.results 17 | } 18 | 19 | case types.INIT_CONFIG_SUCCESS: 20 | return { 21 | ...state, 22 | config:action.results, 23 | initComplete:true 24 | } 25 | case types.SET_CONFIG_SUCCESS: 26 | return { 27 | ...state, 28 | config:action.results 29 | } 30 | case types.RESTORE_CONFIG_SUCCESS: 31 | return { 32 | ...state, 33 | config:action.results 34 | } 35 | default : 36 | return state 37 | } 38 | } -------------------------------------------------------------------------------- /androidApp/reducers/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/10/14. 3 | */ 4 | 5 | import { combineReducers } from 'redux'; 6 | import configState from './configReducer' 7 | import topicState from './topicReducer' 8 | import userState from './userReducer.js' 9 | 10 | const rootReducer = combineReducers({ 11 | configState,topicState,userState 12 | }); 13 | 14 | export default rootReducer; -------------------------------------------------------------------------------- /androidApp/reducers/topicReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/8. 3 | */ 4 | 5 | var types = require('../actions/ActionTypes') 6 | 7 | var initialState = { 8 | upSuccess:false, 9 | replySuccess:false, 10 | publishSuccess:false 11 | } 12 | 13 | export default function configReducer(state = initialState, action={}) { 14 | switch (action.type) { 15 | case types.UP_COMMENT_SUCCESS: 16 | return { 17 | ...state, 18 | upSuccess:true 19 | } 20 | case types.UP_COMMENT_FAILED: 21 | return { 22 | ...state, 23 | upSuccess:false 24 | } 25 | case types.REPLY_SUCCESS: 26 | return { 27 | ...state, 28 | replySuccess:true 29 | } 30 | case types.REPLY_SET_FALSE: 31 | return { 32 | ...state, 33 | replySuccess:false 34 | } 35 | case types.PUBLISH_SUCCESS: 36 | return { 37 | ...state, 38 | publishSuccess:true 39 | } 40 | case types.PUBLISH_SET_FALSE: 41 | return { 42 | ...state, 43 | publishSuccess:false 44 | } 45 | default : 46 | return state 47 | } 48 | } -------------------------------------------------------------------------------- /androidApp/reducers/userReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/14. 3 | */ 4 | 5 | var types = require('../actions/ActionTypes') 6 | var React = require('react-native') 7 | 8 | var AsyncStorage = React.AsyncStorage 9 | 10 | var initialState = { 11 | isLogin:false, 12 | userData:null, 13 | accesstoken:null 14 | } 15 | 16 | export default function userReducer(state = initialState, action={}) { 17 | switch (action.type) { 18 | case types.CHECK_TOKEN_SUCCESS: 19 | return { 20 | ...state, 21 | userData:action.userData, 22 | isLogin:true, 23 | accesstoken:action.accesstoken 24 | } 25 | case types.CHECK_TOKEN_FAILED: 26 | return{ 27 | ...state, 28 | isLogin:false, 29 | error:action.err 30 | } 31 | case types.LOAD_USER_SUCCESS: 32 | return { 33 | ...state, 34 | userData:action.results, 35 | isLogin:true, 36 | accesstoken:action.accesstoken 37 | } 38 | case types.LOAD_USER_FAILED: 39 | return{ 40 | ...state, 41 | isLogin:false, 42 | err:null 43 | } 44 | case types.LOGOUT: 45 | return{ 46 | ...state, 47 | isLogin:false, 48 | userData:null, 49 | accesstoken:null, 50 | err:null 51 | } 52 | case types.LOAD_TOKEN_SUCCESS: 53 | return{ 54 | ...state, 55 | accesstoken:action.accesstoken 56 | } 57 | case types.LOAD_USERID_SUCCESS: 58 | return{ 59 | ...state, 60 | userId:action.userId 61 | } 62 | default : 63 | return state 64 | } 65 | } -------------------------------------------------------------------------------- /androidApp/services/ConfigService.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by liujia on 2015/12/7. 3 | */ 4 | var Storage = require('./Storage') 5 | import initConfig from "../configs/initConfig" 6 | import {STORAGE_KEY_CONFIG} from "../configs/Constants" 7 | 8 | var storage = {} 9 | 10 | storage.get = function () { 11 | return Storage.getItem(STORAGE_KEY_CONFIG) 12 | } 13 | 14 | storage.save = function (value) { 15 | return Storage.setItem(STORAGE_KEY_CONFIG, value) 16 | } 17 | 18 | storage.remove = function () { 19 | return Storage.removeItem(STORAGE_KEY_CONFIG) 20 | } 21 | 22 | var req = {} 23 | 24 | req.loadConfig=function() { 25 | return storage.get() 26 | } 27 | 28 | req.initConfig=function() { 29 | return storage.get().then( 30 | value=>{ 31 | if(!value) { 32 | storage.save(initConfig) 33 | return storage.get() 34 | } 35 | } 36 | ) 37 | 38 | } 39 | 40 | req.restoreConfig=function(){ 41 | storage.save(initConfig) 42 | return storage.get() 43 | } 44 | 45 | req.setConfig=function(valee){ 46 | storage.save(valee) 47 | return storage.get() 48 | } 49 | 50 | req.removeConfig=function() { 51 | return storage.remove() 52 | } 53 | 54 | exports.configService = req -------------------------------------------------------------------------------- /androidApp/services/MessageService.js: -------------------------------------------------------------------------------- 1 | var Storage = require('./Storage') 2 | var request = require('./Request') 3 | var config = require('../configs/config') 4 | 5 | var storage = {} 6 | 7 | storage.get = function () { 8 | return Storage.getItem('messages') 9 | } 10 | 11 | storage.save = function (value) { 12 | return Storage.setItem('messages', value) 13 | } 14 | 15 | storage.remove = function () { 16 | return Storage.removeItem('messages') 17 | } 18 | 19 | 20 | var req = {} 21 | 22 | req.get = function (token) { 23 | let apiUrl = config.domain + config.apiPath + '/messages' + '?accesstoken=' + token 24 | return request.get(apiUrl) 25 | .then((data)=>data.data) 26 | .then((messages)=> { 27 | if (messages) { 28 | storage.save(messages) 29 | return messages 30 | } 31 | else { 32 | throw 'getMessagesFailed' 33 | } 34 | }) 35 | } 36 | 37 | req.markAsRead = function (token) { 38 | let apiUrl = config.domain + config.apiPath + '/message/mark_all' 39 | 40 | return request.post(apiUrl, { 41 | accesstoken: token 42 | }) 43 | .then(data=> { 44 | console.log(data); 45 | if (data.success) { 46 | return data 47 | } 48 | else { 49 | throw 'markAsReadFailed' 50 | } 51 | }) 52 | } 53 | 54 | 55 | req.getUnreadMessageCount = function (token) { 56 | let url = config.domain + config.apiPath + '/message/count' 57 | return request.get(url, { 58 | accesstoken: token 59 | }) 60 | .then(data=>data.data) 61 | } 62 | 63 | 64 | exports.storage = storage 65 | exports.req = req 66 | -------------------------------------------------------------------------------- /androidApp/services/Request.js: -------------------------------------------------------------------------------- 1 | var queryString = require('query-string') 2 | 3 | var request = {} 4 | 5 | request.get = function (url, params) { 6 | if (params) { 7 | url += '?' + queryString.stringify(params) 8 | } 9 | return fetch(url) 10 | .then(res=>res.json()) 11 | } 12 | 13 | 14 | request.post = function (url, body) { 15 | let fetchOptions = { 16 | method: 'POST', 17 | headers: { 18 | 'Accept': 'application/json', 19 | 'Content-Type': 'application/json' 20 | }, 21 | body: JSON.stringify(body) 22 | } 23 | 24 | return fetch(url, fetchOptions) 25 | .then(res=>res.json()) 26 | } 27 | 28 | 29 | module.exports = request -------------------------------------------------------------------------------- /androidApp/services/Storage.js: -------------------------------------------------------------------------------- 1 | var React = require('react-native') 2 | 3 | var AsyncStorage = React.AsyncStorage 4 | 5 | var Storage = {} 6 | 7 | Storage.setItem = function (key, value) { 8 | if (value == null) return Promise.reject('value is null') 9 | return AsyncStorage.setItem(key, JSON.stringify(value)) 10 | } 11 | 12 | Storage.getItem = function (key) { 13 | var result = AsyncStorage.getItem(key) 14 | .then(function (value) { 15 | return JSON.parse(value) 16 | }) 17 | 18 | return result 19 | } 20 | 21 | Storage.clear = AsyncStorage.clear 22 | 23 | Storage.removeItem = AsyncStorage.removeItem 24 | 25 | Storage.multiGet = function (keys) { 26 | return AsyncStorage.multiGet(keys) 27 | .then(results=> { 28 | return results.map(item=> { 29 | return [item[0], JSON.parse(item[1])] 30 | }) 31 | }) 32 | } 33 | Storage.multiSet = function (keys) { 34 | return AsyncStorage.multiSet(keys) 35 | } 36 | 37 | Storage.multiRemove = function (keys) { 38 | return AsyncStorage.multiRemove(keys) 39 | } 40 | 41 | module.exports = Storage 42 | -------------------------------------------------------------------------------- /androidApp/services/TopicService.js: -------------------------------------------------------------------------------- 1 | var request = require('./Request') 2 | var Storage = require('./Storage') 3 | 4 | var config = require('../configs/config') 5 | var tabs = ['good', 'ask', 'all', 'share', 'job'] 6 | 7 | var storage = {} 8 | 9 | storage.get = function (tab) { 10 | return Storage.getItem('tab_' + tab) 11 | .then(topics=> { 12 | if (topics) { 13 | return topics 14 | } 15 | throw 'topicsInStorageIsEmpty' 16 | }) 17 | } 18 | 19 | storage.getAll = function () { 20 | return Storage.multiGet(tabs.map(tab=> { 21 | return 'tab_' + tab 22 | })) 23 | } 24 | 25 | storage.remove = function () { 26 | return Storage.multiRemove(tabs.map(tab=> { 27 | return 'tab_' + tab 28 | })) 29 | } 30 | 31 | storage.set=function(tab,value){ 32 | return Storage.setItem('tab_' + tab,value) 33 | } 34 | 35 | var req = {} 36 | 37 | req.getTopicsByTab = function (params) { 38 | /* 39 | params:{ 40 | page:Number, 41 | tab:String 42 | } 43 | */ 44 | var url = config.domain + '/api/v1/topics' 45 | 46 | return request.get(url, params) 47 | .then(data=>data.data) 48 | .then(topics => { 49 | if (params.page == 1 && topics) { 50 | Storage.setItem('tab_' + params.tab, topics) 51 | } 52 | return topics 53 | }) 54 | } 55 | 56 | req.getTopicById = function (id) { 57 | let url = config.domain + '/api/v1/topic/' + id 58 | return request.get(url) 59 | .then(data=>data.data) 60 | .then(topic=> { 61 | if (topic && topic.id) { 62 | return topic 63 | } 64 | throw 'GetTopicError' 65 | }) 66 | } 67 | 68 | 69 | req.markTopicAsLike = function (id, token, isLiked) { 70 | var apiUrl = config.domain + config.apiPath 71 | 72 | if (!isLiked) { 73 | apiUrl += '/topic/collect' 74 | } 75 | else { 76 | apiUrl += '/topic/de_collect' 77 | } 78 | 79 | 80 | return request.post(apiUrl, { 81 | accesstoken: token, 82 | topic_id: id 83 | }) 84 | .then(data => { 85 | if (!data.success) { 86 | throw 'error' 87 | } 88 | return data 89 | }) 90 | } 91 | 92 | req.reply = function (topicId, content, token, replyId) { 93 | let apiUrl = config.domain + config.apiPath 94 | var body = { 95 | accesstoken: token, 96 | content: content 97 | } 98 | if (replyId) { 99 | body.reply_id = replyId 100 | } 101 | let url = `${apiUrl}/topic/${topicId}/replies` 102 | 103 | return request.post(url, body) 104 | .then(data=> { 105 | if (data.success) { 106 | return data.reply_id 107 | } 108 | else { 109 | throw 'do reply failed' 110 | } 111 | }) 112 | } 113 | 114 | req.upComment = function (replyId, token) { 115 | let apiUrl = config.domain + config.apiPath 116 | var body = { 117 | accesstoken: token 118 | } 119 | 120 | let url = `${apiUrl}/reply/${replyId}/ups` 121 | 122 | return request.post(url, body) 123 | .then(data=> { 124 | if (data.success) { 125 | return data.action == 'up' 126 | } 127 | else { 128 | throw 'do reply failed' 129 | } 130 | }) 131 | } 132 | 133 | 134 | req.publish = function (title, tab, content, token) { 135 | let url = `${config.domain + config.apiPath}/topics` 136 | const body = { 137 | title: title, 138 | tab: tab, 139 | content: content, 140 | accesstoken: token 141 | } 142 | return request.post(url, body) 143 | .then(data=> { 144 | if (data.success) { 145 | return data.topic_id 146 | } 147 | throw 'publish failed' 148 | }) 149 | } 150 | 151 | 152 | exports.storage = storage 153 | exports.req = req 154 | -------------------------------------------------------------------------------- /androidApp/services/UserService.js: -------------------------------------------------------------------------------- 1 | var Storage = require('./Storage') 2 | var config = require('../configs/config') 3 | var request = require('./Request') 4 | 5 | var storage = {} 6 | 7 | storage.logout=function(){ 8 | return Storage.multiRemove(['userInfo','accesstoken']) 9 | } 10 | 11 | storage.clearUserInfo = function () { 12 | return Storage.removeItem('userInfo') 13 | } 14 | 15 | storage.saveUserInfo = function (userInfo) { 16 | return Storage.setItem('userInfo', userInfo) 17 | } 18 | 19 | storage.getUserInfo = function () { 20 | return Storage.getItem('userInfo') 21 | } 22 | 23 | storage.getUserAndUserInfo = function () { 24 | return Promise.all([ 25 | storage.getUser(), 26 | storage.getUserInfo() 27 | ]) 28 | .then(results=> { 29 | return { 30 | user: results[0], 31 | userInfo: results[1] 32 | } 33 | }) 34 | } 35 | 36 | storage.multiGet=function() 37 | { 38 | return Storage.multiGet(['userInfo','accesstoken']) 39 | } 40 | 41 | var req = {} 42 | 43 | req.loadUser=function() { 44 | return storage.getUserInfo() 45 | } 46 | 47 | req.getLoginUserInfo = function (user) { 48 | var apiUrl = config.domain + config.apiPath 49 | 50 | return request.get(apiUrl + '/user/' + user.loginname) 51 | .then((data)=>data.data) 52 | .then(userInfo=> { 53 | if (userInfo) { 54 | Storage.setItem('userInfo', userInfo) 55 | return userInfo 56 | } 57 | return Storage.getItem('userInfo') 58 | }) 59 | } 60 | 61 | 62 | req.getUserInfo = function (userName) { 63 | var apiUrl = config.domain + config.apiPath 64 | 65 | return request.get(apiUrl + '/user/' + userName) 66 | .then(data=> { 67 | if (data.error_msg) { 68 | throw 'UserNotExist' 69 | } 70 | return data 71 | }) 72 | .then((data)=>data.data) 73 | } 74 | 75 | 76 | 77 | req.checkToken = function (token) { 78 | var apiUrl = config.domain + config.apiPath + '/accesstoken' 79 | return request.post(apiUrl, { 80 | accesstoken: token 81 | }) 82 | .then(data => { 83 | if (data.success) { 84 | Storage.setItem('userId', data.id) 85 | Storage.setItem('accesstoken', token) 86 | return data 87 | } 88 | throw 'wrong token' 89 | }) 90 | } 91 | 92 | req.loadToken=function(){ 93 | return Storage.getItem('accesstoken') 94 | } 95 | req.loadUserId=function(){ 96 | return Storage.getItem('userId') 97 | } 98 | 99 | exports.storage = storage 100 | exports.req = req 101 | -------------------------------------------------------------------------------- /androidApp/util/cnodeUtil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by mars on 2015/11/17. 3 | */ 4 | 5 | exports.getCategory=function(category) 6 | { 7 | const categoryDict={"ask":"提问","share":"分享","job":"招聘"} 8 | return categoryDict[category]?categoryDict[category]:category 9 | } -------------------------------------------------------------------------------- /androidApp/util/genColor.js: -------------------------------------------------------------------------------- 1 | var colors = ['#E74C3C', '#C0392B', '#1ABC9C', 2 | '#16A085', '#2ECC71', '#27AE60', '#3498DB', 3 | '#2980B9', '#9B59B6', '#8E44AD', '#34495E', 4 | '#2C3E50', '#E67E22', 5 | '#D35400', '#7F8C8D']; 6 | 7 | 8 | function getRandomNum(Min, Max) { 9 | var Range = Max - Min; 10 | var Rand = Math.random(); 11 | return (Min + Math.round(Rand * Range)); 12 | } 13 | 14 | module.exports = function () { 15 | return colors[getRandomNum(0, colors.length - 1)]; 16 | }; 17 | -------------------------------------------------------------------------------- /androidApp/util/window.js: -------------------------------------------------------------------------------- 1 | var React = require('react-native') 2 | var Dimensions = require('Dimensions') 3 | 4 | 5 | var { 6 | AlertIOS, 7 | LinkingIOS 8 | } = React 9 | 10 | 11 | // The Dimensions API may change, so I move to a single module 12 | exports.get = function () { 13 | return Dimensions.get('window') 14 | } 15 | 16 | 17 | exports.alert = function (content) { 18 | AlertIOS.alert(content) 19 | } 20 | 21 | 22 | exports.link = function (url) { 23 | LinkingIOS.canOpenURL(url, (supported) => { 24 | if (!supported) { 25 | console.warn("Can't support the url") 26 | } else { 27 | LinkingIOS.openURL(url) 28 | } 29 | }) 30 | } 31 | 32 | 33 | exports.parseImgUrl= function (url) { 34 | if (/^\/\/.*/.test(url)) { 35 | url = 'http:' + url 36 | } 37 | return url 38 | } 39 | -------------------------------------------------------------------------------- /image/about_header_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/image/about_header_bg.png -------------------------------------------------------------------------------- /image/defaultUser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/image/defaultUser.png -------------------------------------------------------------------------------- /image/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/image/error.png -------------------------------------------------------------------------------- /image/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/image/loading.gif -------------------------------------------------------------------------------- /image/user_detail_header_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/image/user_detail_header_bg.png -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | import React, 2 | { 3 | Component, 4 | AppRegistry 5 | } from 'react-native' 6 | 7 | import App from './androidApp/containers/app' 8 | 9 | class Noder extends Component { 10 | 11 | render() { 12 | return ( 13 | 14 | 15 | ) 16 | } 17 | } 18 | 19 | AppRegistry.registerComponent('cnodejs', () => Noder) 20 | -------------------------------------------------------------------------------- /index.ios.js: -------------------------------------------------------------------------------- 1 | import React, 2 | { 3 | Component, 4 | AppRegistry 5 | } from 'react-native' 6 | 7 | import App from './androidApp/containers/app' 8 | 9 | class Noder extends Component { 10 | 11 | render() { 12 | return ( 13 | 14 | 15 | ) 16 | } 17 | } 18 | 19 | AppRegistry.registerComponent('cnodejs', () => Noder) 20 | -------------------------------------------------------------------------------- /ios/cnodejs.xcodeproj/xcshareddata/xcschemes/cnodejs.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /ios/cnodejs/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ios/cnodejs/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import "RCTRootView.h" 13 | 14 | @implementation AppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | NSURL *jsCodeLocation; 19 | 20 | /** 21 | * Loading JavaScript code - uncomment the one you want. 22 | * 23 | * OPTION 1 24 | * Load from development server. Start the server from the repository root: 25 | * 26 | * $ npm start 27 | * 28 | * To run on device, change `localhost` to the IP address of your computer 29 | * (you can get this by typing `ifconfig` into the terminal and selecting the 30 | * `inet` value under `en0:`) and make sure your computer and iOS device are 31 | * on the same Wi-Fi network. 32 | */ 33 | 34 | jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"]; 35 | 36 | /** 37 | * OPTION 2 38 | * Load from pre-bundled file on disk. The static bundle is automatically 39 | * generated by "Bundle React Native code and images" build step. 40 | */ 41 | 42 | // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 43 | 44 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 45 | moduleName:@"cnodejs" 46 | initialProperties:nil 47 | launchOptions:launchOptions]; 48 | 49 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 50 | UIViewController *rootViewController = [UIViewController new]; 51 | rootViewController.view = rootView; 52 | self.window.rootViewController = rootViewController; 53 | [self.window makeKeyAndVisible]; 54 | return YES; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /ios/cnodejs/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ios/cnodejs/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /ios/cnodejs/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIAppFonts 6 | 7 | MaterialIcons.ttf 8 | Foundation.ttf 9 | Entypo.ttf 10 | EvilIcons.ttf 11 | FontAwesome.ttf 12 | Ionicons.ttf 13 | Octicons.ttf 14 | Zocial.ttf 15 | 16 | CFBundleDevelopmentRegion 17 | en 18 | LSApplicationCategoryType 19 | 20 | CFBundleExecutable 21 | $(EXECUTABLE_NAME) 22 | CFBundleIdentifier 23 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 24 | CFBundleInfoDictionaryVersion 25 | 6.0 26 | CFBundleName 27 | $(PRODUCT_NAME) 28 | CFBundlePackageType 29 | APPL 30 | CFBundleShortVersionString 31 | 1.0 32 | CFBundleSignature 33 | ???? 34 | CFBundleVersion 35 | 1 36 | LSRequiresIPhoneOS 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | NSLocationWhenInUseUsageDescription 53 | 54 | CFBundleDisplayName 55 | 56 | NSAppTransportSecurity 57 | 58 | NSAllowsArbitraryLoads 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /ios/cnodejs/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ios/cnodejsTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/cnodejsTests/cnodejsTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import "RCTLog.h" 14 | #import "RCTRootView.h" 15 | 16 | #define TIMEOUT_SECONDS 240 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface cnodejsTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation cnodejsTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /ios/main.jsbundle: -------------------------------------------------------------------------------- 1 | // Offline JS 2 | // To re-generate the offline bundle, run this from the root of your project: 3 | // 4 | // $ react-native bundle --minify 5 | // 6 | // See http://facebook.github.io/react-native/docs/runningondevice.html for more details. 7 | 8 | throw new Error('Offline JS file is empty. See iOS/main.jsbundle for instructions'); 9 | -------------------------------------------------------------------------------- /logo_og.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/logo_og.png -------------------------------------------------------------------------------- /my-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marsprince/react-native-cnodejs/cc8f725b8a2cff5bf003d7a27417cc857183213a/my-icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cnodejs", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node_modules/react-native/packager/packager.sh" 7 | }, 8 | "dependencies": { 9 | "moment": "^2.10.6", 10 | "query-string": "^3.0.0", 11 | "react-native": "^0.19.0", 12 | "react-native-barcodescanner": "^0.1.3", 13 | "react-native-camera": "^0.3.8", 14 | "react-native-drawer-layout": "^0.3.5", 15 | "react-native-html-render": "^1.0.2", 16 | "react-native-scrollable-tab-view": "^0.3.2", 17 | "react-native-vector-icons": "^1.1.0", 18 | "react-redux": "v3.1.2", 19 | "redux": "^3.0.5", 20 | "redux-thunk": "^1.0.1" 21 | } 22 | } 23 | --------------------------------------------------------------------------------