├── .watchmanconfig ├── App ├── I18n │ ├── af.json │ ├── am.json │ ├── ar.json │ ├── bg.json │ ├── ca.json │ ├── cs.json │ ├── da.json │ ├── de.json │ ├── el.json │ ├── es.json │ ├── et.json │ ├── fi.json │ ├── he.json │ ├── hi.json │ ├── hr.json │ ├── hu.json │ ├── id.json │ ├── it.json │ ├── ja.json │ ├── ko.json │ ├── lt.json │ ├── lv.json │ ├── ms.json │ ├── nb.json │ ├── nl.json │ ├── no.json │ ├── pl.json │ ├── pt.json │ ├── ro.json │ ├── ru.json │ ├── sk.json │ ├── sl.json │ ├── sr.json │ ├── sv.json │ ├── sw.json │ ├── th.json │ ├── tr.json │ ├── uk.json │ ├── vi.json │ ├── zh.json │ ├── zu.json │ ├── fil.json │ ├── fr.json │ ├── README.md │ └── english.json ├── Containers │ ├── ContactTest.js │ ├── Styles │ │ ├── README.md │ │ ├── DrawerContentStyle.js │ │ ├── APITestingScreenStyle.js │ │ ├── AllComponentsScreenStyle.js │ │ ├── PresentationScreenStyle.js │ │ ├── MapviewExampleStyle.js │ │ ├── AddContactModalStyle.js │ │ ├── RootContainerStyle.js │ │ ├── ListviewExampleStyle.js │ │ ├── UsageExamplesScreenStyle.js │ │ ├── GroupListScreenStyle.js │ │ ├── ListviewGridExampleStyle.js │ │ ├── GroupMembersScreenStyle.js │ │ ├── ThemeScreenStyle.js │ │ └── DeviceInfoScreenStyle.js │ ├── README.md │ ├── RootContainer.js │ ├── PresentationScreen.js │ └── DrawerContent.js ├── Lib │ ├── axios │ │ ├── index.js │ │ ├── component.json │ │ ├── lib │ │ │ ├── helpers │ │ │ │ ├── bind.js │ │ │ │ ├── README.md │ │ │ │ ├── combineURLs.js │ │ │ │ ├── normalizeHeaderName.js │ │ │ │ ├── isAbsoluteURL.js │ │ │ │ ├── spread.js │ │ │ │ ├── deprecatedMethod.js │ │ │ │ ├── parseHeaders.js │ │ │ │ ├── btoa.js │ │ │ │ ├── cookies.js │ │ │ │ └── buildURL.js │ │ │ ├── core │ │ │ │ ├── README.md │ │ │ │ ├── enhanceError.js │ │ │ │ ├── createError.js │ │ │ │ ├── transformData.js │ │ │ │ ├── settle.js │ │ │ │ ├── InterceptorManager.js │ │ │ │ └── dispatchRequest.js │ │ │ ├── adapters │ │ │ │ └── README.md │ │ │ ├── axios.js │ │ │ └── defaults.js │ │ ├── http_proxy.txt │ │ ├── LICENSE │ │ └── axios.d.ts │ ├── README.md │ ├── Utilities.js │ ├── MapHelpers.js │ ├── apisauce │ │ └── package.json │ ├── PlatformStyleSheet.js │ └── WebIMConfig.js ├── Sdk │ ├── index.js │ ├── README.md │ ├── package.json │ ├── src │ │ └── emoji.js │ └── gulpfile.js ├── Images │ ├── BG.png │ ├── ir.png │ ├── chats.png │ ├── chats@2x.png │ ├── chats@3x.png │ ├── default.png │ ├── feedback.png │ ├── iconAdd.png │ ├── iconFile.png │ ├── logout.png │ ├── message.png │ ├── settings.png │ ├── tile_bg.png │ ├── top_logo.png │ ├── buttonCall.png │ ├── buttonChat.png │ ├── default@2x.png │ ├── default@3x.png │ ├── iconAdd@2x.png │ ├── iconAdd@3x.png │ ├── iconAudio.png │ ├── iconCamera.png │ ├── iconEmoji.png │ ├── iconImage.png │ ├── logoGreen.png │ ├── logout@2x.png │ ├── logout@3x.png │ ├── message@2x.png │ ├── message@3x.png │ ├── buttonCall@2x.png │ ├── buttonCall@3x.png │ ├── buttonChat@2x.png │ ├── buttonChat@3x.png │ ├── buttonVideo.png │ ├── feedback@2x.png │ ├── feedback@3x.png │ ├── groupDefault.png │ ├── iconAudio@2x.png │ ├── iconAudio@3x.png │ ├── iconCamera@2x.png │ ├── iconCamera@3x.png │ ├── iconEmoji@2x.png │ ├── iconEmoji@3x.png │ ├── iconFile@2x.png │ ├── iconFile@3x.png │ ├── iconImage@2x.png │ ├── iconImage@3x.png │ ├── iconLocation.png │ ├── ignite_logo.png │ ├── logoGreen@2x.png │ ├── logoGreen@3x.png │ ├── requestsIcon.png │ ├── settings@2x.png │ ├── settings@3x.png │ ├── top_logo@2x.png │ ├── top_logo@3x.png │ ├── buttonVideo@2x.png │ ├── buttonVideo@3x.png │ ├── contactsActive.png │ ├── groupDefault@2x.png │ ├── groupDefault@3x.png │ ├── iconEmojiActive.png │ ├── iconLocation@2x.png │ ├── iconLocation@3x.png │ ├── invitationsIcon.png │ ├── requestsIcon@2x.png │ ├── requestsIcon@3x.png │ ├── contactsActive@2x.png │ ├── contactsActive@3x.png │ ├── iconEmojiActive@2x.png │ ├── iconEmojiActive@3x.png │ ├── invitationsIcon@2x.png │ ├── invitationsIcon@3x.png │ ├── chatsActiveNotification.png │ ├── chatsActiveNotification@2x.png │ └── chatsActiveNotification@3x.png ├── Components │ ├── README.md │ ├── Styles │ │ ├── README.md │ │ ├── MapCalloutStyle.js │ │ ├── DrawerButtonStyles.js │ │ ├── ButtonStyle.js │ │ ├── FullButtonStyle.js │ │ ├── RoundedButtonStyle.js │ │ ├── AlertMessageStyle.js │ │ ├── CustomNavBarStyle.js │ │ ├── ModalHeaderStyle.js │ │ ├── InputStyle.js │ │ └── InfoNavBarStyle.js │ ├── TabIcon.js │ ├── CustomNavBar.js │ ├── DrawerButton.js │ ├── FullButton.js │ ├── RoundedButton.js │ ├── ModalHeader.js │ ├── Button.js │ ├── MapCallout.js │ ├── AlertMessage.js │ ├── Base.js │ ├── InfoNavBar.js │ └── Row.js ├── Themes │ ├── README.md │ ├── index.js │ ├── Metrics.js │ ├── Fonts.js │ ├── Images.js │ ├── Colors.js │ └── ApplicationStyles.js ├── Config │ ├── AppConfig.js │ ├── DebugSettings.js │ ├── README.md │ ├── index.js │ ├── ReduxPersist.js │ ├── PushConfig.js │ └── ReactotronConfig.js ├── Navigation │ ├── Styles │ │ ├── NavigationDrawerStyle.js │ │ ├── NavItemsStyle.js │ │ └── NavigationContainerStyle.js │ └── NavItems.js ├── Redux │ ├── StartupRedux.js │ ├── ContactsScreenRedux.js │ ├── CommonRedux.js │ ├── ContactInfoScreenRedux.js │ ├── DemoRedux.js │ ├── GroupMemberRedux.js │ ├── TemperatureRedux.js │ ├── index.js │ ├── GroupRedux.js │ ├── SubscribeRedux.js │ └── CreateStore.js ├── Fixtures │ ├── README.md │ ├── boise.json │ └── toronto.json ├── Transforms │ ├── ConvertFromKelvin.js │ └── README.md ├── Sagas │ ├── LoginSagas.js │ ├── StartupSagas.js │ ├── TemperatureSagas.js │ └── index.js └── Services │ ├── FixtureApi.js │ ├── ExamplesRegistry.js │ ├── RehydrationServices.js │ ├── ImmutablePersistenceTransform.js │ └── Api.js ├── .travis.yml ├── .env ├── main.jsbundle.meta ├── ios ├── main.jsbundle.meta ├── app │ ├── main.jsbundle.meta │ ├── Images.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Icon-76.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-76@2x.png │ │ │ ├── Icon-Small.png │ │ │ ├── Icon-83.5@2x.png │ │ │ ├── Icon-Small-60.png │ │ │ ├── Icon-Small@2x.png │ │ │ ├── Icon-Small@3x.png │ │ │ ├── Icon-Small-40@2x.png │ │ │ ├── Icon-Small-60@2x.png │ │ │ └── Icon-Small-60@3x.png │ │ └── LaunchImage.launchimage │ │ │ ├── Splash_iphone4.png │ │ │ ├── Splash_iphone5.png │ │ │ ├── Splash_iphone6.png │ │ │ ├── Splash_iphone6p.png │ │ │ └── Contents.json │ ├── AppDelegate.h │ ├── main.m │ └── AppDelegate.m ├── app.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── lwz.xcuserdatad │ │ │ └── WorkspaceSettings.xcsettings │ └── xcuserdata │ │ └── lwz.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── appTests │ ├── Info.plist │ └── appTests.m ├── android ├── app │ ├── hyphenate.keystore │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ └── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── assets │ │ │ └── fonts │ │ │ │ ├── Entypo.ttf │ │ │ │ ├── Zocial.ttf │ │ │ │ ├── EvilIcons.ttf │ │ │ │ ├── Foundation.ttf │ │ │ │ ├── Ionicons.ttf │ │ │ │ ├── Octicons.ttf │ │ │ │ ├── FontAwesome.ttf │ │ │ │ └── MaterialIcons.ttf │ │ │ ├── java │ │ │ └── com │ │ │ │ └── app │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── AndroidManifest.xml │ ├── my-release-key.keystore │ └── BUCK ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── keystores │ ├── debug.keystore.properties │ └── BUCK ├── build.gradle ├── app.iml ├── gradle.properties └── settings.gradle ├── .buckconfig ├── .babelrc ├── .ignite ├── .editorconfig ├── __tests__ ├── index.ios.js └── index.android.js ├── fastlane ├── Matchfile └── Appfile ├── index.android.js ├── index.ios.js ├── .gitignore ├── Tests ├── Services │ └── FixtureAPITest.js ├── Sagas │ ├── StartupSagaTest.js │ ├── LoginSagaTest.js │ └── TemperatureSagaTest.js ├── Reducers │ ├── LoginReducerTest.js │ └── TemperatureReducerTest.js ├── Components │ ├── DrawerButtonTest.js │ ├── FullButtonTest.js │ ├── RoundedButtonTest.js │ └── AlertMessageTest.js └── Setup.js ├── CHANGELOG.md ├── .tmp └── reactNativeBuild │ └── debuggerWorker.js └── .flowconfig /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /App/I18n/af.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/am.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/ar.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/bg.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/ca.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/cs.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/da.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/de.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/el.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/es.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/et.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/fi.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/he.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/hi.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/hr.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/hu.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/id.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/it.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/ja.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/ko.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/lt.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/lv.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/ms.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/nb.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/nl.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/no.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/pl.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/pt.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/ro.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/ru.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/sk.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/sl.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/sr.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/sv.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/sw.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/th.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/tr.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/uk.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/vi.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/zh.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/zu.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /App/I18n/fil.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | -------------------------------------------------------------------------------- /App/Containers/ContactTest.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /App/Lib/axios/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/axios'); -------------------------------------------------------------------------------- /App/Sdk/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src/connection') 2 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # Your secrets go here e.g. 2 | # MY_SECRET_API_KEY=tacosareawesome -------------------------------------------------------------------------------- /App/Images/BG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/BG.png -------------------------------------------------------------------------------- /App/Images/ir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/ir.png -------------------------------------------------------------------------------- /main.jsbundle.meta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/main.jsbundle.meta -------------------------------------------------------------------------------- /App/Components/README.md: -------------------------------------------------------------------------------- 1 | ### Copmonents Folder 2 | All components are stored and organized here 3 | -------------------------------------------------------------------------------- /App/Images/chats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/chats.png -------------------------------------------------------------------------------- /App/Components/Styles/README.md: -------------------------------------------------------------------------------- 1 | ### Styles Folder 2 | Component styles are separated from functionality. 3 | -------------------------------------------------------------------------------- /App/Containers/Styles/README.md: -------------------------------------------------------------------------------- 1 | ### Styles Folder 2 | Container styles are separated from functionality. 3 | -------------------------------------------------------------------------------- /App/Images/chats@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/chats@2x.png -------------------------------------------------------------------------------- /App/Images/chats@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/chats@3x.png -------------------------------------------------------------------------------- /App/Images/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/default.png -------------------------------------------------------------------------------- /App/Images/feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/feedback.png -------------------------------------------------------------------------------- /App/Images/iconAdd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconAdd.png -------------------------------------------------------------------------------- /App/Images/iconFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconFile.png -------------------------------------------------------------------------------- /App/Images/logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/logout.png -------------------------------------------------------------------------------- /App/Images/message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/message.png -------------------------------------------------------------------------------- /App/Images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/settings.png -------------------------------------------------------------------------------- /App/Images/tile_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/tile_bg.png -------------------------------------------------------------------------------- /App/Images/top_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/top_logo.png -------------------------------------------------------------------------------- /ios/main.jsbundle.meta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/main.jsbundle.meta -------------------------------------------------------------------------------- /App/Images/buttonCall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/buttonCall.png -------------------------------------------------------------------------------- /App/Images/buttonChat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/buttonChat.png -------------------------------------------------------------------------------- /App/Images/default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/default@2x.png -------------------------------------------------------------------------------- /App/Images/default@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/default@3x.png -------------------------------------------------------------------------------- /App/Images/iconAdd@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconAdd@2x.png -------------------------------------------------------------------------------- /App/Images/iconAdd@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconAdd@3x.png -------------------------------------------------------------------------------- /App/Images/iconAudio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconAudio.png -------------------------------------------------------------------------------- /App/Images/iconCamera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconCamera.png -------------------------------------------------------------------------------- /App/Images/iconEmoji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconEmoji.png -------------------------------------------------------------------------------- /App/Images/iconImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconImage.png -------------------------------------------------------------------------------- /App/Images/logoGreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/logoGreen.png -------------------------------------------------------------------------------- /App/Images/logout@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/logout@2x.png -------------------------------------------------------------------------------- /App/Images/logout@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/logout@3x.png -------------------------------------------------------------------------------- /App/Images/message@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/message@2x.png -------------------------------------------------------------------------------- /App/Images/message@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/message@3x.png -------------------------------------------------------------------------------- /App/Images/buttonCall@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/buttonCall@2x.png -------------------------------------------------------------------------------- /App/Images/buttonCall@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/buttonCall@3x.png -------------------------------------------------------------------------------- /App/Images/buttonChat@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/buttonChat@2x.png -------------------------------------------------------------------------------- /App/Images/buttonChat@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/buttonChat@3x.png -------------------------------------------------------------------------------- /App/Images/buttonVideo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/buttonVideo.png -------------------------------------------------------------------------------- /App/Images/feedback@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/feedback@2x.png -------------------------------------------------------------------------------- /App/Images/feedback@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/feedback@3x.png -------------------------------------------------------------------------------- /App/Images/groupDefault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/groupDefault.png -------------------------------------------------------------------------------- /App/Images/iconAudio@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconAudio@2x.png -------------------------------------------------------------------------------- /App/Images/iconAudio@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconAudio@3x.png -------------------------------------------------------------------------------- /App/Images/iconCamera@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconCamera@2x.png -------------------------------------------------------------------------------- /App/Images/iconCamera@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconCamera@3x.png -------------------------------------------------------------------------------- /App/Images/iconEmoji@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconEmoji@2x.png -------------------------------------------------------------------------------- /App/Images/iconEmoji@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconEmoji@3x.png -------------------------------------------------------------------------------- /App/Images/iconFile@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconFile@2x.png -------------------------------------------------------------------------------- /App/Images/iconFile@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconFile@3x.png -------------------------------------------------------------------------------- /App/Images/iconImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconImage@2x.png -------------------------------------------------------------------------------- /App/Images/iconImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconImage@3x.png -------------------------------------------------------------------------------- /App/Images/iconLocation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconLocation.png -------------------------------------------------------------------------------- /App/Images/ignite_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/ignite_logo.png -------------------------------------------------------------------------------- /App/Images/logoGreen@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/logoGreen@2x.png -------------------------------------------------------------------------------- /App/Images/logoGreen@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/logoGreen@3x.png -------------------------------------------------------------------------------- /App/Images/requestsIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/requestsIcon.png -------------------------------------------------------------------------------- /App/Images/settings@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/settings@2x.png -------------------------------------------------------------------------------- /App/Images/settings@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/settings@3x.png -------------------------------------------------------------------------------- /App/Images/top_logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/top_logo@2x.png -------------------------------------------------------------------------------- /App/Images/top_logo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/top_logo@3x.png -------------------------------------------------------------------------------- /ios/app/main.jsbundle.meta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/main.jsbundle.meta -------------------------------------------------------------------------------- /App/Images/buttonVideo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/buttonVideo@2x.png -------------------------------------------------------------------------------- /App/Images/buttonVideo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/buttonVideo@3x.png -------------------------------------------------------------------------------- /App/Images/contactsActive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/contactsActive.png -------------------------------------------------------------------------------- /App/Images/groupDefault@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/groupDefault@2x.png -------------------------------------------------------------------------------- /App/Images/groupDefault@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/groupDefault@3x.png -------------------------------------------------------------------------------- /App/Images/iconEmojiActive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconEmojiActive.png -------------------------------------------------------------------------------- /App/Images/iconLocation@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconLocation@2x.png -------------------------------------------------------------------------------- /App/Images/iconLocation@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconLocation@3x.png -------------------------------------------------------------------------------- /App/Images/invitationsIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/invitationsIcon.png -------------------------------------------------------------------------------- /App/Images/requestsIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/requestsIcon@2x.png -------------------------------------------------------------------------------- /App/Images/requestsIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/requestsIcon@3x.png -------------------------------------------------------------------------------- /android/app/hyphenate.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/hyphenate.keystore -------------------------------------------------------------------------------- /ios/app/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /App/Images/contactsActive@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/contactsActive@2x.png -------------------------------------------------------------------------------- /App/Images/contactsActive@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/contactsActive@3x.png -------------------------------------------------------------------------------- /App/Images/iconEmojiActive@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconEmojiActive@2x.png -------------------------------------------------------------------------------- /App/Images/iconEmojiActive@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/iconEmojiActive@3x.png -------------------------------------------------------------------------------- /App/Images/invitationsIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/invitationsIcon@2x.png -------------------------------------------------------------------------------- /App/Images/invitationsIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/invitationsIcon@3x.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Hyphenate JS 3 | 4 | -------------------------------------------------------------------------------- /android/app/my-release-key.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/my-release-key.keystore -------------------------------------------------------------------------------- /App/Images/chatsActiveNotification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/chatsActiveNotification.png -------------------------------------------------------------------------------- /App/Images/chatsActiveNotification@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/chatsActiveNotification@2x.png -------------------------------------------------------------------------------- /App/Images/chatsActiveNotification@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/App/Images/chatsActiveNotification@3x.png -------------------------------------------------------------------------------- /App/Themes/README.md: -------------------------------------------------------------------------------- 1 | ### Themes Folder 2 | Application specific themes 3 | * Base Styles 4 | * Fonts 5 | * Metrics 6 | * Colors 7 | 8 | etc. 9 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/assets/fonts/Entypo.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/assets/fonts/Zocial.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/assets/fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/assets/fonts/Foundation.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/assets/fonts/Ionicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/assets/fonts/Octicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "react-native" 4 | ], 5 | "env": { 6 | "development": { 7 | "sourceMaps": "inline" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.ignite: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | igniteVersion: '1.11.0', 3 | reactNativeVersion: '0.36.0', 4 | options: { 5 | testing: 'ava' 6 | }, 7 | plugins: {} 8 | } 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /App/Config/AppConfig.js: -------------------------------------------------------------------------------- 1 | // Simple React Native specific changes 2 | 3 | export default { 4 | // font scaling override - RN default is on 5 | allowTextFontScaling: true 6 | } 7 | -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small-60.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small-60@2x.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/AppIcon.appiconset/Icon-Small-60@3x.png -------------------------------------------------------------------------------- /android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = 'debug', 3 | store = 'debug.keystore', 4 | properties = 'debug.keystore.properties', 5 | visibility = [ 6 | 'PUBLIC', 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /ios/app/Images.xcassets/LaunchImage.launchimage/Splash_iphone4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/LaunchImage.launchimage/Splash_iphone4.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/LaunchImage.launchimage/Splash_iphone5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/LaunchImage.launchimage/Splash_iphone5.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/LaunchImage.launchimage/Splash_iphone6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/LaunchImage.launchimage/Splash_iphone6.png -------------------------------------------------------------------------------- /ios/app/Images.xcassets/LaunchImage.launchimage/Splash_iphone6p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easemob/webim-react-native/HEAD/ios/app/Images.xcassets/LaunchImage.launchimage/Splash_iphone6p.png -------------------------------------------------------------------------------- /App/Containers/Styles/DrawerContentStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export default { 4 | container: { 5 | flex: 1, 6 | padding: 20 7 | }, 8 | logo: { 9 | alignSelf: 'center' 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /App/Sdk/README.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.1.4 4 | 5 | * add browser version support umd 6 | * remove strophe from sdk because it't too big for webpack or other compiler 7 | 8 | ## todo 9 | 10 | * version semver -------------------------------------------------------------------------------- /App/Config/DebugSettings.js: -------------------------------------------------------------------------------- 1 | const SETTINGS = { 2 | useFixtures: false, 3 | ezLogin: false, 4 | yellowBox: __DEV__, 5 | reduxLogging: __DEV__, 6 | includeExamples: __DEV__ 7 | } 8 | 9 | export default SETTINGS 10 | -------------------------------------------------------------------------------- /App/Components/Styles/MapCalloutStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | 5 | export default StyleSheet.create({ 6 | callout: { 7 | position: 'relative', 8 | flex: 1 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /App/Config/README.md: -------------------------------------------------------------------------------- 1 | ### Config Folder 2 | All application specific configuration falls in this folder. 3 | 4 | `DebugSettings.js` is used for development-wide globals. 5 | `ReactotronConfig.js` is used for Reactotron client settings. 6 | -------------------------------------------------------------------------------- /App/Containers/Styles/APITestingScreenStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { ApplicationStyles } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | ...ApplicationStyles.screen 8 | }) 9 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /App/Lib/axios/component.json: -------------------------------------------------------------------------------- 1 | {"name":"axios","version":"0.9.1","description":"Promise based HTTP client for the browser and node.js","keywords":["xhr","http","ajax","promise","node"],"repo":{"type":"git","url":"https://github.com/mzabriskie/axios.git"},"license":"MIT"} 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | -------------------------------------------------------------------------------- /App/Navigation/Styles/NavigationDrawerStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {Colors} from '../../Themes/' 4 | 5 | export default { 6 | drawer: { 7 | backgroundColor: Colors.transparent 8 | }, 9 | main: { 10 | backgroundColor: Colors.snow 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /App/Components/Styles/DrawerButtonStyles.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { Metrics, Colors, Fonts } from '../../Themes' 4 | 5 | export default { 6 | text: { 7 | ...Fonts.style.h5, 8 | color: Colors.snow, 9 | marginVertical: Metrics.baseMargin 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ios/app.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Nov 21 11:50:05 CST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /App/Themes/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import Colors from './Colors' 4 | import Fonts from './Fonts' 5 | import Metrics from './Metrics' 6 | import Images from './Images' 7 | import ApplicationStyles from './ApplicationStyles' 8 | 9 | export { Colors, Fonts, Images, Metrics, ApplicationStyles } 10 | -------------------------------------------------------------------------------- /App/Redux/StartupRedux.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { createActions } from 'reduxsauce' 4 | 5 | /* ------------- Types and Action Creators ------------- */ 6 | 7 | const { Types, Creators } = createActions({ 8 | startup: null 9 | }) 10 | 11 | export const StartupTypes = Types 12 | export default Creators 13 | -------------------------------------------------------------------------------- /App/Fixtures/README.md: -------------------------------------------------------------------------------- 1 | ### Fixtures folder 2 | All key API responses are housed here. 3 | 4 | These API responses can be used for several reasons. _E.G._: 5 | * To bypass logins when building any screen of the application 6 | * To quickly test API parsing in unit tests 7 | * To separate Network from Data concerns while coding 8 | -------------------------------------------------------------------------------- /App/Containers/Styles/AllComponentsScreenStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { ApplicationStyles } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | ...ApplicationStyles.screen, 8 | groupContainer: { 9 | ...ApplicationStyles.groupContainer 10 | } 11 | }) 12 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/bind.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function bind(fn, thisArg) { 4 | return function wrap() { 5 | var args = new Array(arguments.length); 6 | for (var i = 0; i < args.length; i++) { 7 | args[i] = arguments[i]; 8 | } 9 | return fn.apply(thisArg, args); 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /__tests__/index.ios.js: -------------------------------------------------------------------------------- 1 | import 'react-native' 2 | import React from 'react' 3 | import Index from '../index.ios.js' 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer' 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ) 12 | }) 13 | -------------------------------------------------------------------------------- /App/Navigation/Styles/NavItemsStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {StyleSheet} from 'react-native' 4 | import { Metrics, Colors } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | navButtonLeft: { 8 | marginLeft: Metrics.baseMargin, 9 | backgroundColor: Colors.transparent, 10 | width: Metrics.icons.medium 11 | } 12 | }) 13 | -------------------------------------------------------------------------------- /__tests__/index.android.js: -------------------------------------------------------------------------------- 1 | import 'react-native' 2 | import React from 'react' 3 | import Index from '../index.android.js' 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer' 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ) 12 | }) 13 | -------------------------------------------------------------------------------- /App/Transforms/ConvertFromKelvin.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import I18n from 'react-native-i18n' 4 | 5 | export default (kelvin: number) => { 6 | const celcius = kelvin - 273.15 7 | const farenheit = (celcius * 1.8000) + 32 8 | 9 | if (I18n.t('tempIndicator') === 'F') { 10 | return Math.round(farenheit) 11 | } else { 12 | return Math.round(celcius) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/core/README.md: -------------------------------------------------------------------------------- 1 | # axios // core 2 | 3 | The modules found in `core/` should be modules that are specific to the domain logic of axios. These modules would most likely not make sense to be consumed outside of the axios module, as their logic is too specific. Some examples of core modules are: 4 | 5 | - Dispatching requests 6 | - Managing interceptors 7 | - Handling config 8 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/README.md: -------------------------------------------------------------------------------- 1 | # axios // helpers 2 | 3 | The modules found in `helpers/` should be generic modules that are _not_ specific to the domain logic of axios. These modules could theoretically be published to npm on their own and consumed by other modules or apps. Some examples of generic modules are things like: 4 | 5 | - Browser polyfills 6 | - Managing cookies 7 | - Parsing HTTP headers 8 | -------------------------------------------------------------------------------- /fastlane/Matchfile: -------------------------------------------------------------------------------- 1 | # git_url "git@github.com:infinitered/IgniteCerts.git" 2 | 3 | type "development" # The default type, can be: appstore, adhoc or development 4 | 5 | # app_identifier "tools.fastlane.app" 6 | # username "user@fastlane.tools" # Your Apple Developer Portal username 7 | 8 | # For all available options run `match --help` 9 | # Remove the # in the beginning of the line to enable the other options 10 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/combineURLs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Creates a new URL by combining the specified URLs 5 | * 6 | * @param {string} baseURL The base URL 7 | * @param {string} relativeURL The relative URL 8 | * @returns {string} The combined URL 9 | */ 10 | module.exports = function combineURLs(baseURL, relativeURL) { 11 | return baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, ''); 12 | }; 13 | -------------------------------------------------------------------------------- /App/Sagas/LoginSagas.js: -------------------------------------------------------------------------------- 1 | import { put } from 'redux-saga/effects' 2 | import LoginActions from '../Redux/LoginRedux' 3 | 4 | // attempts to login 5 | export function * login ({ username, password }) { 6 | if (password === '') { 7 | // dispatch failure 8 | yield put(LoginActions.loginFailure('WRONG')) 9 | } else { 10 | // dispatch successful logins 11 | yield put(LoginActions.loginSuccess(username)) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /App/Containers/Styles/PresentationScreenStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { Metrics, ApplicationStyles } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | ...ApplicationStyles.screen, 8 | logo: { 9 | height: Metrics.images.logo, 10 | width: Metrics.images.logo, 11 | resizeMode: 'contain' 12 | }, 13 | centered: { 14 | alignItems: 'center' 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/normalizeHeaderName.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('../utils'); 4 | 5 | module.exports = function normalizeHeaderName(headers, normalizedName) { 6 | utils.forEach(headers, function processHeader(value, name) { 7 | if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) { 8 | headers[normalizedName] = value; 9 | delete headers[name]; 10 | } 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import './App/Config/ReactotronConfig' 4 | import ReactNative, { AppRegistry, View } from 'react-native' 5 | 6 | // 兼容 0.39 版本的支持 7 | ReactNative.ViewPropTypes || ( ReactNative.ViewPropTypes = View.propTypes ); 8 | ReactNative.BackHandler || ( ReactNative.BackHandler = ReactNative.BackAndroid ); 9 | 10 | let App = require( './App/Containers/App' ).default; 11 | 12 | AppRegistry.registerComponent('app', () => App) 13 | -------------------------------------------------------------------------------- /index.ios.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import './App/Config/ReactotronConfig' 4 | import ReactNative, { AppRegistry, View } from 'react-native' 5 | 6 | // 兼容 0.39 版本的支持 7 | ReactNative.ViewPropTypes || ( ReactNative.ViewPropTypes = View.propTypes ); 8 | ReactNative.BackHandler || ( ReactNative.BackHandler = ReactNative.BackAndroid ); 9 | 10 | let App = require( './App/Containers/App' ).default; 11 | 12 | AppRegistry.registerComponent('app', () => App) 13 | -------------------------------------------------------------------------------- /App/Services/FixtureApi.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export default { 4 | // Functions return fixtures 5 | getCity: (city: string) => { 6 | // This fixture only supports Boise or else returns toronto 7 | const boiseData = require('../Fixtures/boise.json') 8 | const torontoData = require('../Fixtures/toronto.json') 9 | return { 10 | ok: true, 11 | data: city.toLowerCase() === 'boise' ? boiseData : torontoData 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/app/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.app; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "app"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /App/Lib/README.md: -------------------------------------------------------------------------------- 1 | # Lib 2 | 3 | At first glance, this could appear to be a "miscellaneous" folder, but we recommend that you treat this as proving ground for components that could be reuseable outside your project. 4 | 5 | Maybe you're writing a set of utilities that you could use outside your project, but they're not quite ready or battle tested. This folder would be a great place to put them. They ideally be pure functions have no dependencies on other things in your App folder. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | /.project 4 | .idea/* 5 | *.swp 6 | demo/javascript/dist/demo.js 7 | demo/javascript/dist/debug.js 8 | demo/javascript/dist/webim.config.js 9 | App/Sdk/dist/websdk-*.js 10 | webrtc/dist/webrtc-1.0.0.js 11 | publish/* 12 | /webrtc/dist/webrtc-1.0.0.js 13 | android/.gradle 14 | android/app/build 15 | android/build 16 | android/local.properties 17 | yarn-error.log 18 | ios/build 19 | npm-debug.log 20 | ios/app.xcodeproj/project.xcworkspace/xcuserdata/lwz.xcuserdatad 21 | -------------------------------------------------------------------------------- /App/Containers/Styles/MapviewExampleStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { ApplicationStyles } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | ...ApplicationStyles.screen, 8 | container: { 9 | flex: 1, 10 | justifyContent: 'flex-end', 11 | alignItems: 'center' 12 | }, 13 | map: { 14 | // For Android :/ 15 | position: 'absolute', 16 | top: 0, 17 | left: 0, 18 | right: 0, 19 | bottom: 0 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /ios/app/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 | -------------------------------------------------------------------------------- /Tests/Services/FixtureAPITest.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import API from '../../App/Services/Api' 3 | import FixtureAPI from '../../App/Services/FixtureApi' 4 | import R from 'ramda' 5 | 6 | test('All fixtures map to actual API', (t) => { 7 | const fixtureKeys = R.keys(FixtureAPI).sort() 8 | const apiKeys = R.keys(API.create()) 9 | 10 | const intersection = R.intersection(fixtureKeys, apiKeys).sort() 11 | 12 | // There is no difference between the intersection and all fixtures 13 | t.true(R.equals(fixtureKeys, intersection)) 14 | }) 15 | -------------------------------------------------------------------------------- /App/Config/index.js: -------------------------------------------------------------------------------- 1 | import { Text } from 'react-native' 2 | import DebugSettings from './DebugSettings' 3 | import AppConfig from './AppConfig' 4 | 5 | export default () => { 6 | if (__DEV__) { 7 | // If ReactNative's yellow box warnings are too much, it is possible to turn 8 | // it off, but the healthier approach is to fix the warnings. =) 9 | console.disableYellowBox = !DebugSettings.yellowBox 10 | } 11 | 12 | // Allow/disallow font-scaling in app 13 | Text.defaultProps.allowFontScaling = AppConfig.allowTextFontScaling 14 | } 15 | -------------------------------------------------------------------------------- /App/Components/Styles/ButtonStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { Fonts, Colors } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | button: { 8 | marginVertical: 5, 9 | borderRadius: 3, 10 | backgroundColor: Colors.button, 11 | paddingVertical: 10, 12 | paddingHorizontal: 20, 13 | height: 40, 14 | }, 15 | buttonText: { 16 | textAlign: 'center', 17 | color: Colors.snow, 18 | fontSize: Fonts.size.medium, 19 | fontFamily: Fonts.type.bold 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /ios/app/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 | -------------------------------------------------------------------------------- /App/Sagas/StartupSagas.js: -------------------------------------------------------------------------------- 1 | import { put, select } from 'redux-saga/effects' 2 | import TemperatureActions from '../Redux/TemperatureRedux' 3 | import { is } from 'ramda' 4 | 5 | // exported to make available for tests 6 | export const selectTemperature = (state) => state.temperature.temperature 7 | 8 | // process STARTUP actions 9 | export function * startup (action) { 10 | const temp = yield select(selectTemperature) 11 | // only fetch new temps when we don't have one yet 12 | if (!is(Number, temp)) { 13 | yield put(TemperatureActions.temperatureRequest('San Francisco')) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /App/Components/Styles/FullButtonStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { Fonts, Colors } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | button: { 8 | marginVertical: 5, 9 | borderTopColor: Colors.fire, 10 | borderBottomColor: Colors.bloodOrange, 11 | borderTopWidth: 1, 12 | borderBottomWidth: 1, 13 | backgroundColor: Colors.ember 14 | }, 15 | buttonText: { 16 | margin: 18, 17 | textAlign: 'center', 18 | color: Colors.snow, 19 | fontSize: Fonts.size.medium, 20 | fontFamily: Fonts.type.bold 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /Tests/Sagas/StartupSagaTest.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { select, put } from 'redux-saga/effects' 3 | import { selectTemperature, startup } from '../../App/Sagas/StartupSagas' 4 | import TemperatureActions from '../../App/Redux/TemperatureRedux' 5 | 6 | const stepper = (fn) => (mock) => fn.next(mock).value 7 | 8 | test('watches for the right action', (t) => { 9 | const step = stepper(startup()) 10 | TemperatureActions.temperatureRequest('San Francisco') 11 | t.deepEqual(step(), select(selectTemperature)) 12 | t.deepEqual(step(), put(TemperatureActions.temperatureRequest('San Francisco'))) 13 | }) 14 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/core/enhanceError.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Update an Error with the specified config, error code, and response. 5 | * 6 | * @param {Error} error The error to update. 7 | * @param {Object} config The config. 8 | * @param {string} [code] The error code (for example, 'ECONNABORTED'). 9 | @ @param {Object} [response] The response. 10 | * @returns {Error} The error. 11 | */ 12 | module.exports = function enhanceError(error, config, code, response) { 13 | error.config = config; 14 | if (code) { 15 | error.code = code; 16 | } 17 | error.response = response; 18 | return error; 19 | }; 20 | -------------------------------------------------------------------------------- /App/Transforms/README.md: -------------------------------------------------------------------------------- 1 | # Transforms 2 | 3 | A common pattern when working with APIs is to change data to play nice between your app & the API. 4 | 5 | We've found this to be the case in every project we've worked on. So much so that we're recommending that you create a folder dedicated to these transformations. 6 | 7 | Transforms are not necessarily a bad thing (although an API might have you transforming more than you'd like). 8 | 9 | For example, you may: 10 | 11 | * turn appropriate strings to date objects 12 | * convert snake case to camel case 13 | * normalize or denormalize things 14 | * create lookup tables 15 | -------------------------------------------------------------------------------- /App/Containers/Styles/AddContactModalStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {StyleSheet, PixelRatio} from 'react-native' 4 | import {Colors, Metrics} from '../../Themes' 5 | import {create} from '../../Lib/PlatformStyleSheet' 6 | 7 | export default create({ 8 | container: { 9 | flex: 1, 10 | justifyContent: 'flex-start', 11 | flexDirection: 'column' 12 | }, 13 | body: { 14 | // flex: 1, 15 | height: 200, 16 | marginTop: 100, 17 | justifyContent: 'center', 18 | alignItems: 'center', 19 | paddingHorizontal: 33 20 | }, 21 | button: { 22 | marginTop: 39, 23 | // flex: 0, 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /App/Containers/Styles/RootContainerStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {StyleSheet} from 'react-native' 4 | import {Fonts, Metrics, Colors} from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | applicationView: { 8 | flex: 1 9 | }, 10 | container: { 11 | flex: 1, 12 | justifyContent: 'center', 13 | backgroundColor: Colors.background 14 | }, 15 | welcome: { 16 | fontSize: 20, 17 | textAlign: 'center', 18 | fontFamily: Fonts.type.base, 19 | margin: Metrics.baseMargin 20 | }, 21 | myImage: { 22 | width: 200, 23 | height: 200, 24 | alignSelf: 'center' 25 | } 26 | }) 27 | -------------------------------------------------------------------------------- /App/Components/Styles/RoundedButtonStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { Fonts, Colors, Metrics } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | button: { 8 | height: 45, 9 | borderRadius: 5, 10 | marginHorizontal: Metrics.section, 11 | marginVertical: Metrics.baseMargin, 12 | backgroundColor: Colors.fire, 13 | justifyContent: 'center' 14 | }, 15 | buttonText: { 16 | color: Colors.snow, 17 | textAlign: 'center', 18 | fontWeight: 'bold', 19 | fontSize: Fonts.size.medium, 20 | marginVertical: Metrics.baseMargin 21 | } 22 | }) 23 | -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | # iOS 2 | # app_identifier "com.infinitered.ignite" # The bundle identifier of your app 3 | # apple_id "thisIsMe@gmail.com" # Your Apple email address 4 | # team_id "3FTD6ME549" # Developer Portal Team ID 5 | 6 | # Android 7 | # json_key_file "./google-play-api-secret.json" # Path to the json secret file - Follow https://github.com/fastlane/supply#setup to get one 8 | # package_name "com.infinitered.myapp" # You Android app package 9 | 10 | # you can even provide different app identifiers, Apple IDs and team names per lane: 11 | # More information: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Appfile.md 12 | -------------------------------------------------------------------------------- /App/Lib/axios/http_proxy.txt: -------------------------------------------------------------------------------- 1 | process.env.http_proxy 2 | 3 | var http = require("http"); 4 | 5 | var options = { 6 | host: "proxy", 7 | port: 8080, 8 | path: "http://www.google.com", 9 | headers: { 10 | Host: "www.google.com" 11 | } 12 | }; 13 | http.get(options, function(res) { 14 | console.log(res); 15 | res.pipe(process.stdout); 16 | }); 17 | 18 | 19 | process.env.https_proxy 20 | 21 | var http = require('http'); 22 | 23 | http.get ({ 24 | host: '127.0.0.1', 25 | port: 8888, 26 | path: 'https://www.google.com/accounts/OAuthGetRequestToken' 27 | }, function (response) { 28 | console.log (response); 29 | }); 30 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/isAbsoluteURL.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Determines whether the specified URL is absolute 5 | * 6 | * @param {string} url The URL to test 7 | * @returns {boolean} True if the specified URL is absolute, otherwise false 8 | */ 9 | module.exports = function isAbsoluteURL(url) { 10 | // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). 11 | // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed 12 | // by any combination of letters, digits, plus, period, or hyphen. 13 | return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url); 14 | }; 15 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/core/createError.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var enhanceError = require('./enhanceError'); 4 | 5 | /** 6 | * Create an Error with the specified message, config, error code, and response. 7 | * 8 | * @param {string} message The error message. 9 | * @param {Object} config The config. 10 | * @param {string} [code] The error code (for example, 'ECONNABORTED'). 11 | @ @param {Object} [response] The response. 12 | * @returns {Error} The created error. 13 | */ 14 | module.exports = function createError(message, config, code, response) { 15 | var error = new Error(message); 16 | return enhanceError(error, config, code, response); 17 | }; 18 | -------------------------------------------------------------------------------- /App/Config/ReduxPersist.js: -------------------------------------------------------------------------------- 1 | import immutablePersistenceTransform from '../Services/ImmutablePersistenceTransform' 2 | import { AsyncStorage } from 'react-native' 3 | 4 | const REDUX_PERSIST = { 5 | active: true, 6 | reducerVersion: '2', 7 | storeConfig: { 8 | storage: AsyncStorage, 9 | blacklist: ['login'], // reducer keys that you do NOT want stored to persistence here 10 | whitelist: [], // Optionally, just specify the keys you DO want stored to 11 | // persistence. An empty array means 'don't store any reducers' -> infinitered/ignite#409 12 | transforms: [immutablePersistenceTransform] 13 | } 14 | } 15 | 16 | export default REDUX_PERSIST 17 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/core/transformData.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./../utils'); 4 | 5 | /** 6 | * Transform the data for a request or a response 7 | * 8 | * @param {Object|String} data The data to be transformed 9 | * @param {Array} headers The headers for the request or response 10 | * @param {Array|Function} fns A single function or Array of functions 11 | * @returns {*} The resulting transformed data 12 | */ 13 | module.exports = function transformData(data, headers, fns) { 14 | /*eslint no-param-reassign:0*/ 15 | utils.forEach(fns, function transform(fn) { 16 | data = fn(data, headers); 17 | }); 18 | 19 | return data; 20 | }; 21 | -------------------------------------------------------------------------------- /App/Components/TabIcon.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | PropTypes, 3 | } from 'react'; 4 | import { 5 | Text, 6 | Image, 7 | View 8 | } from 'react-native'; 9 | 10 | const propTypes = { 11 | selected: PropTypes.bool, 12 | title: PropTypes.string, 13 | }; 14 | 15 | const TabIcon = (props) => ( 16 | 17 | {props.image ? : null} 18 | {props.title ? 21 | {props.title} 22 | : null 23 | } 24 | 25 | ); 26 | 27 | TabIcon.propTypes = propTypes; 28 | 29 | export default TabIcon; 30 | -------------------------------------------------------------------------------- /Tests/Sagas/LoginSagaTest.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import { put } from 'redux-saga/effects' 3 | import { login } from '../../App/Sagas/LoginSagas' 4 | import LoginActions from '../../App/Redux/LoginRedux' 5 | 6 | const stepper = (fn) => (mock) => fn.next(mock).value 7 | 8 | test('success', (t) => { 9 | const mock = { username: 'a', password: 'b' } 10 | const step = stepper(login(mock)) 11 | 12 | t.deepEqual(step(), put(LoginActions.loginSuccess(mock.username))) 13 | }) 14 | 15 | test('failure', (t) => { 16 | const mock = { username: '', password: '' } 17 | const step = stepper(login(mock)) 18 | 19 | t.deepEqual(step(), put(LoginActions.loginFailure('WRONG'))) 20 | }) 21 | -------------------------------------------------------------------------------- /App/Navigation/Styles/NavigationContainerStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {StyleSheet, Platform} from 'react-native' 3 | import {Colors} from '../../Themes/' 4 | 5 | export default { 6 | container: { 7 | flex: 1 8 | }, 9 | navBar: { 10 | backgroundColor: Colors.background 11 | }, 12 | title: { 13 | color: Colors.snow 14 | }, 15 | leftButton: { 16 | tintColor: Colors.snow 17 | }, 18 | rightButton: { 19 | color: Colors.snow 20 | }, 21 | tabBarStyle: { 22 | borderTopWidth: StyleSheet.hairlineWidth, 23 | borderColor: '#b7b7b7', 24 | backgroundColor: Colors.white1, 25 | justifyContent: 'center', 26 | opacity: 1, 27 | height: 50, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /App/Redux/ContactsScreenRedux.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {createReducer, createActions} from 'reduxsauce' 4 | import Immutable from 'seamless-immutable' 5 | 6 | /* ------------- Types and Action Creators ------------- */ 7 | 8 | const {Types, Creators} = createActions({ 9 | nop: null 10 | }) 11 | 12 | export const ContactsTypes = Types 13 | export default Creators 14 | 15 | /* ------------- Initial State ------------- */ 16 | export const INITIAL_STATE = Immutable({}) 17 | 18 | /* ------------- Reducers ------------- */ 19 | 20 | /* ------------- Hookup Reducers To Types ------------- */ 21 | export const reducer = createReducer(INITIAL_STATE, {}) 22 | 23 | /* ------------- Selectors ------------- */ 24 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/spread.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Syntactic sugar for invoking a function and expanding an array for arguments. 5 | * 6 | * Common use case would be to use `Function.prototype.apply`. 7 | * 8 | * ```js 9 | * function f(x, y, z) {} 10 | * var args = [1, 2, 3]; 11 | * f.apply(null, args); 12 | * ``` 13 | * 14 | * With `spread` this example can be re-written. 15 | * 16 | * ```js 17 | * spread(function(x, y, z) {})([1, 2, 3]); 18 | * ``` 19 | * 20 | * @param {Function} callback 21 | * @returns {Function} 22 | */ 23 | module.exports = function spread(callback) { 24 | return function wrap(arr) { 25 | return callback.apply(null, arr); 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /App/Components/Styles/AlertMessageStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { Colors, Metrics, Fonts } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | container: { 8 | justifyContent: 'center', 9 | marginVertical: Metrics.section 10 | }, 11 | contentContainer: { 12 | alignSelf: 'center', 13 | alignItems: 'center' 14 | }, 15 | message: { 16 | marginTop: Metrics.baseMargin, 17 | marginHorizontal: Metrics.baseMargin, 18 | textAlign: 'center', 19 | fontFamily: Fonts.type.base, 20 | fontSize: Fonts.size.regular, 21 | fontWeight: 'bold', 22 | color: Colors.steel 23 | }, 24 | icon: { 25 | color: Colors.steel 26 | } 27 | }) 28 | -------------------------------------------------------------------------------- /App/Sagas/TemperatureSagas.js: -------------------------------------------------------------------------------- 1 | import { call, put } from 'redux-saga/effects' 2 | import { path } from 'ramda' 3 | import TemperatureActions from '../Redux/TemperatureRedux' 4 | import convertFromKelvin from '../Transforms/ConvertFromKelvin' 5 | 6 | export function * getTemperature (api, action) { 7 | const { city } = action 8 | // make the call to the api 9 | const response = yield call(api.getCity, city) 10 | 11 | // success? 12 | if (response.ok) { 13 | const kelvin = path(['data', 'main', 'temp_max'], response) 14 | const temperature = convertFromKelvin(kelvin) 15 | yield put(TemperatureActions.temperatureSuccess(temperature, 'bonus')) 16 | } else { 17 | yield put(TemperatureActions.temperatureFailure()) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ios/app.xcodeproj/xcuserdata/lwz.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | app.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 00E356ED1AD99517003FC87E 16 | 17 | primary 18 | 19 | 20 | 13B07F861A680F5B00A75B9A 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /App/Components/Styles/CustomNavBarStyle.js: -------------------------------------------------------------------------------- 1 | import { Colors, Metrics } from '../../Themes/' 2 | 3 | export default { 4 | container: { 5 | position: 'absolute', 6 | top: 0, 7 | left: 0, 8 | right: 0, 9 | height: Metrics.navBarHeight, 10 | paddingHorizontal: Metrics.baseMargin, 11 | backgroundColor: Colors.background, 12 | flexDirection: 'row', 13 | alignItems: 'center', 14 | justifyContent: 'space-between' 15 | }, 16 | leftButton: { 17 | paddingTop: Metrics.baseMargin 18 | }, 19 | logo: { 20 | height: Metrics.navBarHeight - Metrics.doubleBaseMargin, 21 | width: Metrics.navBarHeight - Metrics.doubleBaseMargin, 22 | resizeMode: 'contain' 23 | }, 24 | rightButton: { 25 | paddingTop: Metrics.baseMargin 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ios/app.xcodeproj/project.xcworkspace/xcuserdata/lwz.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildLocationStyle 6 | CustomLocation 7 | CustomBuildIntermediatesPath 8 | Build/Intermediates 9 | CustomBuildLocationType 10 | RelativeToWorkspace 11 | CustomBuildProductsPath 12 | Build/Products 13 | DerivedDataLocationStyle 14 | Default 15 | IssueFilterStyle 16 | ShowActiveSchemeOnly 17 | LiveSourceIssuesEnabled 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Tests/Reducers/LoginReducerTest.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import Actions, { reducer, INITIAL_STATE } from '../../App/Redux/LoginRedux' 3 | 4 | test('attempt', (t) => { 5 | const state = reducer(INITIAL_STATE, Actions.loginRequest('u', 'p')) 6 | 7 | t.true(state.fetching) 8 | }) 9 | 10 | test('success', (t) => { 11 | const state = reducer(INITIAL_STATE, Actions.loginSuccess('hi')) 12 | 13 | t.is(state.username, 'hi') 14 | }) 15 | 16 | test('failure', (t) => { 17 | const state = reducer(INITIAL_STATE, Actions.loginFailure(69)) 18 | 19 | t.false(state.fetching) 20 | t.is(state.error, 69) 21 | }) 22 | 23 | test('logout', (t) => { 24 | const loginState = reducer(INITIAL_STATE, Actions.loginSuccess('hi')) 25 | const state = reducer(loginState, Actions.logout()) 26 | 27 | t.falsy(state.username) 28 | }) 29 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/core/settle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var createError = require('./createError'); 4 | 5 | /** 6 | * Resolve or reject a Promise based on response status. 7 | * 8 | * @param {Function} resolve A function that resolves the promise. 9 | * @param {Function} reject A function that rejects the promise. 10 | * @param {object} response The response. 11 | */ 12 | module.exports = function settle(resolve, reject, response) { 13 | var validateStatus = response.config.validateStatus; 14 | // Note: status is not exposed by XDomainRequest 15 | if (!response.status || !validateStatus || validateStatus(response.status)) { 16 | resolve(response); 17 | } else { 18 | reject(createError( 19 | 'Request failed with status code ' + response.status, 20 | response.config, 21 | null, 22 | response 23 | )); 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/deprecatedMethod.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*eslint no-console:0*/ 4 | 5 | /** 6 | * Supply a warning to the developer that a method they are using 7 | * has been deprecated. 8 | * 9 | * @param {string} method The name of the deprecated method 10 | * @param {string} [instead] The alternate method to use if applicable 11 | * @param {string} [docs] The documentation URL to get further details 12 | */ 13 | module.exports = function deprecatedMethod(method, instead, docs) { 14 | try { 15 | console.warn( 16 | 'DEPRECATED method `' + method + '`.' + 17 | (instead ? ' Use `' + instead + '` instead.' : '') + 18 | ' This method will be removed in a future release.'); 19 | 20 | if (docs) { 21 | console.warn('For more information about usage see ' + docs); 22 | } 23 | } catch (e) { /* Ignore */ } 24 | }; 25 | -------------------------------------------------------------------------------- /Tests/Reducers/TemperatureReducerTest.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import Actions, { reducer, INITIAL_STATE } from '../../App/Redux/TemperatureRedux' 3 | 4 | test('request', (t) => { 5 | const cityName = 'someCity' 6 | const state = reducer(INITIAL_STATE, Actions.temperatureRequest(cityName)) 7 | 8 | t.true(state.fetching) 9 | t.is(state.city, cityName) 10 | t.is(null, state.temperature) 11 | }) 12 | 13 | test('success', (t) => { 14 | const cityTemp = 69 15 | const state = reducer(INITIAL_STATE, Actions.temperatureSuccess(cityTemp)) 16 | 17 | t.false(state.fetching) 18 | t.is(state.temperature, cityTemp) 19 | t.is(null, state.error) 20 | }) 21 | 22 | test('failure', (t) => { 23 | const state = reducer(INITIAL_STATE, Actions.temperatureFailure()) 24 | 25 | t.false(state.fetching) 26 | t.true(state.error) 27 | t.is(null, state.temperature) 28 | }) 29 | -------------------------------------------------------------------------------- /App/Components/CustomNavBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { View, Image, Animated, TouchableOpacity } from 'react-native' 3 | import { Images, Colors } from '../Themes' 4 | import Styles from './Styles/CustomNavBarStyle' 5 | import Icon from 'react-native-vector-icons/Ionicons' 6 | import { Actions as NavigationActions } from 'react-native-router-flux' 7 | 8 | export default class CustomNavBar extends React.Component { 9 | render () { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ) 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /ios/appTests/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 | -------------------------------------------------------------------------------- /App/Containers/Styles/ListviewExampleStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { ApplicationStyles, Metrics, Colors } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | ...ApplicationStyles.screen, 8 | container: { 9 | flex: 1, 10 | marginTop: Metrics.navBarHeight, 11 | backgroundColor: Colors.background 12 | }, 13 | row: { 14 | flex: 1, 15 | backgroundColor: Colors.fire, 16 | marginVertical: Metrics.smallMargin, 17 | justifyContent: 'center' 18 | }, 19 | boldLabel: { 20 | fontWeight: 'bold', 21 | alignSelf: 'center', 22 | color: Colors.snow, 23 | textAlign: 'center', 24 | marginBottom: Metrics.smallMargin 25 | }, 26 | label: { 27 | textAlign: 'center', 28 | color: Colors.snow 29 | }, 30 | listContent: { 31 | marginTop: Metrics.baseMargin 32 | } 33 | }) 34 | -------------------------------------------------------------------------------- /App/Fixtures/boise.json: -------------------------------------------------------------------------------- 1 | { 2 | "coord":{ 3 | "lon":-116.2, 4 | "lat":43.61 5 | }, 6 | "weather":[ 7 | { 8 | "id":803, 9 | "main":"Clouds", 10 | "description":"broken clouds", 11 | "icon":"04n" 12 | } 13 | ], 14 | "base":"stations", 15 | "main":{ 16 | "temp":294.76, 17 | "pressure":1015, 18 | "humidity":20, 19 | "temp_min":294.15, 20 | "temp_max":296.15 21 | }, 22 | "visibility":16093, 23 | "wind":{ 24 | "speed":3.6, 25 | "deg":130 26 | }, 27 | "clouds":{ 28 | "all":75 29 | }, 30 | "dt":1474172351, 31 | "sys":{ 32 | "type":1, 33 | "id":911, 34 | "message":0.0333, 35 | "country":"US", 36 | "sunrise":1474205304, 37 | "sunset":1474249684 38 | }, 39 | "id":5586437, 40 | "name":"Boise", 41 | "cod":200 42 | } -------------------------------------------------------------------------------- /App/Fixtures/toronto.json: -------------------------------------------------------------------------------- 1 | { 2 | "coord":{ 3 | "lon":-79.38, 4 | "lat":43.65 5 | }, 6 | "weather":[ 7 | { 8 | "id":701, 9 | "main":"Mist", 10 | "description":"mist", 11 | "icon":"50n" 12 | } 13 | ], 14 | "base":"stations", 15 | "main":{ 16 | "temp":292.05, 17 | "pressure":1012, 18 | "humidity":94, 19 | "temp_min":290.37, 20 | "temp_max":293.71 21 | }, 22 | "visibility":14484, 23 | "wind":{ 24 | "speed":3.1, 25 | "deg":230 26 | }, 27 | "clouds":{ 28 | "all":1 29 | }, 30 | "dt":1474172343, 31 | "sys":{ 32 | "type":1, 33 | "id":3721, 34 | "message":0.037, 35 | "country":"CA", 36 | "sunrise":1474196460, 37 | "sunset":1474240859 38 | }, 39 | "id":6167863, 40 | "name":"Downtown Toronto", 41 | "cod":200 42 | } -------------------------------------------------------------------------------- /App/Sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easemob-websdk", 3 | "version": "1.1.7", 4 | "description": "Easemob im websdk", 5 | "keywords": [ 6 | "realtime", 7 | "im", 8 | "easemob", 9 | "xmpp", 10 | "strophe" 11 | ], 12 | "main": "index.js", 13 | "scripts": { 14 | "build": "gulp", 15 | "test": "echo \"Error: no test specified\" && exit 1" 16 | }, 17 | "author": "WytheMe", 18 | "license": "MIT", 19 | "dependencies": {}, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/easemob/web-im" 23 | }, 24 | "devDependencies": { 25 | "gulp-rename": "^1.2.2", 26 | "browserify": "^13.1.1", 27 | "gulp-sourcemaps": "^2.2.0", 28 | "gulp-uglify": "^2.0.0", 29 | "gulp-util": "^3.0.7", 30 | "vinyl-buffer": "^1.0.0", 31 | "vinyl-source-stream": "^1.1.0", 32 | "webpack-stream": "^3.2.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /App/Components/DrawerButton.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React, { Component } from 'react' 4 | import { Text, TouchableOpacity } from 'react-native' 5 | import styles from './Styles/DrawerButtonStyles' 6 | import ExamplesRegistry from '../Services/ExamplesRegistry' 7 | 8 | // Example 9 | ExamplesRegistry.add('Drawer Button', () => 10 | window.alert('Your drawers are showing')} 13 | /> 14 | ) 15 | 16 | type DrawerButtonProps = { 17 | text: string, 18 | onPress: () => void 19 | } 20 | 21 | class DrawerButton extends Component { 22 | props: DrawerButtonProps 23 | 24 | render () { 25 | return ( 26 | 27 | {this.props.text} 28 | 29 | ) 30 | } 31 | } 32 | 33 | export default DrawerButton 34 | -------------------------------------------------------------------------------- /App/Themes/Metrics.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {Dimensions, Platform} from 'react-native' 4 | 5 | const {width, height} = Dimensions.get('window') 6 | 7 | // Used via Metrics.baseMargin 8 | const metrics = { 9 | marginHorizontal: 10, 10 | marginVertical: 10, 11 | section: 25, 12 | baseMargin: 10, 13 | doubleBaseMargin: 20, 14 | smallMargin: 5, 15 | horizontalLineHeight: 1, 16 | screenWidth: width < height ? width : height, 17 | screenHeight: width < height ? height : width, 18 | navBarHeight: (Platform.OS === 'ios') ? 64 : 54, 19 | statusBarHeight: 20, 20 | buttonRadius: 4, 21 | icons: { 22 | tiny0: 13, 23 | tiny: 15, 24 | tiny2: 17, 25 | small: 20, 26 | medium: 30, 27 | large: 45, 28 | xl: 60 29 | }, 30 | images: { 31 | small: 20, 32 | medium: 40, 33 | large: 60, 34 | logo: 300 35 | } 36 | } 37 | 38 | export default metrics 39 | -------------------------------------------------------------------------------- /android/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /App/Components/FullButton.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React from 'react' 4 | import { TouchableOpacity, Text } from 'react-native' 5 | import styles from './Styles/FullButtonStyle' 6 | import ExamplesRegistry from '../Services/ExamplesRegistry' 7 | 8 | // Example 9 | ExamplesRegistry.add('Full Button', () => 10 | window.alert('Full Button Pressed!')} 13 | /> 14 | ) 15 | 16 | type FullButtonProps = { 17 | text: string, 18 | onPress: () => void, 19 | styles?: Object 20 | } 21 | 22 | export default class FullButton extends React.Component { 23 | props: FullButtonProps 24 | 25 | render () { 26 | return ( 27 | 28 | {this.props.text && this.props.text.toUpperCase()} 29 | 30 | ) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/parseHeaders.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./../utils'); 4 | 5 | /** 6 | * Parse headers into an object 7 | * 8 | * ``` 9 | * Date: Wed, 27 Aug 2014 08:58:49 GMT 10 | * Content-Type: application/json 11 | * Connection: keep-alive 12 | * Transfer-Encoding: chunked 13 | * ``` 14 | * 15 | * @param {String} headers Headers needing to be parsed 16 | * @returns {Object} Headers parsed into an object 17 | */ 18 | module.exports = function parseHeaders(headers) { 19 | var parsed = {}; 20 | var key; 21 | var val; 22 | var i; 23 | 24 | if (!headers) { return parsed; } 25 | 26 | utils.forEach(headers.split('\n'), function parser(line) { 27 | i = line.indexOf(':'); 28 | key = utils.trim(line.substr(0, i)).toLowerCase(); 29 | val = utils.trim(line.substr(i + 1)); 30 | 31 | if (key) { 32 | parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; 33 | } 34 | }); 35 | 36 | return parsed; 37 | }; 38 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /App/Services/ExamplesRegistry.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React from 'react' 4 | import { Text, View } from 'react-native' 5 | import R from 'ramda' 6 | import { ApplicationStyles } from '../Themes' 7 | import DebugSettings from '../Config/DebugSettings' 8 | let globalExamplesRegistry = [] 9 | 10 | export const addExample = (title: string, usage: () => React$Element<*>) => { if (DebugSettings.includeExamples) globalExamplesRegistry.push({title, usage}) } 11 | 12 | const renderExample = (example: Object) => { 13 | return ( 14 | 15 | 16 | {example.title} 17 | 18 | {example.usage.call()} 19 | 20 | ) 21 | } 22 | 23 | export const renderExamples = () => R.map(renderExample, globalExamplesRegistry) 24 | 25 | // Default for readability 26 | export default { 27 | render: renderExamples, 28 | add: addExample 29 | } 30 | -------------------------------------------------------------------------------- /App/Containers/Styles/UsageExamplesScreenStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { Colors, Fonts, Metrics, ApplicationStyles } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | ...ApplicationStyles.screen, 8 | loginBox: { 9 | padding: Metrics.doubleBaseMargin 10 | }, 11 | loginButton: { 12 | borderWidth: 1, 13 | borderColor: Colors.charcoal, 14 | backgroundColor: Colors.panther, 15 | padding: 6 16 | }, 17 | loginText: { 18 | textAlign: 'center', 19 | color: Colors.silver 20 | }, 21 | componentLabelContainer: { 22 | ...ApplicationStyles.darkLabelContainer 23 | }, 24 | componentLabel: { 25 | ...ApplicationStyles.darkLabel 26 | }, 27 | temperature: { 28 | ...Fonts.style.h4, 29 | color: Colors.snow 30 | }, 31 | locale: { 32 | ...Fonts.style.h4, 33 | color: Colors.snow 34 | }, 35 | groupContainer: { 36 | ...ApplicationStyles.groupContainer 37 | } 38 | }) 39 | -------------------------------------------------------------------------------- /App/Redux/CommonRedux.js: -------------------------------------------------------------------------------- 1 | import {createReducer, createActions} from 'reduxsauce' 2 | import Immutable from 'seamless-immutable' 3 | 4 | /* ------------- Types and Action Creators ------------- */ 5 | 6 | const {Types, Creators} = createActions({ 7 | fetching: [], 8 | fetched: [], 9 | }) 10 | 11 | export const CommonTypes = Types 12 | export default Creators 13 | 14 | /* ------------- Initial State ------------- */ 15 | 16 | export const INITIAL_STATE = Immutable({ 17 | fetching: false, 18 | }) 19 | 20 | /* ------------- Reducers ------------- */ 21 | 22 | export const fetching = (state) => { 23 | return state.merge({fetching: true}) 24 | } 25 | 26 | export const fetched = (state) => { 27 | return state.merge({fetching: false}) 28 | } 29 | 30 | /* ------------- Hookup Reducers To Types ------------- */ 31 | 32 | export const reducer = createReducer(INITIAL_STATE, { 33 | [Types.FETCHING]: fetching, 34 | [Types.FETCHED]: fetched, 35 | }) 36 | 37 | /* ------------- Selectors ------------- */ 38 | -------------------------------------------------------------------------------- /Tests/Components/DrawerButtonTest.js: -------------------------------------------------------------------------------- 1 | // https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md 2 | import test from 'ava' 3 | import React from 'react' 4 | import DrawerButton from '../../App/Components/DrawerButton' 5 | import { shallow } from 'enzyme' 6 | 7 | const wrapper = shallow( {}} text='hi' />) 8 | 9 | test('component exists', (t) => { 10 | t.is(wrapper.length, 1) // exists 11 | }) 12 | 13 | test('component structure', (t) => { 14 | t.is(wrapper.name(), 'TouchableOpacity') // the right root component 15 | t.is(wrapper.children().length, 1) // has 1 child 16 | t.is(wrapper.children().first().name(), 'Text') // that child is Text 17 | }) 18 | 19 | test('onPress', (t) => { 20 | let i = 0 21 | const onPress = () => i++ 22 | const wrapperPress = shallow() 23 | 24 | t.is(wrapperPress.prop('onPress'), onPress) // uses the right handler 25 | t.is(i, 0) 26 | wrapperPress.simulate('press') 27 | t.is(i, 1) 28 | }) 29 | -------------------------------------------------------------------------------- /App/I18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "signIn": "Se connecter", 3 | "logOut": "Se déconnecter", 4 | "loginLogoutExampleTitle": "Connexion / Déconnexion Redux + Sagas Exemple", 5 | "progressiveImageComponent": "Composant Image Progressive", 6 | "api": "Mon Dieu! Une API pour vous!", 7 | "locale": "I18n Paramètres régionaux", 8 | "rnVectorIcons": "RN icônes vectorielles", 9 | "loginWithFacebook": "Se connecter avec Facebook", 10 | "rnAnimatable": "RN Animatable", 11 | "igniteGenerated": "Ignite Générer des Écrans", 12 | "forgotPassword": "Mot de passe oublié", 13 | "username": "Nom d'utilisateur", 14 | "password": "Mot de passe", 15 | "cancel": "Annuler", 16 | "welcome": "Bienvenue", 17 | "login": "S'identifier", 18 | "tempIndicator": "C", 19 | "componentExamples": "Exemples de Composants", 20 | "usageExamples": "Exemples d'utilisation", 21 | "apiTesting": "API Testing", 22 | "themeSettings": "Réglage des thèmes", 23 | "deviceDetails": "Détails du périphérique", 24 | "noItems": "Aucun" 25 | } 26 | -------------------------------------------------------------------------------- /App/Containers/Styles/GroupListScreenStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {StyleSheet} from 'react-native' 4 | import {Colors, Metrics, Fonts} from '../../Themes' 5 | import {create} from '../../Lib/PlatformStyleSheet' 6 | 7 | export default create({ 8 | // ListView 9 | listView: { 10 | flex: 1, 11 | }, 12 | row: { 13 | marginLeft: 15, 14 | height: 70, 15 | justifyContent: 'center', 16 | alignItems: 'center', 17 | flexDirection: 'row' 18 | }, 19 | separator: { 20 | height: StyleSheet.hairlineWidth, 21 | marginLeft: 15, 22 | backgroundColor: '#CCCCCC', 23 | }, 24 | rowLogo: { 25 | width: 50, 26 | height: 50, 27 | borderRadius: 25 28 | }, 29 | rowName: { 30 | flex: 1, 31 | justifyContent: 'center', 32 | marginLeft: 10 33 | }, 34 | groupName: { 35 | ...Fonts.style.rowText, 36 | color: Colors.almostBlack, 37 | }, 38 | groupIntro: { 39 | ...Fonts.style.rowText, 40 | marginTop: 10, 41 | color: Colors.steelGrey, 42 | } 43 | 44 | }) 45 | -------------------------------------------------------------------------------- /App/Containers/README.md: -------------------------------------------------------------------------------- 1 | ### Containers Folder 2 | A container is what they call a "Smart Component" in Redux. It is a component 3 | which knows about Redux. They are usually used as "Screens". 4 | 5 | Also located in here are 2 special containers: `App.js` and `RootContainer.js`. 6 | 7 | `App.js` is first component loaded after `index.ios.js` or `index.android.js`. The purpose of this file is to setup Redux or any other non-visual "global" modules. Having Redux setup here helps with the hot-reloading process in React Native during development as it won't try to reload your sagas and reducers should your colors change (for example). 8 | 9 | `RootContainer.js` is the first visual component in the app. It is the ancestor of all other screens and components. 10 | 11 | You'll probably find you'll have great mileage in Ignite apps without even touching these 2 files. They, of course, belong to you, so when you're ready to add something non-visual like Firebase or something visual like an overlay, you have spots to place these additions. 12 | -------------------------------------------------------------------------------- /App/Sdk/src/emoji.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | map: { 3 | '[):]': 'grinning', 4 | '[:D]': 'smiley', 5 | '[;)]': 'wink', 6 | '[:-o]': 'sweat_smile', 7 | '[:p]': 'yum', 8 | '[(H)]': 'sunglasses', 9 | '[:@]': 'rage', 10 | '[:s]': 'confounded', 11 | '[:$]': 'flushed', 12 | '[:(]': 'disappointed', 13 | '[:\'(]': 'sob', 14 | '[:|]': 'neutral_face', 15 | '[(a)]': 'innocent', 16 | '[8o|]': 'grin', 17 | '[8-|]': 'smirk', 18 | '[+o(]': 'scream', 19 | '[ {}} text='hi' />) 9 | 10 | test('component exists', (t) => { 11 | t.is(wrapper.length, 1) // exists 12 | }) 13 | 14 | test('component structure', (t) => { 15 | t.is(wrapper.name(), 'TouchableOpacity') // the right root component 16 | t.is(wrapper.children().length, 1) // has 1 child 17 | t.is(wrapper.children().first().name(), 'Text') // that child is Text 18 | }) 19 | 20 | test('onPress', (t) => { 21 | let i = 0 // i guess i could have used sinon here too... less is more i guess 22 | const onPress = () => i++ 23 | const wrapperPress = shallow() 24 | 25 | t.is(wrapperPress.prop('onPress'), onPress) // uses the right handler 26 | t.is(i, 0) 27 | wrapperPress.simulate('press') 28 | t.is(i, 1) 29 | }) 30 | -------------------------------------------------------------------------------- /App/Components/RoundedButton.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React from 'react' 4 | import { TouchableOpacity, Text } from 'react-native' 5 | import styles from './Styles/RoundedButtonStyle' 6 | import ExamplesRegistry from '../Services/ExamplesRegistry' 7 | 8 | // Example 9 | ExamplesRegistry.add('Rounded Button', () => 10 | window.alert('Rounded Button Pressed!')} 13 | /> 14 | ) 15 | 16 | type RoundedButtonProps = { 17 | onPress: () => void, 18 | text?: string, 19 | children?: string, 20 | navigator?: Object 21 | } 22 | 23 | export default class RoundedButton extends React.Component { 24 | props: RoundedButtonProps 25 | 26 | getText () { 27 | const buttonText = this.props.text || this.props.children || '' 28 | return buttonText.toUpperCase() 29 | } 30 | 31 | render () { 32 | return ( 33 | 34 | {this.getText()} 35 | 36 | ) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /App/Redux/ContactInfoScreenRedux.js: -------------------------------------------------------------------------------- 1 | import {createReducer, createActions} from 'reduxsauce' 2 | import Immutable from 'seamless-immutable' 3 | 4 | /* ------------- Types and Action Creators ------------- */ 5 | 6 | const {Types, Creators} = createActions({ 7 | contactDeleted: [], 8 | contactShowed: [] 9 | }) 10 | 11 | export const ContactInfoScreenTypes = Types 12 | export default Creators 13 | 14 | /* ------------- Initial State ------------- */ 15 | 16 | export const INITIAL_STATE = Immutable({ 17 | show: true, 18 | }) 19 | 20 | /* ------------- Reducers ------------- */ 21 | 22 | export const contactDeleted = (state, {}) => { 23 | return state.merge({show: false}) 24 | } 25 | 26 | export const contactShowed = (state, {}) => { 27 | return state.merge({show: true}) 28 | } 29 | /* ------------- Hookup Reducers To Types ------------- */ 30 | 31 | export const reducer = createReducer(INITIAL_STATE, { 32 | [Types.CONTACT_DELETED]: contactDeleted, 33 | [Types.CONTACT_SHOWED]: contactShowed, 34 | }) 35 | 36 | /* ------------- Selectors ------------- */ 37 | 38 | // Is the current user logged in? 39 | -------------------------------------------------------------------------------- /App/Containers/Styles/GroupMembersScreenStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {StyleSheet} from 'react-native' 4 | import {Colors, Metrics, Fonts} from '../../Themes' 5 | import {create} from '../../Lib/PlatformStyleSheet' 6 | 7 | export default create({ 8 | // ListView 9 | listView: { 10 | // flex: 1, 11 | backgroundColor: Colors.paleGrey 12 | }, 13 | row: { 14 | paddingLeft: 15, 15 | height: 50, 16 | justifyContent: 'center', 17 | alignItems: 'center', 18 | flexDirection: 'row', 19 | backgroundColor: Colors.snow 20 | }, 21 | separator: { 22 | height: StyleSheet.hairlineWidth, 23 | marginLeft: 15, 24 | backgroundColor: '#CCCCCC', 25 | }, 26 | rowLogo: { 27 | width: 30, 28 | height: 30, 29 | borderRadius: 15 30 | }, 31 | rowName: { 32 | flex: 1, 33 | justifyContent: 'center', 34 | marginLeft: 10 35 | }, 36 | groupName: { 37 | ...Fonts.style.rowText, 38 | color: Colors.almostBlack, 39 | }, 40 | groupIntro: { 41 | ...Fonts.style.rowText, 42 | marginTop: 10, 43 | color: Colors.steelGrey, 44 | } 45 | 46 | }) 47 | -------------------------------------------------------------------------------- /App/Lib/axios/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Matt Zabriskie 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /App/Navigation/NavItems.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React from 'react' 4 | import { TouchableOpacity } from 'react-native' 5 | import styles from './Styles/NavItemsStyle' 6 | import { Actions as NavigationActions } from 'react-native-router-flux' 7 | import Icon from 'react-native-vector-icons/FontAwesome' 8 | import { Colors, Metrics } from '../Themes' 9 | 10 | const openDrawer = () => { 11 | NavigationActions.refresh({ 12 | key: 'drawer', 13 | open: true 14 | }) 15 | } 16 | 17 | export default { 18 | backButton () { 19 | return ( 20 | 21 | 26 | 27 | ) 28 | }, 29 | 30 | hamburgerButton () { 31 | return ( 32 | 33 | 38 | 39 | ) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/btoa.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // btoa polyfill for IE<10 courtesy https://github.com/davidchambers/Base64.js 4 | 5 | var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; 6 | 7 | function E() { 8 | this.message = 'String contains an invalid character'; 9 | } 10 | E.prototype = new Error; 11 | E.prototype.code = 5; 12 | E.prototype.name = 'InvalidCharacterError'; 13 | 14 | function btoa(input) { 15 | var str = String(input); 16 | var output = ''; 17 | for ( 18 | // initialize result and counter 19 | var block, charCode, idx = 0, map = chars; 20 | // if the next str index does not exist: 21 | // change the mapping table to "=" 22 | // check if d has no fractional digits 23 | str.charAt(idx | 0) || (map = '=', idx % 1); 24 | // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8 25 | output += map.charAt(63 & block >> 8 - idx % 1 * 8) 26 | ) { 27 | charCode = str.charCodeAt(idx += 3 / 4); 28 | if (charCode > 0xFF) { 29 | throw new E(); 30 | } 31 | block = block << 8 | charCode; 32 | } 33 | return output; 34 | } 35 | 36 | module.exports = btoa; 37 | -------------------------------------------------------------------------------- /App/Components/Styles/ModalHeaderStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet, PixelRatio } from 'react-native' 4 | import { Colors, Metrics } from '../../Themes' 5 | import { create } from '../../Lib/PlatformStyleSheet' 6 | 7 | export default create({ 8 | container: { 9 | // flex: 1, 10 | flexDirection: 'row', 11 | height: 42, 12 | backgroundColor: Colors.bgGrey, 13 | justifyContent: 'center', 14 | borderBottomWidth: StyleSheet.hairlineWidth, 15 | borderBottomColor: Colors.paleGrey, 16 | }, 17 | left: { 18 | flex: 1, 19 | justifyContent: 'center', 20 | alignItems: 'flex-start', 21 | paddingLeft: 15, 22 | }, 23 | leftText: { 24 | fontSize: 13, 25 | color: Colors.modelHeaderText 26 | }, 27 | middle: { 28 | flex: 1, 29 | justifyContent: 'center', 30 | alignItems: 'center', 31 | }, 32 | middleText: { 33 | fontSize: 17, 34 | marginBottom: 3 35 | }, 36 | right: { 37 | flex: 1, 38 | justifyContent: 'center', 39 | alignItems: 'flex-end', 40 | paddingRight: 15, 41 | }, 42 | rightText: { 43 | fontSize: 13, 44 | color: Colors.modelHeaderText 45 | }, 46 | }) 47 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # 版本更新说明: 3 | 4 | ## v0.2.0 @ 2017-01-05 5 | 6 | ### Feature 7 | 8 | * [Android] 9 | - 登陆 10 | - 注册 11 | - 好友 12 | - 列表及筛选 13 | - 好友信息展示 14 | - 黑名单 15 | - 好友通知 16 | - 添加好友通知展示 17 | - 接受好友请求 18 | - 拒绝好友请求 19 | - 添加好友 20 | - 群组 21 | - 群组列表 22 | - 群组成员列表 23 | - 聊天 24 | - 相机图片消息 25 | - 本地图片消息 26 | - emoji消息 27 | - 普通消息 28 | 29 | ### BugFix and Update 30 | 31 | * 群成员刷新crash的问题 32 | * 添加logout图标 33 | * 统一iOS和Android UI 34 | * emoji颜色在android颜色太浅 35 | * 登出的时候清空用户状态 36 | * 完善联系人页面的搜索在切换场景及刷新时的显示逻辑 37 | 38 | ### Extra 39 | 40 | * [react-native] 升级到最新0.39.2 41 | * [component/input] 功能完善 42 | * [component/button] 功能完善 43 | * [addContactModal] 统一通过react-native-router-flux管理modal 44 | * [tabBar] 统一通过react-native-router-flux管理tabBar 45 | * [camera] android 支持调用相机/本地图片 46 | * [yarn] 添加yarn lock file,可以通过yarn做包管理 47 | 48 | ## v0.1.0 @ 2016-12-20 49 | 50 | ### Feature 51 | 52 | * [iOS] 53 | - 登陆 54 | - 注册 55 | - 好友 56 | - 列表及筛选 57 | - 好友信息展示 58 | - 黑名单 59 | - 好友通知 60 | - 添加好友通知展示 61 | - 接受好友请求 62 | - 拒绝好友请求 63 | - 添加好友 64 | - 群组 65 | - 群组列表 66 | - 群组成员列表 67 | - 聊天 68 | - 相机图片消息 69 | - 本地图片消息 70 | - emoji消息 71 | - 普通消息 72 | 73 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/axios.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./utils'); 4 | var bind = require('./helpers/bind'); 5 | var Axios = require('./core/Axios'); 6 | 7 | /** 8 | * Create an instance of Axios 9 | * 10 | * @param {Object} defaultConfig The default config for the instance 11 | * @return {Axios} A new instance of Axios 12 | */ 13 | function createInstance(defaultConfig) { 14 | var context = new Axios(defaultConfig); 15 | var instance = bind(Axios.prototype.request, context); 16 | 17 | // Copy axios.prototype to instance 18 | utils.extend(instance, Axios.prototype, context); 19 | 20 | // Copy context to instance 21 | utils.extend(instance, context); 22 | 23 | return instance; 24 | } 25 | 26 | // Create the default instance to be exported 27 | var axios = module.exports = createInstance(); 28 | 29 | // Expose Axios class to allow class inheritance 30 | axios.Axios = Axios; 31 | 32 | // Factory for creating new instances 33 | axios.create = function create(defaultConfig) { 34 | return createInstance(defaultConfig); 35 | }; 36 | 37 | // Expose all/spread 38 | axios.all = function all(promises) { 39 | return Promise.all(promises); 40 | }; 41 | axios.spread = require('./helpers/spread'); 42 | -------------------------------------------------------------------------------- /ios/app/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "Splash_iphone6p.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "667h", 16 | "filename" : "Splash_iphone6.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "portrait", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "orientation" : "portrait", 23 | "idiom" : "iphone", 24 | "filename" : "Splash_iphone4.png", 25 | "extent" : "full-screen", 26 | "minimum-system-version" : "7.0", 27 | "scale" : "2x" 28 | }, 29 | { 30 | "extent" : "full-screen", 31 | "idiom" : "iphone", 32 | "subtype" : "retina4", 33 | "filename" : "Splash_iphone5.png", 34 | "minimum-system-version" : "7.0", 35 | "orientation" : "portrait", 36 | "scale" : "2x" 37 | } 38 | ], 39 | "info" : { 40 | "version" : 1, 41 | "author" : "xcode" 42 | } 43 | } -------------------------------------------------------------------------------- /App/I18n/README.md: -------------------------------------------------------------------------------- 1 | # Idea 2 | 3 | Shipping app with localization for all available languages. The main idea here is to minimise the memory required of other languages that is not used by the platform. 4 | 5 | For example if the phone is localized in French, then this will only load the French and English translations into memory and ignore the 30+ other languages available. 6 | 7 | English translation is set as default fallback in case some translations are not available in the chosen language. 8 | 9 | # Installation 10 | 11 | First install i18n into your react native project 12 | 13 | npm install --save react-native-i18n 14 | react-native link 15 | 16 | Then clone this project to your within your project, removing the git repo and example afterwards. 17 | 18 | git clone --depth 1 https://github.com/hiaw/rn-translate-template translations 19 | rm -rf translations/.git translations/example 20 | 21 | Then require the translations.js file within your main app js file 22 | 23 | require('./translations/_translation.js'); 24 | 25 | To use the translation in app. 26 | 27 | import I18n from 'react-native-i18n'; 28 | 29 | render() { 30 | ... 31 | { I18n.t('welcome') } 32 | ... 33 | } 34 | -------------------------------------------------------------------------------- /Tests/Sagas/TemperatureSagaTest.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import FixtureAPI from '../../App/Services/FixtureApi' 3 | import { put, call } from 'redux-saga/effects' 4 | import { getTemperature } from '../../App/Sagas/TemperatureSagas' 5 | import TemperatureActions from '../../App/Redux/TemperatureRedux' 6 | 7 | const stepper = (fn) => (mock) => fn.next(mock).value 8 | 9 | test('first calls API', (t) => { 10 | const step = stepper(getTemperature(FixtureAPI, {city: 'taco'})) 11 | // first yield is API 12 | t.deepEqual(step(), call(FixtureAPI.getCity, 'taco')) 13 | }) 14 | 15 | test('success path', (t) => { 16 | const response = FixtureAPI.getCity('taco') 17 | const step = stepper(getTemperature(FixtureAPI, {city: 'taco'})) 18 | // first step API 19 | step() 20 | // Second step successful return and temperature 21 | t.deepEqual(step(response), put(TemperatureActions.temperatureSuccess(21, 'bonus'))) 22 | }) 23 | 24 | test('failure path', (t) => { 25 | const response = {ok: false} 26 | const step = stepper(getTemperature(FixtureAPI, {city: 'taco'})) 27 | // first step API 28 | step() 29 | // Second step failed response 30 | t.deepEqual(step(response), put(TemperatureActions.temperatureFailure())) 31 | }) 32 | -------------------------------------------------------------------------------- /App/Themes/Fonts.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | const type = { 4 | base: 'HelveticaNeue', 5 | bold: 'HelveticaNeue-Bold', 6 | emphasis: 'HelveticaNeue-Italic' 7 | } 8 | 9 | const size = { 10 | h1: 38, 11 | h2: 34, 12 | h3: 30, 13 | h4: 26, 14 | h5: 20, 15 | h6: 19, 16 | input: 18, 17 | regular: 17, 18 | medium: 14, 19 | small2: 13, 20 | small: 12, 21 | tiny1: 11, 22 | tiny: 8.5 23 | } 24 | 25 | const style = { 26 | h1: { 27 | fontFamily: type.base, 28 | fontSize: size.h1 29 | }, 30 | h2: { 31 | fontWeight: 'bold', 32 | fontSize: size.h2 33 | }, 34 | h3: { 35 | fontFamily: type.emphasis, 36 | fontSize: size.h3 37 | }, 38 | h4: { 39 | fontFamily: type.base, 40 | fontSize: size.h4 41 | }, 42 | h5: { 43 | fontFamily: type.base, 44 | fontSize: size.h5 45 | }, 46 | h6: { 47 | fontFamily: type.emphasis, 48 | fontSize: size.h6 49 | }, 50 | normal: { 51 | fontFamily: type.base, 52 | fontSize: size.regular 53 | }, 54 | description: { 55 | fontFamily: type.base, 56 | fontSize: size.medium 57 | }, 58 | rowText: { 59 | fontFamily: type.base, 60 | fontSize: size.small2 61 | } 62 | } 63 | 64 | export default { 65 | type, 66 | size, 67 | style 68 | } 69 | 70 | -------------------------------------------------------------------------------- /Tests/Setup.js: -------------------------------------------------------------------------------- 1 | import mockery from 'mockery' 2 | import m from 'module' 3 | 4 | // inject __DEV__ as it is not available when running through the tests 5 | global.__DEV__ = true 6 | 7 | // We enable mockery and leave it on. 8 | mockery.enable() 9 | 10 | // Silence the warnings when *real* modules load... this is a change from 11 | // the norm. We want to opt-in instead of opt-out because not everything 12 | // will be mocked. 13 | mockery.warnOnUnregistered(false) 14 | 15 | // Mock any libs that get called in here 16 | // I'm looking at you react-native-router-flux, reactotron etc! 17 | mockery.registerMock('reactotron-react-native', {}) 18 | mockery.registerMock('reactotron-redux', {}) 19 | mockery.registerMock('reactotron-apisauce', {}) 20 | mockery.registerMock('react-native-animatable', {View: 'Animatable.View'}) 21 | mockery.registerMock('react-native-vector-icons/Ionicons', {}) 22 | 23 | // mock i18n as it uses react native stufff 24 | mockery.registerMock('react-native-i18n', { 25 | t: (key) => key 26 | }) 27 | 28 | // Mock all images for React Native 29 | const originalLoader = m._load 30 | m._load = (request, parent, isMain) => { 31 | if (request.match(/.jpeg|.jpg|.png|.gif$/)) { 32 | return { uri: request } 33 | } 34 | 35 | return originalLoader(request, parent, isMain) 36 | } 37 | -------------------------------------------------------------------------------- /App/Sagas/index.js: -------------------------------------------------------------------------------- 1 | import { takeLatest } from 'redux-saga' 2 | import API from '../Services/Api' 3 | import FixtureAPI from '../Services/FixtureApi' 4 | import DebugSettings from '../Config/DebugSettings' 5 | 6 | /* ------------- Types ------------- */ 7 | 8 | import { StartupTypes } from '../Redux/StartupRedux' 9 | import { TemperatureTypes } from '../Redux/TemperatureRedux' 10 | import { LoginTypes } from '../Redux/LoginRedux' 11 | 12 | /* ------------- Sagas ------------- */ 13 | 14 | import { startup } from './StartupSagas' 15 | import { login } from './LoginSagas' 16 | import { getTemperature } from './TemperatureSagas' 17 | 18 | /* ------------- API ------------- */ 19 | 20 | // The API we use is only used from Sagas, so we create it here and pass along 21 | // to the sagas which need it. 22 | const api = DebugSettings.useFixtures ? FixtureAPI : API.create() 23 | 24 | /* ------------- Connect Types To Sagas ------------- */ 25 | 26 | export default function * root () { 27 | yield [ 28 | // some sagas only receive an action 29 | takeLatest(StartupTypes.STARTUP, startup), 30 | takeLatest(LoginTypes.LOGIN_REQUEST, login), 31 | 32 | // some sagas receive extra parameters in addition to an action 33 | takeLatest(TemperatureTypes.TEMPERATURE_REQUEST, getTemperature, api) 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /App/Lib/Utilities.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // Utility functions 4 | import { Platform } from 'react-native' 5 | import R from 'ramda' 6 | 7 | // useful cleaning functions 8 | const nullToEmpty = R.defaultTo('') 9 | const replaceEscapedCRLF = R.replace(/\\n/g) 10 | const nullifyNewlines = R.compose(replaceEscapedCRLF(' '), nullToEmpty) 11 | 12 | // Correct Map URIs 13 | export const locationURL = (address: string) => { 14 | let cleanAddress = nullifyNewlines(address) 15 | // https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html 16 | let url = `http://maps.apple.com/?address=${cleanAddress}` 17 | // https://developers.google.com/maps/documentation/ios-sdk/urlscheme 18 | if (Platform.OS === 'android') url = `http://maps.google.com/?q=${cleanAddress}` 19 | 20 | return url 21 | } 22 | export const directionsURL = (address: string) => { 23 | let cleanAddress = nullifyNewlines(address) 24 | // https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/MapLinks/MapLinks.html 25 | let url = `http://maps.apple.com/?daddr=${cleanAddress}&dirflg=d` 26 | // https://developers.google.com/maps/documentation/ios-sdk/urlscheme 27 | if (Platform.OS === 'android') url = `http://maps.google.com/?daddr=${cleanAddress}` 28 | 29 | return url 30 | } 31 | -------------------------------------------------------------------------------- /App/Services/RehydrationServices.js: -------------------------------------------------------------------------------- 1 | import ReduxPersist from '../Config/ReduxPersist' 2 | import { AsyncStorage } from 'react-native' 3 | import { persistStore } from 'redux-persist' 4 | import StartupActions from '../Redux/StartupRedux' 5 | 6 | const updateReducers = (store: Object) => { 7 | const reducerVersion = ReduxPersist.reducerVersion 8 | const config = ReduxPersist.storeConfig 9 | const startup = () => store.dispatch(StartupActions.startup()) 10 | 11 | // Check to ensure latest reducer version 12 | AsyncStorage.getItem('reducerVersion').then((localVersion) => { 13 | if (localVersion !== reducerVersion) { 14 | console.tron.display({ 15 | name: 'PURGE', 16 | value: { 17 | 'Old Version:': localVersion, 18 | 'New Version:': reducerVersion 19 | }, 20 | preview: 'Reducer Version Change Detected', 21 | important: true 22 | }) 23 | // Purge store 24 | persistStore(store, config, startup).purge() 25 | AsyncStorage.setItem('reducerVersion', reducerVersion) 26 | } else { 27 | persistStore(store, config, startup) 28 | } 29 | }).catch(() => { 30 | persistStore(store, config, startup) 31 | AsyncStorage.setItem('reducerVersion', reducerVersion) 32 | }) 33 | } 34 | 35 | export default {updateReducers} 36 | -------------------------------------------------------------------------------- /App/Config/PushConfig.js: -------------------------------------------------------------------------------- 1 | import PushNotification from 'react-native-push-notification' 2 | 3 | // https://github.com/zo0r/react-native-push-notification 4 | PushNotification.configure({ 5 | 6 | // (optional) Called when Token is generated (iOS and Android) 7 | onRegister: (token) => { 8 | if (__DEV__) console.log('TOKEN:', token) 9 | }, 10 | 11 | // (required) Called when a remote or local notification is opened or received 12 | onNotification: (notification) => { 13 | if (__DEV__) console.log('NOTIFICATION:', notification) 14 | }, 15 | 16 | // ANDROID ONLY: (optional) GCM Sender ID. 17 | senderID: 'YOUR GCM SENDER ID', 18 | 19 | // IOS ONLY (optional): default: all - Permissions to register. 20 | permissions: { 21 | alert: true, 22 | badge: true, 23 | sound: true 24 | }, 25 | 26 | // Should the initial notification be popped automatically 27 | // default: true 28 | // Leave this off unless you have good reason. 29 | popInitialNotification: false, 30 | 31 | /** 32 | * IOS ONLY: (optional) default: true 33 | * - Specified if permissions will requested or not, 34 | * - if not, you must call PushNotificationsHandler.requestPermissions() later 35 | * This example app shows how to best call requestPermissions() later. 36 | */ 37 | requestPermissions: false 38 | }) 39 | -------------------------------------------------------------------------------- /App/Components/Styles/InputStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {StyleSheet} from 'react-native' 4 | import {Fonts, Colors} from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | search: { 8 | borderRadius: 3, 9 | flexDirection: 'row', 10 | borderWidth: StyleSheet.hairlineWidth, 11 | borderColor: Colors.coolGrey, 12 | paddingVertical: 17, 13 | paddingHorizontal: 15, 14 | }, 15 | searchFocus: { 16 | borderColor: Colors.frogGreen 17 | }, 18 | iconSize: 13, 19 | searchRow: { 20 | // color: Colors.blueyGrey, 21 | flex: 1, 22 | height: 30, 23 | justifyContent: 'center', 24 | alignItems: 'flex-start', 25 | backgroundColor: Colors.paleGrey, 26 | flexDirection: 'column', 27 | // borderWidth: 1 28 | }, 29 | searchInput: { 30 | // height: 30, 31 | flex: 1, 32 | alignSelf: 'stretch', 33 | fontSize: 13, 34 | paddingLeft: 4, 35 | paddingVertical: 5 36 | }, 37 | searchIcon: { 38 | alignItems: 'flex-end', 39 | justifyContent: 'center', 40 | }, 41 | searchIconFocus: { 42 | flex: 0, 43 | width: 20, 44 | alignItems: 'center' 45 | }, 46 | searchCancel: { 47 | width: 50, 48 | height: 30, 49 | alignItems: 'center', 50 | justifyContent: 'center', 51 | }, 52 | // placeholderTextColor: Colors.blueGrey, 53 | }) 54 | -------------------------------------------------------------------------------- /App/Containers/RootContainer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React, { Component } from 'react' 4 | import { View, StatusBar } from 'react-native' 5 | import NavigationRouter from '../Navigation/NavigationRouter' 6 | import { connect } from 'react-redux' 7 | import StartupActions from '../Redux/StartupRedux' 8 | import ReduxPersist from '../Config/ReduxPersist' 9 | 10 | // Styles 11 | import styles from './Styles/RootContainerStyle' 12 | 13 | // import WebIM from '../Lib/WebIM' 14 | // import WebIMActions from '../Redux/WebIMRedux' 15 | 16 | class RootContainer extends Component { 17 | 18 | componentDidMount () { 19 | // if redux persist is not active fire startup action 20 | if (!ReduxPersist.active) { 21 | this.props.startup() 22 | } 23 | } 24 | 25 | componentWillReceiveProps (nextProps) { 26 | console.log('componentWillReceiveProps', nextProps) 27 | } 28 | 29 | render () { 30 | return ( 31 | 32 | {/* barStyle='light-content' */} 33 | 34 | 35 | 36 | ) 37 | } 38 | } 39 | 40 | const mapStateToDispatch = (dispatch) => ({ 41 | startup: () => dispatch(StartupActions.startup()) 42 | // dispatch: dispatch 43 | }) 44 | 45 | export default connect(null, mapStateToDispatch)(RootContainer) 46 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /App/Components/ModalHeader.js: -------------------------------------------------------------------------------- 1 | import React, {Component, PropTypes} from 'react' 2 | import {connect} from 'react-redux' 3 | import {Modal, Text, TouchableOpacity, View, Dimensions} from 'react-native' 4 | 5 | // custom 6 | import I18n from 'react-native-i18n' 7 | import {Images, Colors} from '../Themes' 8 | import Styles from './Styles/ModalHeaderStyle' 9 | import Icon from 'react-native-vector-icons/FontAwesome'; 10 | 11 | export default class ModalHeader extends Component { 12 | 13 | // ------------ init ------------- 14 | constructor(props) { 15 | super(props) 16 | } 17 | 18 | // ------------ lifecycle ------------ 19 | 20 | 21 | // ------------ renders ------------- 22 | 23 | render() { 24 | let {title = 'Title', leftBtn, leftClick, rightBtn, rightClick} = this.props 25 | 26 | return ( 27 | 28 | 29 | 30 | {leftBtn} 31 | 32 | 33 | 34 | {title} 35 | 36 | 37 | 38 | {rightBtn} 39 | 40 | 41 | 42 | ) 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /App/Components/Styles/InfoNavBarStyle.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {Colors, Metrics} from '../../Themes' 3 | import {create} from '../../Lib/PlatformStyleSheet' 4 | 5 | export default create({ 6 | container: { 7 | position: 'absolute', 8 | top: 0, 9 | left: 0, 10 | right: 0, 11 | height: Metrics.navBarHeight, 12 | // paddingHorizontal: Metrics.baseMargin, 13 | // backgroundColor: 'transparent', 14 | flexDirection: 'row', 15 | alignItems: 'center', 16 | justifyContent: 'space-between', 17 | // 18 | ios: { 19 | paddingTop: 30, 20 | }, 21 | backgroundColor: Colors.white1, 22 | borderBottomWidth: StyleSheet.hairlineWidth, 23 | borderBottomColor: Colors.paleGrey 24 | }, 25 | leftButton: { 26 | paddingHorizontal: 15, 27 | paddingVertical: 3, 28 | }, 29 | logo: { 30 | height: Metrics.navBarHeight - Metrics.doubleBaseMargin, 31 | width: Metrics.navBarHeight - Metrics.doubleBaseMargin, 32 | resizeMode: 'contain' 33 | }, 34 | rightButton: { 35 | paddingHorizontal: 15, 36 | paddingVertical: 3, 37 | }, 38 | title: { 39 | flex: 1, 40 | textAlign: 'center', 41 | flexDirection: 'row', 42 | }, 43 | flexLeft: { 44 | flex: 1, 45 | justifyContent: 'flex-start', 46 | flexDirection: 'row', 47 | }, 48 | flexRight: { 49 | flex: 1, 50 | justifyContent: 'flex-end', 51 | flexDirection: 'row', 52 | } 53 | }) 54 | -------------------------------------------------------------------------------- /App/Components/Button.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React from 'react' 4 | import {View, TouchableOpacity, Text, TouchableNativeFeedback, Platform} from 'react-native' 5 | import {Colors, Metrics} from '../Themes' 6 | import Styles from './Styles/ButtonStyle' 7 | 8 | export default class Button extends React.Component { 9 | render() { 10 | const {color, isHighlight = false, styles} = this.props 11 | 12 | // const Touchable = Platform.OS === 'android' ? : TouchableOpacity; 13 | 14 | let textStyles = []; 15 | color && textStyles.push({color: color}) 16 | 17 | let textWrapperStyles = [Styles.button, styles, { 18 | // borderWidth: 1, 19 | justifyContent: 'center', 20 | }] 21 | textWrapperStyles.push({backgroundColor: isHighlight ? Colors.buttonGreen : Colors.coolGrey}) 22 | 23 | return Platform.OS === 'android' ? ( 24 | 27 | 28 | {this.props.text} 29 | 30 | 31 | ) : ( 32 | 34 | 35 | {this.props.text} 36 | 37 | 38 | ) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /App/Services/ImmutablePersistenceTransform.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import R from 'ramda' 4 | import Immutable from 'seamless-immutable' 5 | 6 | // is this object already Immutable? 7 | const isImmutable = R.has('asMutable') 8 | 9 | // change this Immutable object into a JS object 10 | const convertToJs = (state: Object) => state.asMutable({deep: true}) 11 | 12 | // optionally convert this object into a JS object if it is Immutable 13 | const fromImmutable = R.when(isImmutable, convertToJs) 14 | 15 | // convert this JS object into an Immutable object 16 | const toImmutable = (raw: Object) => Immutable(raw) 17 | 18 | // the transform interface that redux-persist is expecting 19 | export default { 20 | out: (state: Object) => { 21 | console.log('retrieving', state) 22 | // --- HACKZORZ --- 23 | // Attach a empty-ass function to the object called `mergeDeep`. 24 | // This tricks redux-persist into just placing our Immutable object into the state tree 25 | // instead of trying to convert it to a POJO 26 | // https://github.com/rt2zz/redux-persist/blob/master/src/autoRehydrate.js#L55 27 | // 28 | // Another equal terrifying option would be to try to pass their other check 29 | // which is lodash isPlainObject. 30 | // --- END HACKZORZ --- 31 | state.mergeDeep = R.identity 32 | return toImmutable(state) 33 | }, 34 | in: (raw: Object) => { 35 | // console.log({ storing: raw }) 36 | return fromImmutable(raw) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /App/Redux/DemoRedux.js: -------------------------------------------------------------------------------- 1 | import {createReducer, createActions} from 'reduxsauce' 2 | import Immutable from 'seamless-immutable' 3 | 4 | /* ------------- Types and Action Creators ------------- */ 5 | 6 | const {Types, Creators} = createActions({ 7 | nop: [''], 8 | nopFunc: null, 9 | asyncFunc: () => { 10 | return (dispatch, getState) => { 11 | 12 | } 13 | } 14 | }) 15 | 16 | export const DemoTypes = Types 17 | export default Creators 18 | 19 | /* ------------- Initial State ------------- */ 20 | 21 | export const INITIAL_STATE = Immutable({ 22 | error: null, 23 | fetching: false, 24 | }) 25 | 26 | /* ------------- Reducers ------------- */ 27 | 28 | export const request = (state, {username, password}) => { 29 | return state.merge({fetching: true, error: false}) 30 | } 31 | 32 | export const success = (state, {msg}) => { 33 | return state.merge({fetching: false, error: false, msg}) 34 | } 35 | 36 | export const failure = (state, {error}) => { 37 | return state.merge({fetching: false, error: true}) 38 | } 39 | 40 | // we've logged out 41 | export const logout = (state) => INITIAL_STATE 42 | 43 | /* ------------- Hookup Reducers To Types ------------- */ 44 | 45 | export const reducer = createReducer(INITIAL_STATE, { 46 | [Types.NOP]: request, 47 | [Types.NOP_FUNC]: request, 48 | }) 49 | 50 | /* ------------- Selectors ------------- */ 51 | 52 | // Is the current user logged in? 53 | export const isLoggedIn = (loginState) => loginState.username !== null 54 | -------------------------------------------------------------------------------- /App/Containers/Styles/ThemeScreenStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { Colors, Metrics, ApplicationStyles } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | ...ApplicationStyles.screen, 8 | groupContainer: { 9 | ...ApplicationStyles.groupContainer 10 | }, 11 | sectionHeaderContainer: { 12 | ...ApplicationStyles.darkLabelContainer 13 | }, 14 | sectionHeader: { 15 | ...ApplicationStyles.darkLabel 16 | }, 17 | colorsContainer: { 18 | flexDirection: 'row', 19 | flexWrap: 'wrap', 20 | justifyContent: 'center' 21 | }, 22 | backgroundContainer: { 23 | position: 'relative', 24 | width: 102, 25 | height: 102, 26 | borderWidth: 1, 27 | borderColor: Colors.frost 28 | }, 29 | backerImage: { 30 | top: 0, 31 | bottom: 0, 32 | left: 0, 33 | right: 0, 34 | position: 'absolute', 35 | resizeMode: 'stretch' 36 | }, 37 | colorContainer: { 38 | height: 130, 39 | padding: Metrics.smallMargin, 40 | marginBottom: Metrics.smallMargin 41 | }, 42 | colorSquare: { 43 | width: 100, 44 | height: 100 45 | }, 46 | colorName: { 47 | width: 100, 48 | height: Metrics.doubleBaseMargin, 49 | lineHeight: Metrics.doubleBaseMargin, 50 | color: Colors.charcoal, 51 | textAlign: 'center' 52 | }, 53 | fontRow: { 54 | padding: Metrics.smallMargin, 55 | marginHorizontal: Metrics.smallMargin, 56 | color: Colors.snow 57 | } 58 | }) 59 | -------------------------------------------------------------------------------- /App/Components/MapCallout.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Text, TouchableOpacity } from 'react-native' 3 | import MapView from 'react-native-maps' 4 | import Styles from './Styles/MapCalloutStyle' 5 | import ExamplesRegistry from '../Services/ExamplesRegistry' 6 | 7 | // Example 8 | ExamplesRegistry.add('Map Callout', () => 9 | window.alert('That tickles!')} 14 | /> 15 | ) 16 | 17 | type MapCalloutProps = { 18 | location: Object, 19 | onPress: () => void 20 | } 21 | 22 | export default class MapCallout extends React.Component { 23 | props: MapCalloutProps 24 | 25 | constructor (props: MapCalloutProps) { 26 | super(props) 27 | this.onPress = this.props.onPress.bind(this, this.props.location) 28 | } 29 | 30 | render () { 31 | /* *********************************************************** 32 | * Customize the appearance of the callout that opens when the user interacts with a marker. 33 | * Note: if you don't want your callout surrounded by the default tooltip, pass `tooltip={true}` to `MapView.Callout` 34 | *************************************************************/ 35 | const { location } = this.props 36 | return ( 37 | 38 | 39 | {location.title} 40 | 41 | 42 | ) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/core/InterceptorManager.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./../utils'); 4 | 5 | function InterceptorManager() { 6 | this.handlers = []; 7 | } 8 | 9 | /** 10 | * Add a new interceptor to the stack 11 | * 12 | * @param {Function} fulfilled The function to handle `then` for a `Promise` 13 | * @param {Function} rejected The function to handle `reject` for a `Promise` 14 | * 15 | * @return {Number} An ID used to remove interceptor later 16 | */ 17 | InterceptorManager.prototype.use = function use(fulfilled, rejected) { 18 | this.handlers.push({ 19 | fulfilled: fulfilled, 20 | rejected: rejected 21 | }); 22 | return this.handlers.length - 1; 23 | }; 24 | 25 | /** 26 | * Remove an interceptor from the stack 27 | * 28 | * @param {Number} id The ID that was returned by `use` 29 | */ 30 | InterceptorManager.prototype.eject = function eject(id) { 31 | if (this.handlers[id]) { 32 | this.handlers[id] = null; 33 | } 34 | }; 35 | 36 | /** 37 | * Iterate over all the registered interceptors 38 | * 39 | * This method is particularly useful for skipping over any 40 | * interceptors that may have become `null` calling `eject`. 41 | * 42 | * @param {Function} fn The function to call for each interceptor 43 | */ 44 | InterceptorManager.prototype.forEach = function forEach(fn) { 45 | utils.forEach(this.handlers, function forEachHandler(h) { 46 | if (h !== null) { 47 | fn(h); 48 | } 49 | }); 50 | }; 51 | 52 | module.exports = InterceptorManager; 53 | -------------------------------------------------------------------------------- /ios/app/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 "RCTBundleURLProvider.h" 13 | #import "RCTRootView.h" 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"app" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /App/Redux/GroupMemberRedux.js: -------------------------------------------------------------------------------- 1 | import {createReducer, createActions} from 'reduxsauce' 2 | import Immutable from 'seamless-immutable' 3 | 4 | /* ------------- Types and Action Creators ------------- */ 5 | 6 | const {Types, Creators} = createActions({ 7 | updateGroupMember: ['id', 'members'], 8 | // ---------------async------------------ 9 | getGroupMember: (id) => { 10 | return (dispatch, getState) => { 11 | WebIM.conn.queryRoomMember({ 12 | roomId: id, 13 | success: function (members) { 14 | dispatch(Creators.updateGroupMember(id, members)) 15 | }, 16 | error: function () { 17 | } 18 | }); 19 | } 20 | }, 21 | }) 22 | 23 | export const GroupMemberTypes = Types 24 | export default Creators 25 | 26 | /* ------------- Initial State ------------- */ 27 | 28 | export const INITIAL_STATE = Immutable({}) 29 | 30 | /* ------------- Reducers ------------- */ 31 | // [{jid,name,roomId}] members 32 | export const updateGroupMember = (state, {id, members}) => { 33 | let byName = {} 34 | members.forEach((v) => { 35 | let name = (v.jid.match(/_(.*?)@/))[1] 36 | byName[name] = v 37 | }) 38 | return state.merge({ 39 | [id]: { 40 | byName, 41 | names: Object.keys(byName).sort() 42 | } 43 | }) 44 | } 45 | 46 | /* ------------- Hookup Reducers To Types ------------- */ 47 | 48 | export const reducer = createReducer(INITIAL_STATE, { 49 | [Types.UPDATE_GROUP_MEMBER]: updateGroupMember, 50 | }) 51 | 52 | /* ------------- Selectors ------------- */ 53 | -------------------------------------------------------------------------------- /App/Redux/TemperatureRedux.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { createReducer, createActions } from 'reduxsauce' 4 | import Immutable from 'seamless-immutable' 5 | 6 | /* ------------- Types and Action Creators ------------- */ 7 | 8 | const { Types, Creators } = createActions({ 9 | temperatureRequest: ['city'], 10 | temperatureSuccess: ['temperature'], 11 | temperatureFailure: null 12 | }) 13 | 14 | export const TemperatureTypes = Types 15 | export default Creators 16 | 17 | /* ------------- Initial State ------------- */ 18 | 19 | export const INITIAL_STATE = Immutable({ 20 | temperature: null, 21 | fetching: null, 22 | error: null, 23 | city: null 24 | }) 25 | 26 | /* ------------- Reducers ------------- */ 27 | 28 | // request the temperature for a city 29 | export const request = (state: Object, { city }: Object) => 30 | state.merge({ fetching: true, city, temperature: null }) 31 | 32 | // successful temperature lookup 33 | export const success = (state: Object, action: Object) => { 34 | const { temperature } = action 35 | return state.merge({ fetching: false, error: null, temperature }) 36 | } 37 | 38 | // failed to get the temperature 39 | export const failure = (state: Object) => 40 | state.merge({ fetching: false, error: true, temperature: null }) 41 | 42 | /* ------------- Hookup Reducers To Types ------------- */ 43 | 44 | export const reducer = createReducer(INITIAL_STATE, { 45 | [Types.TEMPERATURE_REQUEST]: request, 46 | [Types.TEMPERATURE_SUCCESS]: success, 47 | [Types.TEMPERATURE_FAILURE]: failure 48 | }) 49 | -------------------------------------------------------------------------------- /Tests/Components/RoundedButtonTest.js: -------------------------------------------------------------------------------- 1 | // https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md 2 | import test from 'ava' 3 | import React from 'react' 4 | import RoundedButton from '../../App/Components/RoundedButton' 5 | import { shallow } from 'enzyme' 6 | 7 | // Basic wrapper 8 | const wrapper = shallow( {}} text='howdy' />) 9 | 10 | test('component exists', (t) => { 11 | t.is(wrapper.length, 1) // exists 12 | }) 13 | 14 | test('component structure', (t) => { 15 | t.is(wrapper.name(), 'TouchableOpacity') // the right root component 16 | t.is(wrapper.children().length, 1) // has 1 child 17 | t.is(wrapper.children().first().name(), 'Text') // that child is Text 18 | }) 19 | 20 | test('the text is set properly - uppercase', (t) => { 21 | t.is(wrapper.children().first().props().children, 'HOWDY') 22 | }) 23 | 24 | test('onPress', (t) => { 25 | let i = 0 // i guess i could have used sinon here too... less is more i guess 26 | const onPress = () => i++ 27 | const wrapperPress = shallow() 28 | 29 | t.is(wrapperPress.prop('onPress'), onPress) // uses the right handler 30 | t.is(i, 0) 31 | wrapperPress.simulate('press') 32 | t.is(i, 1) 33 | }) 34 | 35 | test('renders children text when passed', (t) => { 36 | const wrapperChild = shallow( {}}>Howdy) 37 | t.is(wrapperChild.children().length, 1) // has 1 child 38 | t.is(wrapperChild.children().first().name(), 'Text') // that child is Text 39 | }) 40 | -------------------------------------------------------------------------------- /App/Containers/Styles/DeviceInfoScreenStyle.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { StyleSheet } from 'react-native' 4 | import { Colors, Metrics, Fonts, ApplicationStyles } from '../../Themes/' 5 | 6 | export default StyleSheet.create({ 7 | ...ApplicationStyles.screen, 8 | cardTitle: { 9 | alignSelf: 'center', 10 | fontSize: Fonts.size.regular, 11 | fontWeight: 'bold', 12 | marginVertical: Metrics.baseMargin, 13 | color: Colors.snow 14 | }, 15 | cardContainer: { 16 | backgroundColor: Colors.ember, 17 | borderColor: 'black', 18 | borderWidth: 1, 19 | borderRadius: 2, 20 | shadowColor: Colors.panther, 21 | shadowOffset: { 22 | height: 7, 23 | width: 7 24 | }, 25 | shadowRadius: 2, 26 | paddingBottom: Metrics.baseMargin, 27 | margin: Metrics.baseMargin 28 | }, 29 | rowContainer: { 30 | flexDirection: 'row', 31 | borderColor: Colors.windowTint, 32 | borderWidth: 0.5, 33 | borderRadius: 2, 34 | marginHorizontal: Metrics.baseMargin 35 | }, 36 | rowLabelContainer: { 37 | flex: 1, 38 | justifyContent: 'center', 39 | backgroundColor: Colors.snow 40 | }, 41 | rowLabel: { 42 | fontWeight: 'bold', 43 | fontSize: Fonts.size.medium, 44 | marginVertical: Metrics.baseMargin, 45 | marginLeft: Metrics.baseMargin 46 | }, 47 | rowInfoContainer: { 48 | flex: 2, 49 | justifyContent: 'center', 50 | backgroundColor: Colors.silver 51 | }, 52 | rowInfo: { 53 | fontSize: Fonts.size.regular, 54 | margin: Metrics.baseMargin 55 | } 56 | }) 57 | -------------------------------------------------------------------------------- /App/Lib/MapHelpers.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import R from 'ramda' 4 | 5 | export const removeEmpty = (markers: Array) => { 6 | let filteredMarkers = R.filter((item) => { 7 | return item.latitude && item.longitude 8 | }, markers) 9 | return filteredMarkers 10 | } 11 | 12 | export const calculateRegion = (locations: Array, options: Object) => { 13 | const latPadding = options && options.latPadding ? options.latPadding : 0.1 14 | const longPadding = options && options.longPadding ? options.longPadding : 0.1 15 | const mapLocations = removeEmpty(locations) 16 | // Only do calculations if there are locations 17 | if (mapLocations.length > 0) { 18 | let allLatitudes = R.map((l) => { 19 | if (l.latitude && !l.latitude.isNaN) return l.latitude 20 | }, mapLocations) 21 | 22 | let allLongitudes = R.map((l) => { 23 | if (l.longitude && !l.longitude.isNaN) return l.longitude 24 | }, mapLocations) 25 | 26 | let minLat = R.reduce(R.min, Infinity, allLatitudes) 27 | let maxLat = R.reduce(R.max, -Infinity, allLatitudes) 28 | let minLong = R.reduce(R.min, Infinity, allLongitudes) 29 | let maxLong = R.reduce(R.max, -Infinity, allLongitudes) 30 | 31 | let middleLat = (minLat + maxLat) / 2 32 | let middleLong = (minLong + maxLong) / 2 33 | let latDelta = (maxLat - minLat) + latPadding 34 | let longDelta = (maxLong - minLong) + longPadding 35 | 36 | // return markers 37 | return { 38 | latitude: middleLat, 39 | longitude: middleLong, 40 | latitudeDelta: latDelta, 41 | longitudeDelta: longDelta 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/cookies.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./../utils'); 4 | 5 | module.exports = ( 6 | utils.isStandardBrowserEnv() ? 7 | 8 | // Standard browser envs support document.cookie 9 | (function standardBrowserEnv() { 10 | return { 11 | write: function write(name, value, expires, path, domain, secure) { 12 | var cookie = []; 13 | cookie.push(name + '=' + encodeURIComponent(value)); 14 | 15 | if (utils.isNumber(expires)) { 16 | cookie.push('expires=' + new Date(expires).toGMTString()); 17 | } 18 | 19 | if (utils.isString(path)) { 20 | cookie.push('path=' + path); 21 | } 22 | 23 | if (utils.isString(domain)) { 24 | cookie.push('domain=' + domain); 25 | } 26 | 27 | if (secure === true) { 28 | cookie.push('secure'); 29 | } 30 | 31 | document.cookie = cookie.join('; '); 32 | }, 33 | 34 | read: function read(name) { 35 | var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)')); 36 | return (match ? decodeURIComponent(match[3]) : null); 37 | }, 38 | 39 | remove: function remove(name) { 40 | this.write(name, '', Date.now() - 86400000); 41 | } 42 | }; 43 | })() : 44 | 45 | // Non standard browser env (web workers, react-native) lack needed support. 46 | (function nonStandardBrowserEnv() { 47 | return { 48 | write: function write() {}, 49 | read: function read() { return null; }, 50 | remove: function remove() {} 51 | }; 52 | })() 53 | ); 54 | -------------------------------------------------------------------------------- /App/Sdk/gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var gulp = require('gulp') 4 | var webpack = require('webpack-stream') 5 | var mocha = require('gulp-mocha') // 用于单元测试 6 | var babel = require('gulp-babel') // 用于ES6转化ES5 7 | // var browserify = require('browserify'); 8 | // var source = require('vinyl-source-stream'); 9 | // var buffer = require('vinyl-buffer'); 10 | var uglify = require('gulp-uglify') 11 | var rename = require('gulp-rename') 12 | var sourcemaps = require('gulp-sourcemaps') 13 | var gutil = require('gulp-util') 14 | 15 | // websdk.js 16 | // websdk.min.js 17 | // websdk.min.js.map 18 | gulp.task('sdk', ['sdk:umd', 'sdk:umd:min']) 19 | 20 | // websdk.js 21 | gulp.task('sdk:umd', function () { 22 | return gulp.src('./index.js') 23 | .pipe(webpack({ 24 | output: { 25 | filename: 'websdk.browser.js', 26 | library: 'WebIM', 27 | libraryTarget: 'umd' 28 | } 29 | }) 30 | ) 31 | .pipe(gulp.dest('dist/')) 32 | }) 33 | 34 | // websdk.min.js 35 | // websdk.min.js.map 36 | gulp.task('sdk:umd:min', ['sdk:umd'], function () { 37 | return gulp.src('./dist/websdk.browser.js') 38 | .pipe(sourcemaps.init({loadMaps: true})) 39 | .pipe(uglify()) 40 | .pipe(rename('websdk.browser.min.js')) 41 | .on('error', gutil.log) 42 | .pipe(sourcemaps.write('./')) 43 | .pipe(gulp.dest('dist/')) 44 | }) 45 | 46 | gulp.task('default', ['sdk']) 47 | 48 | // 49 | // gulp.task('watch', function() { 50 | // livereload.listen(); //要在这里调用listen()方法 51 | // gulp.watch('less/*.less', ['less']); 52 | // }); 53 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/app/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.app; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import com.facebook.react.ReactApplication; 7 | import com.imagepicker.ImagePickerPackage; 8 | import com.oblador.vectoricons.VectorIconsPackage; 9 | import com.airbnb.android.react.maps.MapsPackage; 10 | import com.i18n.reactnativei18n.ReactNativeI18n; 11 | import com.learnium.RNDeviceInfo.RNDeviceInfo; 12 | import com.lugg.ReactNativeConfig.ReactNativeConfigPackage; 13 | import com.facebook.react.ReactInstanceManager; 14 | import com.facebook.react.ReactNativeHost; 15 | import com.facebook.react.ReactPackage; 16 | import com.facebook.react.shell.MainReactPackage; 17 | 18 | import java.util.Arrays; 19 | import java.util.List; 20 | 21 | public class MainApplication extends Application implements ReactApplication { 22 | 23 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 24 | @Override 25 | protected boolean getUseDeveloperSupport() { 26 | return BuildConfig.DEBUG; 27 | } 28 | 29 | @Override 30 | protected List getPackages() { 31 | return Arrays.asList( 32 | new MainReactPackage(), 33 | new ImagePickerPackage(), 34 | new VectorIconsPackage(), 35 | new MapsPackage(), 36 | new ReactNativeI18n(), 37 | new RNDeviceInfo(), 38 | new ReactNativeConfigPackage() 39 | ); 40 | } 41 | }; 42 | 43 | @Override 44 | public ReactNativeHost getReactNativeHost() { 45 | return mReactNativeHost; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.tmp/reactNativeBuild/debuggerWorker.js: -------------------------------------------------------------------------------- 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 | /* global __fbBatchedBridge, self, importScripts, postMessage, onmessage: true */ 10 | /* eslint no-unused-vars: 0 */ 11 | 'use strict'; 12 | 13 | var messageHandlers = { 14 | 'executeApplicationScript': function(message, sendReply) { 15 | for (var key in message.inject) { 16 | self[key] = JSON.parse(message.inject[key]); 17 | } 18 | let error; 19 | try { 20 | importScripts(message.url); 21 | } catch (err) { 22 | error = JSON.stringify(err); 23 | } 24 | sendReply(null /* result */, error); 25 | } 26 | }; 27 | 28 | onmessage = function(message) { 29 | var object = message.data; 30 | 31 | var sendReply = function(result, error) { 32 | postMessage({replyID: object.id, result: result, error: error}); 33 | }; 34 | 35 | var handler = messageHandlers[object.method]; 36 | if (handler) { 37 | // Special cased handlers 38 | handler(object, sendReply); 39 | } else { 40 | // Other methods get called on the bridge 41 | var returnValue = [[], [], [], 0]; 42 | try { 43 | if (typeof __fbBatchedBridge === 'object') { 44 | returnValue = __fbBatchedBridge[object.method].apply(null, object.arguments); 45 | } 46 | } finally { 47 | sendReply(JSON.stringify(returnValue)); 48 | } 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /App/Redux/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {combineReducers} from 'redux' 4 | import configureStore from './CreateStore' 5 | // import rootSaga from '../Sagas/' 6 | 7 | export default () => { 8 | /* ------------- Assemble The Reducers ------------- */ 9 | let rootReducer = combineReducers({ 10 | entities: combineReducers({ 11 | roster: require('./RosterRedux').reducer, 12 | group: require('./GroupRedux').reducer, 13 | groupMember: require('./GroupMemberRedux').reducer, 14 | subscribe: require('./SubscribeRedux').reducer, 15 | blacklist: require('./BlacklistRedux').reducer, 16 | message: require('./MessageRedux').reducer, 17 | }), 18 | ui: combineReducers({ 19 | common: require('./CommonRedux').reducer, 20 | login: require('./LoginRedux').reducer, 21 | contacts: require('./ContactsScreenRedux').reducer, 22 | }), 23 | im: require('./WebIMRedux').reducer 24 | }) 25 | 26 | // 登出清空state 27 | const appReducer = (state, action) => { 28 | if (action.type === 'USER_LOGOUT') { 29 | state = {} 30 | } 31 | 32 | return rootReducer(state, action) 33 | } 34 | 35 | const store = configureStore(appReducer) 36 | 37 | // Provider does not support changing `store` on the fly 38 | // TODO https://github.com/reactjs/react-redux/releases/tag/v2.0.0 by lwz 39 | 40 | // if (module && module.hot) { 41 | // // Enable Webpack hot module replacement for reducers 42 | // module.hot.accept(() => { 43 | // // const nextRootReducer = require('../reducers/index'); 44 | // store.replaceReducer(rootReducer) 45 | // }); 46 | // } 47 | 48 | return store 49 | } 50 | -------------------------------------------------------------------------------- /App/Themes/Images.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // leave off @2x/@3x 4 | const images = { 5 | logo: require('../Images/logoGreen.png'), 6 | clearLogo: require('../Images/top_logo.png'), 7 | ignite: require('../Images/ignite_logo.png'), 8 | tileBg: require('../Images/tile_bg.png'), 9 | background: require('../Images/BG.png'), 10 | chats: require('../Images/chats.png'), 11 | chatsActive: require('../Images/chats.png'), 12 | contacts: require('../Images/contactsActive.png'), 13 | contactsActive: require('../Images/contactsActive.png'), 14 | settings: require('../Images/settings.png'), 15 | settingsActive: require('../Images/settings.png'), 16 | invitationsIcon: require('../Images/invitationsIcon.png'), 17 | requestsIcon: require('../Images/requestsIcon.png'), 18 | default: require('../Images/default.png'), 19 | groupDefault: require('../Images/groupDefault.png'), 20 | buttonChat: require('../Images/buttonChat.png'), 21 | buttonCall: require('../Images/buttonCall.png'), 22 | buttonVideo: require('../Images/buttonVideo.png'), 23 | message: require('../Images/message.png'), 24 | feedback: require('../Images/feedback.png'), 25 | iconAdd: require('../Images/iconAdd.png'), 26 | iconAudio: require('../Images/iconAudio.png'), 27 | iconCamera: require('../Images/iconCamera.png'), 28 | iconEmoji: require('../Images/iconEmoji.png'), 29 | iconEmojiActive: require('../Images/iconEmojiActive.png'), 30 | iconFile: require('../Images/iconFile.png'), 31 | iconLocation: require('../Images/iconLocation.png'), 32 | iconImage: require('../Images/iconImage.png'), 33 | logout: require('../Images/logout.png'), 34 | } 35 | 36 | export default images 37 | -------------------------------------------------------------------------------- /App/Lib/apisauce/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apisauce", 3 | "version": "0.5.0", 4 | "description": "A JSON API client for JavaScript. No, no. Not like that. Like this.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/skellock/apisauce.git" 8 | }, 9 | "main": "./dist/apisauce.js", 10 | "scripts": { 11 | "test": "ava", 12 | "watch": "npm run test -- --watch", 13 | "coverage": "nyc ava", 14 | "dist": "npm run clean && npm run build && npm run docs", 15 | "docs": "node_modules/.bin/jsdoc --configure .jsdoc.json", 16 | "clean": "rm -rf dist docs", 17 | "build": "BABEL_ENV=production rollup -c" 18 | }, 19 | "keywords": [ 20 | "axios", 21 | "api", 22 | "network", 23 | "http" 24 | ], 25 | "author": "Steve Kellock ", 26 | "license": "MIT", 27 | "files": [ 28 | "dist/apisauce.js" 29 | ], 30 | "dependencies": { 31 | "axios": "^0.13.1", 32 | "ramda": "^0.22.1", 33 | "ramdasauce": "^1.1.1" 34 | }, 35 | "devDependencies": { 36 | "ava": "^0.16.0", 37 | "babel-cli": "^6.11.4", 38 | "babel-core": "^6.13.2", 39 | "babel-eslint": "^6.1.2", 40 | "babel-plugin-transform-runtime": "^6.12.0", 41 | "babel-preset-es2015": "^6.13.2", 42 | "babel-preset-es2015-rollup": "^1.2.0", 43 | "babel-preset-stage-0": "^6.5.0", 44 | "docdash": "^0.4.0", 45 | "jsdoc": "^3.4.0", 46 | "nyc": "^8.1.0", 47 | "rollup": "^0.34.9", 48 | "rollup-plugin-babel": "^2.6.1", 49 | "standard": "^7.1.2", 50 | "xyz": "^1.0.0" 51 | }, 52 | "ava": { 53 | "require": [ 54 | "babel-core/register" 55 | ] 56 | }, 57 | "standard": { 58 | "parser": "babel-eslint" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Tests/Components/AlertMessageTest.js: -------------------------------------------------------------------------------- 1 | // https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md 2 | import test from 'ava' 3 | import React from 'react' 4 | import { Text } from 'react-native' 5 | import Icon from 'react-native-vector-icons/Ionicons' 6 | import AlertMessage from '../../App/Components/AlertMessage' 7 | import { shallow } from 'enzyme' 8 | 9 | // Basic wrapper 10 | const wrapper = shallow() 11 | 12 | test('component exists', (t) => { 13 | t.is(wrapper.length, 1) // exists 14 | }) 15 | 16 | test('component structure', (t) => { 17 | t.is(wrapper.name(), 'Animatable.View') 18 | t.is(wrapper.children().length, 1) // has 1 child 19 | t.is(wrapper.children().first().name(), 'View') // that child is View 20 | 21 | const subview = wrapper.children().first() 22 | // The View should contain the icon and text 23 | t.is(subview.children().length, 2) // has 2 children 24 | }) 25 | 26 | test('Has text and set properly', (t) => { 27 | t.is(wrapper.containsMatchingElement(HOWDY), true) 28 | }) 29 | 30 | test('Has Icon and set properly', (t) => { 31 | // default 32 | t.is(wrapper.containsMatchingElement(), true) 33 | 34 | // custom 35 | const custom = shallow( {}} title='howdy' icon='test' />) 36 | t.is(custom.containsMatchingElement(), true) 37 | }) 38 | 39 | test('style props are passed to top view', (t) => { 40 | const withStyle = shallow() 41 | t.is(withStyle.props().style[1].color, 'red') 42 | }) 43 | 44 | test('show false', (t) => { 45 | const hidden = shallow() 46 | t.is(hidden.children().length, 0) 47 | }) 48 | -------------------------------------------------------------------------------- /android/app/BUCK: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | # To learn about Buck see [Docs](https://buckbuild.com/). 4 | # To run your application with Buck: 5 | # - install Buck 6 | # - `npm start` - to start the packager 7 | # - `cd android` 8 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 9 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 10 | # - `buck install -r android/app` - compile, install and run application 11 | # 12 | 13 | lib_deps = [] 14 | for jarfile in glob(['libs/*.jar']): 15 | name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile) 16 | lib_deps.append(':' + name) 17 | prebuilt_jar( 18 | name = name, 19 | binary_jar = jarfile, 20 | ) 21 | 22 | for aarfile in glob(['libs/*.aar']): 23 | name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile) 24 | lib_deps.append(':' + name) 25 | android_prebuilt_aar( 26 | name = name, 27 | aar = aarfile, 28 | ) 29 | 30 | android_library( 31 | name = 'all-libs', 32 | exported_deps = lib_deps 33 | ) 34 | 35 | android_library( 36 | name = 'app-code', 37 | srcs = glob([ 38 | 'src/main/java/**/*.java', 39 | ]), 40 | deps = [ 41 | ':all-libs', 42 | ':build_config', 43 | ':res', 44 | ], 45 | ) 46 | 47 | android_build_config( 48 | name = 'build_config', 49 | package = 'com.app', 50 | ) 51 | 52 | android_resource( 53 | name = 'res', 54 | res = 'src/main/res', 55 | package = 'com.app', 56 | ) 57 | 58 | android_binary( 59 | name = 'app', 60 | package_type = 'debug', 61 | manifest = 'src/main/AndroidManifest.xml', 62 | keystore = '//android/keystores:debug', 63 | deps = [ 64 | ':app-code', 65 | ], 66 | ) 67 | -------------------------------------------------------------------------------- /App/Components/AlertMessage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React from 'react' 4 | import { View, Text } from 'react-native' 5 | import styles from './Styles/AlertMessageStyle' 6 | import * as Animatable from 'react-native-animatable' 7 | import { Metrics } from '../Themes/' 8 | import Icon from 'react-native-vector-icons/Ionicons' 9 | import ExamplesRegistry from '../Services/ExamplesRegistry' 10 | 11 | // Example 12 | ExamplesRegistry.add('Alert Message', () => 13 | 14 | 17 | 21 | 22 | ) 23 | 24 | type AlertMessageProps = { 25 | title: string, 26 | icon?: string, 27 | style?: Object, 28 | show?: bool 29 | } 30 | 31 | export default class AlertMessage extends React.Component { 32 | static defaultProps: { show: boolean } 33 | 34 | props: AlertMessageProps 35 | 36 | render () { 37 | let messageComponent = null 38 | if (this.props.show) { 39 | const { title } = this.props 40 | return ( 41 | 46 | 47 | 52 | {title && title.toUpperCase()} 53 | 54 | 55 | ) 56 | } 57 | 58 | return messageComponent 59 | } 60 | } 61 | 62 | AlertMessage.defaultProps = { 63 | show: true 64 | } 65 | -------------------------------------------------------------------------------- /App/Lib/PlatformStyleSheet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 Facebook, Inc. 3 | * 4 | * You are hereby granted a non-exclusive, worldwide, royalty-free license to 5 | * use, copy, modify, and distribute this software in source code or binary 6 | * form for use in connection with the web services and APIs provided by 7 | * Facebook. 8 | * 9 | * As with any software that integrates with the Facebook platform, your use 10 | * of this software is subject to the Facebook Developer Principles and 11 | * Policies [http://developers.facebook.com/policy/]. This copyright notice 12 | * shall be included in all copies or substantial portions of the software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE 21 | * 22 | * @providesModule F8StyleSheet 23 | * @flow 24 | */ 25 | 26 | 'use strict' 27 | 28 | import {StyleSheet, Platform} from 'react-native' 29 | 30 | export function create(styles) { 31 | const platformStyles = {} 32 | Object.keys(styles).forEach((name) => { 33 | let {ios, android, ...style} = {...styles[name]} 34 | if (ios && Platform.OS === 'ios') { 35 | style = {...style, ...ios} 36 | } 37 | if (android && Platform.OS === 'android') { 38 | style = {...style, ...android} 39 | } 40 | platformStyles[name] = style 41 | // platformStyles[name]['borderWidth'] = 1 42 | }) 43 | return StyleSheet.create(platformStyles) 44 | } 45 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/helpers/buildURL.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./../utils'); 4 | 5 | function encode(val) { 6 | return encodeURIComponent(val). 7 | replace(/%40/gi, '@'). 8 | replace(/%3A/gi, ':'). 9 | replace(/%24/g, '$'). 10 | replace(/%2C/gi, ','). 11 | replace(/%20/g, '+'). 12 | replace(/%5B/gi, '['). 13 | replace(/%5D/gi, ']'); 14 | } 15 | 16 | /** 17 | * Build a URL by appending params to the end 18 | * 19 | * @param {string} url The base of the url (e.g., http://www.google.com) 20 | * @param {object} [params] The params to be appended 21 | * @returns {string} The formatted url 22 | */ 23 | module.exports = function buildURL(url, params, paramsSerializer) { 24 | /*eslint no-param-reassign:0*/ 25 | if (!params) { 26 | return url; 27 | } 28 | 29 | var serializedParams; 30 | if (paramsSerializer) { 31 | serializedParams = paramsSerializer(params); 32 | } else if (utils.isURLSearchParams(params)) { 33 | serializedParams = params.toString(); 34 | } else { 35 | var parts = []; 36 | 37 | utils.forEach(params, function serialize(val, key) { 38 | if (val === null || typeof val === 'undefined') { 39 | return; 40 | } 41 | 42 | if (utils.isArray(val)) { 43 | key = key + '[]'; 44 | } 45 | 46 | if (!utils.isArray(val)) { 47 | val = [val]; 48 | } 49 | 50 | utils.forEach(val, function parseValue(v) { 51 | if (utils.isDate(v)) { 52 | v = v.toISOString(); 53 | } else if (utils.isObject(v)) { 54 | v = JSON.stringify(v); 55 | } 56 | parts.push(encode(key) + '=' + encode(v)); 57 | }); 58 | }); 59 | 60 | serializedParams = parts.join('&'); 61 | } 62 | 63 | if (serializedParams) { 64 | url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams; 65 | } 66 | 67 | return url; 68 | }; 69 | -------------------------------------------------------------------------------- /App/Themes/Colors.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {Platform} from 'react-native' 3 | 4 | // 不能使用rgb,必须rgba 5 | const colors = { 6 | background: 'rgba(0, 0, 0, 0)', 7 | clear: 'rgba(0,0,0,0)', 8 | facebook: '#3b5998', 9 | transparent: 'rgba(0,0,0,0)', 10 | silver: '#F7F7F7', 11 | steel: '#CCCCCC', 12 | error: 'rgba(200, 0, 0, 0.8)', 13 | ricePaper: 'rgba(255,255,255, 0.75)', 14 | frost: '#D8D8D8', 15 | cloud: 'rgba(200,200,200, 0.35)', 16 | windowTint: 'rgba(0, 0, 0, 0.4)', 17 | panther: '#161616', 18 | charcoal: '#595959', 19 | coal: '#2d2d2d', 20 | bloodOrange: '#fb5f26', 21 | snow: 'white', 22 | ember: 'rgba(164, 0, 48, 0.5)', 23 | fire: '#e73536', 24 | drawer: 'rgba(30, 30, 29, 0.95)', 25 | login: 'rgba(61, 92, 120, 1)', 26 | coolGrey: '#adb9c1', 27 | coolGrey50: 'rgba(173, 185, 193, 0.5)', 28 | placeholderTextColor: '#adb9c1', 29 | selectionColor: '#404f5a', 30 | almostBlack: 'rgba(12, 18, 24, 1)', 31 | almostWhite: 'rgba(255, 255, 255, 0.7)', 32 | centerLine: '#4a4a4a', 33 | andBgStart: '#3e5c78', 34 | andBgEnd: '#243e55', 35 | buttonSignin: '#00ba6e', 36 | modelHeaderText: 'rgba(0, 186, 110, 1)', 37 | button: '#adb9c1', 38 | frogGreen: 'rgba(82, 210, 0, 1)', 39 | iconColor: '#8798a4', 40 | blueGrey: 'rgba(135, 152, 164, 1)', 41 | denim: 'rgba(64, 94, 122, 1)', 42 | buttonGreen: '#08ba6e', 43 | buttonGrey: '#8798a4', 44 | steelGrey: 'rgba(112, 126, 137, 1)', 45 | paleGrey: 'rgba(228, 233, 236, 1)', 46 | white1: 'rgba(250, 251, 252, 1)', 47 | orangeRed: 'rgba(255, 59, 48, 1)', 48 | coolGrey190: 'rgba(190, 190, 190, 1)', 49 | textRed: 'rgba(0, 186, 110, 1)', 50 | paleGreyTwo: 'rgba(236, 239, 241, 1)', 51 | messageSelf: 'rgba(0, 186, 110, 1)', 52 | emojiBackground: '#e8ebef' 53 | } 54 | const colorsIos = {} 55 | 56 | const colorsAndroid = {} 57 | 58 | export default Object.assign(colors, (Platform.OS == 'ios' ? colorsIos : colorsAndroid)) 59 | -------------------------------------------------------------------------------- /App/I18n/english.json: -------------------------------------------------------------------------------- 1 | { 2 | "signIn": "SIGN IN", 3 | "logOut": "Log Out", 4 | "loginLogoutExampleTitle": "Login/Logout Redux + Sagas Example", 5 | "progressiveImageComponent": "Progressive Image Component", 6 | "api": "API", 7 | "locale": "I18n Locale", 8 | "rnVectorIcons": "RN Vector Icons", 9 | "loginWithFacebook": "Login with Facebook", 10 | "rnAnimatable": "RN Animatable", 11 | "igniteGenerated": "Ignite Generate Screens", 12 | "forgotPassword": "Forgot Password", 13 | "username": "Hyphenate ID", 14 | "password": "Password", 15 | "signUpTips": "Yay! New to Hyphenate?", 16 | "signInTips": "Have a account?", 17 | "signUp": "Sign up", 18 | "signIn": "Sign in", 19 | "cancel": "Cancel", 20 | "welcome": "Welcome", 21 | "login": "Login", 22 | "tempIndicator": "F", 23 | "componentExamples": "Component Examples", 24 | "usageExamples": "Usage Examples", 25 | "apiTesting": "API Testing", 26 | "themeSettings": "Theme Settings", 27 | "deviceDetails": "Device Details", 28 | "noItems": "No Items", 29 | "invalidID": "Invalid id", 30 | "invalidPassword": "Invalid password", 31 | "contactTabContacts": "Contacts", 32 | "contactTabChats": "Chats", 33 | "contactTabSettings": "Settings", 34 | "search": "Search", 35 | "addContact": "Add Contact", 36 | "add": "Add", 37 | "enterHyphenateID": "Enter Hyphenate ID", 38 | "contactRequests": "Contact Requests", 39 | "accept": "Accept", 40 | "decline": "Decline", 41 | "request": "want to add you as a friend", 42 | "unsubscribed": "unsubscribed from you.", 43 | "subscribed": "has been your friend.", 44 | "infoName": "Name", 45 | "infoID": "Hyphenate ID", 46 | "blockContact": "Block Contact", 47 | "deleteContact": "Delete Contact", 48 | "requestHasSent": "Your request has been sent", 49 | "groups": "Groups", 50 | "newChat": "New Chat", 51 | "newGroup": "New Group", 52 | "sendMessage": "Send Message", 53 | "send": "Send" 54 | } 55 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | # We fork some components by platform. 4 | .*/*[.]android.js 5 | 6 | # Ignore templates with `@flow` in header 7 | .*/local-cli/generator.* 8 | 9 | # Ignore malformed json 10 | .*/node_modules/y18n/test/.*\.json 11 | 12 | # Ignore the website subdir 13 | /website/.* 14 | 15 | # Ignore BUCK generated dirs 16 | /\.buckd/ 17 | 18 | # Ignore unexpected extra @providesModule 19 | .*/node_modules/commoner/test/source/widget/share.js 20 | 21 | # Ignore duplicate module providers 22 | # For RN Apps installed via npm, "Libraries" folder is inside node_modules/react-native but in the source repo it is in the root 23 | .*/Libraries/react-native/React.js 24 | .*/Libraries/react-native/ReactNative.js 25 | .*/node_modules/jest-runtime/build/__tests__/.* 26 | 27 | [include] 28 | 29 | [libs] 30 | node_modules/react-native/Libraries/react-native/react-native-interface.js 31 | node_modules/react-native/flow 32 | flow/ 33 | 34 | [options] 35 | module.system=haste 36 | 37 | esproposal.class_static_fields=enable 38 | esproposal.class_instance_fields=enable 39 | 40 | experimental.strict_type_args=true 41 | 42 | munge_underscores=true 43 | 44 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' 45 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 46 | 47 | suppress_type=$FlowIssue 48 | suppress_type=$FlowFixMe 49 | suppress_type=$FixMe 50 | 51 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-3]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 52 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-3]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 53 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 54 | 55 | unsafe.enable_getters_and_setters=true 56 | 57 | [version] 58 | ^0.33.0 59 | -------------------------------------------------------------------------------- /App/Components/Base.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | View, 4 | Text, 5 | Image, 6 | TouchableOpacity 7 | } from 'react-native' 8 | import Styles from './Styles/RowStyle' 9 | import {Images, Metrics, Colors} from '../Themes' 10 | 11 | const data = { 12 | onPress: null, 13 | style: {}, 14 | subs: [ 15 | { 16 | type: 'image' 17 | }, 18 | { 19 | onPress: null, // func / null 20 | style: {}, 21 | subs: [ 22 | { 23 | style: {}, 24 | wrapperStyle: {}, 25 | type: 'text', 26 | text: '123' 27 | }, 28 | { 29 | style: {}, 30 | type: 'text', 31 | text: '456' 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | // 复杂对象 38 | // - {{}} 39 | // 多组合 40 | // - 1-2-1 41 | // - m-tt-b (i:icon m:image t:text b:button s:switch) 42 | // [{, [{}, {}], {}] 43 | 44 | 45 | export default class Base extends React.Component { 46 | 47 | renderComponent(sub) { 48 | const {type, style = {}} = sub 49 | 50 | switch (type) { 51 | case 'text': 52 | return sub.text 53 | break 54 | } 55 | 56 | } 57 | 58 | renderSubs(subs) { 59 | const views = [] 60 | 61 | subs.forEach((sub) => { 62 | const {wrapperStyle = {}} = sub 63 | 64 | if (sub.subs) { 65 | views.push( 66 | 67 | { this.renderSubs(sub.subs) } 68 | 69 | ) 70 | } else { 71 | views.push( 72 | 73 | { this.renderComponent(sub) } 74 | 75 | ) 76 | } 77 | }) 78 | 79 | return views 80 | } 81 | 82 | render() { 83 | 84 | if (!data) return null 85 | 86 | const subs = this.renderSubs(data.subs) 87 | 88 | return ( 89 | 90 | {subs} 91 | 92 | ) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /App/Redux/GroupRedux.js: -------------------------------------------------------------------------------- 1 | import {createReducer, createActions} from 'reduxsauce' 2 | import Immutable from 'seamless-immutable' 3 | 4 | /* ------------- Types and Action Creators ------------- */ 5 | 6 | const {Types, Creators} = createActions({ 7 | updateGroupInfo: ['info'], 8 | updateGroup: ['groups'], 9 | // ---------------async------------------ 10 | getGroups: () => { 11 | return (dispatch, getState) => { 12 | WebIM.conn.listRooms({ 13 | success: function (rooms) { 14 | dispatch(Creators.updateGroup(rooms)) 15 | }, 16 | error: function (e) { 17 | WebIM.conn.setPresence(); 18 | } 19 | }); 20 | } 21 | }, 22 | }) 23 | 24 | export const GroupsTypes = Types 25 | export default Creators 26 | 27 | /* ------------- Initial State ------------- */ 28 | 29 | export const INITIAL_STATE = Immutable({ 30 | byName: {}, 31 | names: [], 32 | }) 33 | 34 | /* ------------- Reducers ------------- */ 35 | // [{jid,name,roomId}] groups 36 | export const updateGroup = (state, {groups}) => { 37 | let byName = {} 38 | let byId = {} 39 | groups.forEach((v) => { 40 | byName[v.name] = v 41 | byId[v.roomId] = v 42 | }) 43 | return state.merge({ 44 | byName, 45 | byId, 46 | names: Object.keys(byName).sort() 47 | }) 48 | } 49 | 50 | // [{affiliations,description,maxusers,name,occupants,owner}] info 51 | export const updateGroupInfo = (state, {info}) => { 52 | // let byName = {} 53 | // let byId = {} 54 | // state.group.forEach((v) => { 55 | // byName[v.name] = v 56 | // byId[v.roomId] = v 57 | // }) 58 | // return state.merge({ 59 | // byName, 60 | // byId, 61 | // names: Object.keys(byName) 62 | // }) 63 | state.group.byName[info.name] 64 | return {} 65 | } 66 | 67 | /* ------------- Hookup Reducers To Types ------------- */ 68 | 69 | export const reducer = createReducer(INITIAL_STATE, { 70 | [Types.UPDATE_GROUP]: updateGroup, 71 | }) 72 | 73 | /* ------------- Selectors ------------- */ 74 | -------------------------------------------------------------------------------- /App/Redux/SubscribeRedux.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import {createReducer, createActions} from 'reduxsauce' 4 | import Immutable from 'seamless-immutable' 5 | import WebIM from '../Lib/WebIM' 6 | 7 | /* ------------- Types and Action Creators ------------- */ 8 | 9 | const {Types, Creators} = createActions({ 10 | addSubscribe: ['msg'], 11 | removeSubscribe: ['name'], 12 | // ----------------async------------------ 13 | // 接受好友请求 14 | acceptSubscribe: (name) => { 15 | return (dispatch, getState) => { 16 | dispatch(Creators.removeSubscribe(name)) 17 | 18 | WebIM.conn.subscribed({ 19 | to: name, 20 | message: '[resp:true]' 21 | }) 22 | 23 | WebIM.conn.subscribe({ 24 | to: name, 25 | message: '[resp:true]' 26 | }) 27 | } 28 | }, 29 | // 拒绝好友请求 30 | declineSubscribe: (name) => { 31 | return (dispatch, getState) => { 32 | dispatch(Creators.removeSubscribe(name)) 33 | 34 | WebIM.conn.unsubscribed({ 35 | to: name, 36 | message: new Date().toLocaleString() 37 | }) 38 | } 39 | } 40 | }) 41 | 42 | export const SubscribeTypes = Types 43 | export default Creators 44 | 45 | /* ------------- Initial State ------------- */ 46 | 47 | export const INITIAL_STATE = Immutable({ 48 | byFrom: {}, 49 | }) 50 | 51 | /* ------------- Reducers ------------- */ 52 | 53 | export const subscribe = (state, {msg}) => { 54 | return state.merge({ 55 | byFrom: Immutable(state.byFrom).set(msg.from, msg) 56 | }, {deep: true}) 57 | } 58 | 59 | export const removeSubscribe = (state, {name}) => { 60 | let subs = state.byFrom.asMutable() 61 | delete subs[name] 62 | return state.merge({ 63 | byFrom: Immutable(subs) 64 | }) 65 | } 66 | 67 | /* ------------- Hookup Reducers To Types ------------- */ 68 | 69 | export const reducer = createReducer(INITIAL_STATE, { 70 | [Types.ADD_SUBSCRIBE]: subscribe, 71 | [Types.REMOVE_SUBSCRIBE]: removeSubscribe, 72 | }) 73 | 74 | /* ------------- Selectors ------------- */ 75 | -------------------------------------------------------------------------------- /App/Lib/axios/axios.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Axios v0.8.1 2 | // Project: https://github.com/mzabriskie/axios 3 | 4 | 5 | 6 | declare var axios: axios.AxiosStatic 7 | 8 | declare module axios { 9 | interface AxiosRequestMethods { 10 | get(url: string, config?: any): axios.Promise; 11 | delete(url: string, config?: any): axios.Promise; 12 | head(url: string, config?: any): axios.Promise; 13 | post(url: string, data: any, config?: any): axios.Promise; 14 | put(url: string, data: any, config?: any): axios.Promise; 15 | patch(url: string, data: any, config?: any): axios.Promise; 16 | } 17 | 18 | interface AxiosStatic extends AxiosRequestMethods { 19 | (options: axios.RequestOptions): axios.Promise; 20 | create(defaultOptions?: axios.InstanceOptions): AxiosInstance; 21 | all(iterable: any): axios.Promise; 22 | spread(callback: any): axios.Promise; 23 | } 24 | 25 | interface AxiosInstance extends AxiosRequestMethods { 26 | request(options: axios.RequestOptions): axios.Promise; 27 | } 28 | 29 | interface Response { 30 | data?: any; 31 | status?: number; 32 | statusText?: string; 33 | headers?: any; 34 | config?: any; 35 | } 36 | 37 | interface Promise { 38 | then(onFulfilled:(response: axios.Response) => void): axios.Promise; 39 | catch(onRejected:(response: axios.Response) => void): axios.Promise; 40 | } 41 | 42 | interface InstanceOptions { 43 | transformRequest?: (data: any) => any; 44 | transformResponse?: (data: any) => any; 45 | headers?: any; 46 | timeout?: number; 47 | withCredentials?: boolean; 48 | responseType?: string; 49 | xsrfCookieName?: string; 50 | xsrfHeaderName?: string; 51 | paramsSerializer?: (params: any) => string; 52 | baseURL?: string; 53 | } 54 | 55 | interface RequestOptions extends InstanceOptions { 56 | url: string; 57 | method?: string; 58 | params?: any; 59 | data?: any; 60 | } 61 | } 62 | 63 | declare module "axios" { 64 | export = axios; 65 | } 66 | -------------------------------------------------------------------------------- /App/Containers/PresentationScreen.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React from 'react' 4 | import { ScrollView, Text, Image, View } from 'react-native' 5 | import { Images } from '../Themes' 6 | import RoundedButton from '../Components/RoundedButton' 7 | import { Actions as NavigationActions } from 'react-native-router-flux' 8 | 9 | // Styles 10 | import styles from './Styles/PresentationScreenStyle' 11 | 12 | export default class PresentationScreen extends React.Component { 13 | render () { 14 | return ( 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Default screens for development, debugging, and alpha testing 25 | are available below. 26 | 27 | 28 | 29 | 30 | Component Examples Screen 31 | 32 | 33 | 34 | Usage Examples Screen 35 | 36 | 37 | 38 | API Testing Screen 39 | 40 | 41 | 42 | Theme Screen 43 | 44 | 45 | 46 | Device Info Screen 47 | 48 | 49 | 50 | Made with ❤️ by Infinite Red 51 | 52 | 53 | 54 | 55 | ) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /App/Themes/ApplicationStyles.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import Fonts from './Fonts' 4 | import Metrics from './Metrics' 5 | import Colors from './Colors' 6 | 7 | // This file is for a reusable grouping of Theme items. 8 | // Similar to an XML fragment layout in Android 9 | 10 | const ApplicationStyles = { 11 | screen: { 12 | mainContainer: { 13 | flex: 1, 14 | marginTop: Metrics.navBarHeight, 15 | backgroundColor: Colors.transparent 16 | }, 17 | backgroundImage: { 18 | position: 'absolute', 19 | top: 0, 20 | left: 0, 21 | bottom: 0, 22 | right: 0 23 | }, 24 | container: { 25 | flex: 1, 26 | paddingTop: Metrics.baseMargin 27 | }, 28 | section: { 29 | margin: Metrics.section, 30 | padding: Metrics.baseMargin, 31 | borderTopColor: Colors.frost, 32 | borderTopWidth: 0.5, 33 | borderBottomColor: Colors.frost, 34 | borderBottomWidth: 1 35 | }, 36 | sectionText: { 37 | color: Colors.snow, 38 | marginVertical: Metrics.smallMargin, 39 | textAlign: 'center', 40 | fontWeight: 'bold' 41 | }, 42 | subtitle: { 43 | color: Colors.snow, 44 | padding: Metrics.smallMargin, 45 | marginBottom: Metrics.smallMargin, 46 | marginHorizontal: Metrics.smallMargin 47 | } 48 | }, 49 | darkLabelContainer: { 50 | backgroundColor: Colors.cloud, 51 | padding: Metrics.smallMargin 52 | }, 53 | darkLabel: { 54 | fontFamily: Fonts.type.bold, 55 | color: Colors.snow 56 | }, 57 | groupContainer: { 58 | margin: Metrics.smallMargin, 59 | flexDirection: 'row', 60 | justifyContent: 'space-around', 61 | alignItems: 'center' 62 | }, 63 | sectionTitle: { 64 | ...Fonts.style.h4, 65 | color: Colors.coal, 66 | backgroundColor: Colors.ricePaper, 67 | padding: Metrics.smallMargin, 68 | marginTop: Metrics.smallMargin, 69 | marginHorizontal: Metrics.baseMargin, 70 | borderWidth: 1, 71 | borderColor: Colors.ember, 72 | alignItems: 'center', 73 | textAlign: 'center' 74 | } 75 | } 76 | 77 | export default ApplicationStyles 78 | -------------------------------------------------------------------------------- /App/Components/InfoNavBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {View, Text, Animated, TouchableOpacity} from 'react-native' 3 | import {Images, Colors} from '../Themes' 4 | import Styles from './Styles/InfoNavBarStyle' 5 | import Icon from 'react-native-vector-icons/Ionicons' 6 | import {Actions as NavigationActions} from 'react-native-router-flux' 7 | 8 | export default class InfoNavBar extends React.Component { 9 | render() { 10 | const { 11 | title, 12 | containerStyle = {}, 13 | rightTitle = '', 14 | rightIcon = '', 15 | rightShow = true, 16 | onRight = NavigationActions.pop, 17 | leftTitle = '', 18 | leftIcon = 'ios-arrow-back', 19 | onLeft = NavigationActions.pop, 20 | leftShow = true 21 | } = this.props 22 | 23 | const rightButtonTitleComponent = rightTitle 24 | ? ({rightTitle}) : null 25 | const rightButtonIconComponent = rightIcon 26 | ? () : null 27 | const rightButton = ( 28 | 29 | {rightButtonTitleComponent || rightButtonIconComponent} 30 | 31 | ) 32 | 33 | const leftButtonTitleComponent = leftTitle 34 | ? ({leftTitle}) : null 35 | const leftButtonIconComponent = leftIcon 36 | ? () : null 37 | const leftButton = ( 38 | 39 | {leftButtonTitleComponent || leftButtonIconComponent} 40 | 41 | ) 42 | return ( 43 | 44 | 45 | {leftShow ? leftButton : null} 46 | 47 | {title} 48 | 49 | {rightShow ? rightButton : null} 50 | 51 | 52 | ) 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/defaults.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./utils'); 4 | var normalizeHeaderName = require('./helpers/normalizeHeaderName'); 5 | 6 | var PROTECTION_PREFIX = /^\)\]\}',?\n/; 7 | var DEFAULT_CONTENT_TYPE = { 8 | 'Content-Type': 'application/x-www-form-urlencoded' 9 | }; 10 | 11 | function setContentTypeIfUnset(headers, value) { 12 | if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) { 13 | headers['Content-Type'] = value; 14 | } 15 | } 16 | 17 | module.exports = { 18 | transformRequest: [function transformRequest(data, headers) { 19 | normalizeHeaderName(headers, 'Content-Type'); 20 | if (utils.isFormData(data) || 21 | utils.isArrayBuffer(data) || 22 | utils.isStream(data) || 23 | utils.isFile(data) || 24 | utils.isBlob(data) 25 | ) { 26 | return data; 27 | } 28 | if (utils.isArrayBufferView(data)) { 29 | return data.buffer; 30 | } 31 | if (utils.isURLSearchParams(data)) { 32 | setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8'); 33 | return data.toString(); 34 | } 35 | if (utils.isObject(data)) { 36 | setContentTypeIfUnset(headers, 'application/json;charset=utf-8'); 37 | return JSON.stringify(data); 38 | } 39 | return data; 40 | }], 41 | 42 | transformResponse: [function transformResponse(data) { 43 | /*eslint no-param-reassign:0*/ 44 | if (typeof data === 'string') { 45 | data = data.replace(PROTECTION_PREFIX, ''); 46 | try { 47 | data = JSON.parse(data); 48 | } catch (e) { /* Ignore */ } 49 | } 50 | return data; 51 | }], 52 | 53 | headers: { 54 | common: { 55 | 'Accept': 'application/json, text/plain, */*' 56 | }, 57 | patch: utils.merge(DEFAULT_CONTENT_TYPE), 58 | post: utils.merge(DEFAULT_CONTENT_TYPE), 59 | put: utils.merge(DEFAULT_CONTENT_TYPE) 60 | }, 61 | 62 | timeout: 0, 63 | 64 | xsrfCookieName: 'XSRF-TOKEN', 65 | xsrfHeaderName: 'X-XSRF-TOKEN', 66 | 67 | maxContentLength: -1, 68 | 69 | validateStatus: function validateStatus(status) { 70 | return status >= 200 && status < 300; 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /App/Redux/CreateStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux' 2 | import { autoRehydrate } from 'redux-persist' 3 | import createLogger from 'redux-logger' 4 | import Config from '../Config/DebugSettings' 5 | import createSagaMiddleware from 'redux-saga' 6 | import R from 'ramda' 7 | import RehydrationServices from '../Services/RehydrationServices' 8 | import ReduxPersist from '../Config/ReduxPersist' 9 | // 10 | import thunkMiddleware from 'redux-thunk' 11 | 12 | // creates the store 13 | export default (rootReducer, rootSaga) => { 14 | /* ------------- Redux Configuration ------------- */ 15 | 16 | const middleware = [] 17 | const enhancers = [] 18 | 19 | middleware.push(thunkMiddleware) 20 | 21 | /* ------------- Saga Middleware ------------- */ 22 | 23 | // const sagaMiddleware = createSagaMiddleware() 24 | // middleware.push(sagaMiddleware) 25 | 26 | /* ------------- Logger Middleware ------------- */ 27 | 28 | const SAGA_LOGGING_BLACKLIST = ['EFFECT_TRIGGERED', 'EFFECT_RESOLVED', 'EFFECT_REJECTED', 'persist/REHYDRATE'] 29 | if (__DEV__) { 30 | // the logger master switch 31 | const USE_LOGGING = Config.reduxLogging 32 | // silence these saga-based messages 33 | // create the logger 34 | const logger = createLogger({ 35 | predicate: (getState, { type }) => USE_LOGGING && R.not(R.contains(type, SAGA_LOGGING_BLACKLIST)) 36 | }) 37 | middleware.push(logger) 38 | } 39 | 40 | /* ------------- Assemble Middleware ------------- */ 41 | 42 | enhancers.push(applyMiddleware(...middleware)) 43 | 44 | /* ------------- AutoRehydrate Enhancer ------------- */ 45 | 46 | // add the autoRehydrate enhancer 47 | if (ReduxPersist.active) { 48 | enhancers.push(autoRehydrate()) 49 | } 50 | 51 | // in dev mode, we'll create the store through Reactotron 52 | const createAppropriateStore = __DEV__ ? console.tron.createStore : createStore 53 | const store = createAppropriateStore(rootReducer, compose(...enhancers)) 54 | 55 | // configure persistStore and check reducer version number 56 | if (ReduxPersist.active) { 57 | RehydrationServices.updateReducers(store) 58 | } 59 | 60 | // kick off root saga 61 | // sagaMiddleware.run(rootSaga) 62 | 63 | return store 64 | } 65 | -------------------------------------------------------------------------------- /App/Config/ReactotronConfig.js: -------------------------------------------------------------------------------- 1 | import { StartupTypes } from '../Redux/StartupRedux' 2 | import Immutable from 'seamless-immutable' 3 | const Reactotron = require('reactotron-react-native').default 4 | const errorPlugin = require('reactotron-react-native').trackGlobalErrors 5 | const apisaucePlugin = require('reactotron-apisauce') 6 | const { reactotronRedux } = require('reactotron-redux') 7 | 8 | if (__DEV__) { 9 | Reactotron 10 | .configure({ 11 | // host: '10.0.3.2' // default is localhost (on android don't forget to `adb reverse tcp:9090 tcp:9090`) 12 | name: 'Ignite App' // would you like to see your app's name? 13 | }) 14 | 15 | // forward all errors to Reactotron 16 | .use(errorPlugin({ 17 | // ignore all error frames from react-native (for example) 18 | veto: (frame) => 19 | frame.fileName.indexOf('/node_modules/react-native/') >= 0 20 | })) 21 | 22 | // register apisauce so we can install a monitor later 23 | .use(apisaucePlugin()) 24 | 25 | // setup the redux integration with Reactotron 26 | .use(reactotronRedux({ 27 | // you can flag some of your actions as important by returning true here 28 | isActionImportant: action => action.type === StartupTypes.STARTUP, 29 | 30 | // you can flag to exclude certain types too... especially the chatty ones 31 | // except: ['EFFECT_TRIGGERED', 'EFFECT_RESOLVED', 'EFFECT_REJECTED', 'persist/REHYDRATE'], 32 | 33 | // Fires when Reactotron uploads a new copy of the state tree. Since our reducers are 34 | // immutable with `seamless-immutable`, we ensure we convert to that format. 35 | onRestore: state => Immutable(state) 36 | })) 37 | 38 | // let's connect! 39 | .connect() 40 | 41 | // Let's clear Reactotron on every time we load the app 42 | Reactotron.clear() 43 | 44 | // Totally hacky, but this allows you to not both importing reactotron-react-native 45 | // on every file. This is just DEV mode, so no big deal. 46 | console.tron = Reactotron 47 | } else { 48 | // a mock version should you decide to leave console.tron in your codebase 49 | console.tron = { 50 | log: () => false, 51 | warn: () => false, 52 | error: () => false, 53 | display: () => false, 54 | image: () => false 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /App/Lib/axios/lib/core/dispatchRequest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('./../utils'); 4 | var transformData = require('./transformData'); 5 | 6 | /** 7 | * Dispatch a request to the server using whichever adapter 8 | * is supported by the current environment. 9 | * 10 | * @param {object} config The config that is to be used for the request 11 | * @returns {Promise} The Promise to be fulfilled 12 | */ 13 | module.exports = function dispatchRequest(config) { 14 | // Ensure headers exist 15 | config.headers = config.headers || {}; 16 | 17 | // Transform request data 18 | config.data = transformData( 19 | config.data, 20 | config.headers, 21 | config.transformRequest 22 | ); 23 | 24 | // Flatten headers 25 | config.headers = utils.merge( 26 | config.headers.common || {}, 27 | config.headers[config.method] || {}, 28 | config.headers || {} 29 | ); 30 | 31 | utils.forEach( 32 | ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], 33 | function cleanHeaderConfig(method) { 34 | delete config.headers[method]; 35 | } 36 | ); 37 | 38 | var adapter; 39 | 40 | if (typeof config.adapter === 'function') { 41 | // For custom adapter support 42 | adapter = config.adapter; 43 | } else if (typeof XMLHttpRequest !== 'undefined') { 44 | // For browsers use XHR adapter 45 | adapter = require('../adapters/xhr'); 46 | } else if (typeof process !== 'undefined') { 47 | // For node use HTTP adapter 48 | adapter = require('../adapters/http'); 49 | } 50 | 51 | return Promise.resolve(config) 52 | // Wrap synchronous adapter errors and pass configuration 53 | .then(adapter) 54 | .then(function onFulfilled(response) { 55 | // Transform response data 56 | response.data = transformData( 57 | response.data, 58 | response.headers, 59 | config.transformResponse 60 | ); 61 | 62 | return response; 63 | }, function onRejected(error) { 64 | // Transform response data 65 | if (error && error.response) { 66 | error.response.data = transformData( 67 | error.response.data, 68 | error.response.headers, 69 | config.transformResponse 70 | ); 71 | } 72 | 73 | return Promise.reject(error); 74 | }); 75 | }; 76 | -------------------------------------------------------------------------------- /ios/appTests/appTests.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 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface appTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation appTests 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 | -------------------------------------------------------------------------------- /App/Containers/DrawerContent.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React, {Component} from 'react' 4 | import {ScrollView, Image, BackAndroid} from 'react-native' 5 | import styles from './Styles/DrawerContentStyle' 6 | import {Images} from '../Themes' 7 | import DrawerButton from '../Components/DrawerButton' 8 | import {Actions as NavigationActions} from 'react-native-router-flux' 9 | 10 | class DrawerContent extends Component { 11 | 12 | componentDidMount() { 13 | // BackAndroid.addEventListener('hardwareBackPress', () => { 14 | // if (this.context.drawer.props.open) { 15 | // this.toggleDrawer() 16 | // return true 17 | // } 18 | // return false 19 | // }) 20 | setTimeout(() => { 21 | console.log('setTimeout', this.context.drawer.props) 22 | if (this.context.drawer.props.open) { 23 | this.toggleDrawer() 24 | return true 25 | } 26 | }, 5000) 27 | } 28 | 29 | toggleDrawer() { 30 | this.context.drawer.toggle() 31 | } 32 | 33 | handlePressComponents = () => { 34 | this.toggleDrawer() 35 | NavigationActions.componentExamples() 36 | } 37 | 38 | handlePressUsage = () => { 39 | this.toggleDrawer() 40 | NavigationActions.usageExamples() 41 | } 42 | 43 | handlePressAPI = () => { 44 | this.toggleDrawer() 45 | NavigationActions.apiTesting() 46 | } 47 | 48 | handlePressTheme = () => { 49 | this.toggleDrawer() 50 | NavigationActions.theme() 51 | } 52 | 53 | handlePressDevice = () => { 54 | this.toggleDrawer() 55 | NavigationActions.deviceInfo() 56 | } 57 | 58 | handleLogin = () => { 59 | this.toggleDrawer() 60 | NavigationActions.login() 61 | } 62 | 63 | render() { 64 | return ( 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | ) 75 | } 76 | 77 | } 78 | 79 | DrawerContent.contextTypes = { 80 | drawer: React.PropTypes.object 81 | } 82 | 83 | export default DrawerContent 84 | -------------------------------------------------------------------------------- /App/Components/Row.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | View, 4 | Text, 5 | Image, 6 | TouchableOpacity 7 | } from 'react-native' 8 | import Styles from './Styles/RowStyle' 9 | import {Images, Metrics, Colors} from '../Themes' 10 | 11 | const data = { 12 | onPress: null, 13 | style: {}, 14 | subs: [ 15 | { 16 | type: 'image' 17 | }, 18 | { 19 | onPress: null, // func / null 20 | style: {}, 21 | subs: [ 22 | { 23 | style: {}, 24 | wrapperStyle: {}, 25 | type: 'text', 26 | text: '123' 27 | }, 28 | { 29 | style: {}, 30 | type: 'text', 31 | text: '456' 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | 38 | export default class Row extends React.Component { 39 | 40 | static key = 1 41 | 42 | renderComponent(sub) { 43 | const {type, style = {}} = sub 44 | 45 | switch (type) { 46 | case 'text': 47 | return {sub.text} 48 | break 49 | case 'image': 50 | return 51 | break 52 | } 53 | } 54 | 55 | renderSubs(subs, isWrapper = true) { 56 | const views = [] 57 | subs.forEach((sub) => { 58 | const {wrapperStyle = {}, onPress} = sub 59 | const Wrapper = onPress ? TouchableOpacity : View 60 | const rowStyle = isWrapper ? Styles.rowDetail : Styles.flex 61 | Row.key++ 62 | // console.log(sub, isWrapper) 63 | if (sub.subs) { 64 | views.push( 65 | 66 | { this.renderSubs(sub.subs, false) } 67 | 68 | ) 69 | } else { 70 | views.push( 71 | 72 | { this.renderComponent(sub) } 73 | 74 | ) 75 | } 76 | }) 77 | 78 | return views 79 | } 80 | 81 | render() { 82 | const { 83 | onPress = () => { 84 | }, 85 | wrapperStyle = {}, 86 | subs = null, 87 | } = this.props.data || {} 88 | 89 | if (!subs) return null 90 | 91 | const subView = this.renderSubs(subs) 92 | 93 | return ( 94 | 95 | {subView} 96 | 97 | ) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /App/Lib/WebIMConfig.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | /** 4 | * git do not control webim.config.js 5 | * everyone should copy webim.config.js.demo to webim.config.js 6 | * and have their own configs. 7 | * In this way , others won't be influenced by this config while git pull. 8 | * 9 | */ 10 | 11 | // for react native 12 | let location = { 13 | protocol: 'https' 14 | } 15 | 16 | let config = { 17 | /* 18 | * XMPP server 19 | */ 20 | xmppURL: 'im-api.easemob.com', 21 | // xmppURL: '172.17.2.139:5280', 22 | /* 23 | * Backend REST API URL 24 | */ 25 | // apiURL: (location.protocol === 'https:' ? 'https:' : 'http:') + '//a1.easemob.com', 26 | // ios must be https!!! by lwz 27 | apiURL: 'https://a1.easemob.com', 28 | // apiURL: (location.protocol === 'https:' ? 'https:' : 'http:') + '//172.17.3.155:8080', 29 | /* 30 | * Application AppKey 31 | */ 32 | appkey: 'easemob-demo#chatdemoui', 33 | /* 34 | * Whether to use HTTPS 35 | * @parameter {Boolean} true or false 36 | */ 37 | https: true, 38 | /* 39 | * isMultiLoginSessions 40 | * true: A visitor can sign in to multiple webpages and receive messages at all the webpages. 41 | * false: A visitor can sign in to only one webpage and receive messages at the webpage. 42 | */ 43 | isMultiLoginSessions: false, 44 | /** 45 | * Whether to use window.doQuery() 46 | * @parameter {Boolean} true or false 47 | */ 48 | isWindowSDK: false, 49 | /** 50 | * isSandBox=true: xmppURL: 'im-api.sandbox.easemob.com', apiURL: '//a1.sdb.easemob.com', 51 | * isSandBox=false: xmppURL: 'im-api.easemob.com', apiURL: '//a1.easemob.com', 52 | * @parameter {Boolean} true or false 53 | */ 54 | isSandBox: false, 55 | /** 56 | * Whether to console.log in strophe.log() 57 | * @parameter {Boolean} true or false 58 | */ 59 | isDebug: true, 60 | /** 61 | * will auto connect the xmpp server autoReconnectNumMax times in background when client is offline. 62 | * won't auto connect if autoReconnectNumMax=0. 63 | */ 64 | autoReconnectNumMax: 2, 65 | /** 66 | * the interval secons between each atuo reconnectting. 67 | * works only if autoReconnectMaxNum >= 2. 68 | */ 69 | autoReconnectInterval: 2, 70 | /** 71 | * webrtc supports WebKit and https only 72 | */ 73 | isWebRTC: /WebKit/.test(navigator.userAgent) && /^https\:$/.test(window.location.protocol), 74 | /* 75 | * Set to auto sign-in 76 | */ 77 | isAutoLogin: true 78 | } 79 | 80 | export default config 81 | -------------------------------------------------------------------------------- /App/Services/Api.js: -------------------------------------------------------------------------------- 1 | // a library to wrap and simplify api calls 2 | import apisauce from '../Lib/apisauce' 3 | 4 | // our "constructor" 5 | const create = (baseURL = '') => { 6 | // ------ 7 | // STEP 1 8 | // ------ 9 | // 10 | // Create and configure an apisauce-based api object. 11 | // 12 | const api = apisauce.create({ 13 | // base URL is read from the "constructor" 14 | baseURL, 15 | // here are some default headers 16 | headers: { 17 | 'Cache-Control': 'no-cache', 18 | 'Accept': 'application/json', 19 | 'Content-Type': 'application/json' 20 | }, 21 | // 10 second timeout... 22 | timeout: 10000 23 | }) 24 | 25 | // Force OpenWeather API Key on all requests 26 | // api.addRequestTransform((request) => { 27 | // request.params['APPID'] = '0e44183e8d1018fc92eb3307d885379c' 28 | // }) 29 | 30 | // Wrap api's addMonitor to allow the calling code to attach 31 | // additional monitors in the future. But only in __DEV__ and only 32 | // if we've attached Reactotron to console (it isn't during unit tests). 33 | if (__DEV__ && console.tron) { 34 | console.tron.log('Hello, I\'m an example of how to log via Reactotron.') 35 | api.addMonitor(console.tron.apisauce) 36 | } 37 | 38 | // ------ 39 | // STEP 2 40 | // ------ 41 | // 42 | // Define some functions that call the api. The goal is to provide 43 | // a thin wrapper of the api layer providing nicer feeling functions 44 | // rather than "get", "post" and friends. 45 | // 46 | // I generally don't like wrapping the output at this level because 47 | // sometimes specific actions need to be take on `403` or `401`, etc. 48 | // 49 | // Since we can't hide from that, we embrace it by getting out of the 50 | // way at this level. 51 | // 52 | const register = (options) => api.post('/users', options) 53 | 54 | // ------ 55 | // STEP 3 56 | // ------ 57 | // 58 | // Return back a collection of functions that we would consider our 59 | // interface. Most of the time it'll be just the list of all the 60 | // methods in step 2. 61 | // 62 | // Notice we're not returning back the `api` created in step 1? That's 63 | // because it is scoped privately. This is one way to create truly 64 | // private scoped goodies in JavaScript. 65 | // 66 | return { 67 | // a list of the API functions from step 2 68 | register 69 | } 70 | } 71 | 72 | // let's return back our create method as the default. 73 | export default { 74 | create 75 | } 76 | --------------------------------------------------------------------------------