├── .watchmanconfig ├── .gitattributes ├── .babelrc ├── .eslintignore ├── app.json ├── libs ├── react-native-android-bottom-sheet │ ├── README.md │ ├── index.android.js │ ├── src │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ └── terrysahaidak │ │ │ └── bottomsheet │ │ │ ├── AndroidBottomSheetPackage.java │ │ │ └── AndroidBottomSheet.java │ ├── package.json │ ├── build.gradle │ └── index.ios.js └── react-native-gitter-faye │ ├── index.android.js │ ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── terrysahaidak │ │ └── faye │ │ └── FayeGitterPackage.java │ ├── package.json │ ├── index.ios.js │ ├── README.md │ └── build.gradle ├── ios ├── Pods │ ├── Headers │ │ ├── Public │ │ │ ├── SocketRocket │ │ │ │ ├── SRWebSocket.h │ │ │ │ └── SocketRocket.h │ │ │ └── MZFayeClient │ │ │ │ ├── MZFayeClient.h │ │ │ │ └── MZFayeMessage.h │ │ └── Private │ │ │ ├── MZFayeClient │ │ │ ├── MZFayeClient.h │ │ │ └── MZFayeMessage.h │ │ │ └── SocketRocket │ │ │ ├── SRWebSocket.h │ │ │ └── SocketRocket.h │ ├── Target Support Files │ │ ├── MZFayeClient │ │ │ ├── MZFayeClient-dummy.m │ │ │ ├── MZFayeClient-prefix.pch │ │ │ └── MZFayeClient.xcconfig │ │ ├── SocketRocket │ │ │ ├── SocketRocket-dummy.m │ │ │ ├── SocketRocket-prefix.pch │ │ │ └── SocketRocket.xcconfig │ │ └── Pods-GitterMobile │ │ │ ├── Pods-GitterMobile-dummy.m │ │ │ ├── Pods-GitterMobile.debug.xcconfig │ │ │ ├── Pods-GitterMobile.release.xcconfig │ │ │ └── Pods-GitterMobile-acknowledgements.markdown │ ├── SocketRocket │ │ ├── LICENSE │ │ └── SocketRocket │ │ │ └── SocketRocket.h │ ├── Manifest.lock │ ├── Local Podspecs │ │ ├── MZFayeClient.podspec.json │ │ └── RNVectorIcons.podspec.json │ └── MZFayeClient │ │ ├── LICENSE │ │ └── MZFayeClient │ │ ├── MZFayeMessage.h │ │ └── MZFayeMessage.m ├── gittermobile │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-57x57@1x.png │ │ │ ├── Icon-App-60x60@1x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-76x76@3x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ ├── AppDelegate.h │ ├── main.m │ ├── AppDelegate.m │ └── Info.plist ├── Podfile ├── gittermobile.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── gittermobile.xcscmblueprint ├── GitterMobile │ └── FayeManager.h ├── Podfile.lock ├── gittermobileTests │ ├── Info.plist │ └── gittermobileTests.m ├── gittermobile-tvOSTests │ └── Info.plist └── gittermobile-tvOS │ └── Info.plist ├── screenshots ├── home.png ├── room.png ├── drawer.png ├── message.png ├── user_screen.png ├── search_rooms.png └── room_info_screen.png ├── index.ios.js ├── index.android.js ├── app ├── images │ └── gitter-background.jpg ├── components │ ├── Link │ │ ├── styles.js │ │ └── index.js │ ├── ScrollToTop │ │ ├── styles.js │ │ └── index.js │ ├── Button │ │ ├── styles.js │ │ ├── index.ios.js │ │ └── index.android.js │ ├── LoadingOverlay │ │ ├── styles.js │ │ └── index.js │ ├── FailedToLoad │ │ ├── styles.js │ │ └── index.js │ ├── Heading │ │ └── index.js │ ├── Divider │ │ └── index.js │ ├── Avatar │ │ └── index.js │ ├── ParsedText │ │ ├── styles.js │ │ └── index.js │ ├── CustomSearch │ │ ├── styles.js │ │ └── index.js │ ├── LoadingMoreSnack │ │ ├── styles.js │ │ └── index.js │ ├── UnreadBadge │ │ ├── styles.js │ │ └── index.js │ ├── Loading │ │ └── index.js │ ├── Emoji │ │ └── index.js │ └── Toolbar │ │ └── styles.js ├── utils │ ├── channelNameAndOwner.js │ ├── links.js │ ├── storage.js │ ├── normalize.js │ ├── hexToRgb.js │ ├── iconsMap.js │ └── createMessage.js ├── screens │ ├── RoomUsers │ │ ├── RoomUsersList │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── RoomUsersSearchResult │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── styles.js │ │ └── RoomUserItem │ │ │ ├── styles.js │ │ │ └── index.js │ ├── RoomSettings │ │ ├── Section │ │ │ ├── styles.js │ │ │ └── index.js │ │ └── styles.js │ ├── Drawer │ │ ├── styles.js │ │ ├── SearchField │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── ChannelListSection │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── ChannelListItem │ │ │ ├── styles.js │ │ │ └── index.js │ │ └── DrawerUserInfo │ │ │ ├── styles.js │ │ │ └── index.js │ ├── ImageLightbox │ │ ├── styles.js │ │ └── index.js │ ├── RoomInfo │ │ ├── styles.js │ │ ├── RoomInfo │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── Activity │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── RepoInfo │ │ │ └── styles.js │ │ ├── RoomUsers │ │ │ ├── styles.js │ │ │ └── index.js │ │ └── UserInfo │ │ │ └── index.js │ ├── Search │ │ ├── SearchRoomsTab │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── styles.js │ │ ├── SearchUserItem │ │ │ └── index.js │ │ ├── SearchUsersTab │ │ │ └── index.js │ │ └── SearchRoomItem │ │ │ └── index.js │ ├── Room │ │ ├── MessagesList │ │ │ └── styles.js │ │ ├── StatusMessage │ │ │ ├── renderEmoji.js │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── styles.js │ │ ├── HistoryBegin │ │ │ ├── index.js │ │ │ └── styles.js │ │ ├── JoinRoomField │ │ │ ├── index.js │ │ │ └── styles.js │ │ ├── Message │ │ │ └── styles.js │ │ └── SendMessageField │ │ │ └── styles.js │ ├── Settings │ │ ├── Group │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── TextItem │ │ │ ├── styles.js │ │ │ └── index.js │ │ └── styles.js │ ├── RoomUserAdd │ │ ├── SearchResult │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── styles.js │ │ └── RoomUserItem │ │ │ ├── styles.js │ │ │ └── index.js │ ├── Message │ │ ├── styles.js │ │ ├── ReadBy │ │ │ ├── styles.js │ │ │ └── index.js │ │ └── Message │ │ │ ├── styles.js │ │ │ └── index.js │ ├── Launch │ │ ├── styles.js │ │ └── index.js │ ├── Home │ │ ├── HomeRoomItem │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── styles.js │ │ └── HomeRoomItemMy │ │ │ ├── styles.js │ │ │ └── index.js │ ├── LoginByWebView │ │ ├── styles.js │ │ └── index.js │ ├── SearchMessages │ │ ├── styles.js │ │ └── MessagesList │ │ │ └── index.js │ ├── User │ │ ├── styles.js │ │ ├── UserInfo │ │ │ └── styles.js │ │ └── UserTop │ │ │ ├── styles.js │ │ │ └── index.js │ ├── NoInternet │ │ ├── styles.js │ │ └── index.js │ ├── Login │ │ ├── styles.js │ │ └── index.js │ ├── LoginByToken │ │ └── styles.js │ └── index.js ├── styles │ └── common │ │ ├── BackgroundImage.js │ │ └── navigationStyles.js ├── index.js ├── api │ └── github.js ├── modules │ ├── readBy.js │ ├── activity.js │ ├── settings.js │ ├── index.js │ ├── viewer.js │ ├── ui.js │ ├── roomInfo.js │ └── navigation.js ├── configureStore.js └── constants.js ├── android ├── app │ ├── 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 │ │ │ └── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── assets │ │ │ └── fonts │ │ │ │ ├── Entypo.ttf │ │ │ │ ├── Zocial.ttf │ │ │ │ ├── EvilIcons.ttf │ │ │ │ ├── Ionicons.ttf │ │ │ │ ├── Octicons.ttf │ │ │ │ ├── FontAwesome.ttf │ │ │ │ ├── Foundation.ttf │ │ │ │ ├── MaterialIcons.ttf │ │ │ │ ├── SimpleLineIcons.ttf │ │ │ │ └── MaterialCommunityIcons.ttf │ │ │ ├── java │ │ │ └── com │ │ │ │ └── gittermobile │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── AndroidManifest.xml │ └── BUCK ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── keystores │ ├── debug.keystore.properties │ └── BUCK ├── build.gradle ├── gradle.properties └── settings.gradle ├── .buckconfig ├── .editorconfig ├── __tests__ ├── index.ios.js └── index.android.js ├── .eslintrc ├── .gitignore ├── .flowconfig ├── LICENSE └── package.json /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bundle/ 3 | bundle.js 4 | vendor.js 5 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GitterMobile", 3 | "displayName": "GitterMobile" 4 | } -------------------------------------------------------------------------------- /libs/react-native-android-bottom-sheet/README.md: -------------------------------------------------------------------------------- 1 | ## react-native-android-bottom-sheet 2 | -------------------------------------------------------------------------------- /ios/Pods/Headers/Public/SocketRocket/SRWebSocket.h: -------------------------------------------------------------------------------- 1 | ../../../SocketRocket/SocketRocket/SRWebSocket.h -------------------------------------------------------------------------------- /screenshots/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/screenshots/home.png -------------------------------------------------------------------------------- /screenshots/room.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/screenshots/room.png -------------------------------------------------------------------------------- /index.ios.js: -------------------------------------------------------------------------------- 1 | import GitterMobile from './app/index.js' 2 | global.CURRENT_VERSION = 'v0.6.0-beta-2' 3 | -------------------------------------------------------------------------------- /ios/Pods/Headers/Private/MZFayeClient/MZFayeClient.h: -------------------------------------------------------------------------------- 1 | ../../../MZFayeClient/MZFayeClient/MZFayeClient.h -------------------------------------------------------------------------------- /ios/Pods/Headers/Private/MZFayeClient/MZFayeMessage.h: -------------------------------------------------------------------------------- 1 | ../../../MZFayeClient/MZFayeClient/MZFayeMessage.h -------------------------------------------------------------------------------- /ios/Pods/Headers/Private/SocketRocket/SRWebSocket.h: -------------------------------------------------------------------------------- 1 | ../../../SocketRocket/SocketRocket/SRWebSocket.h -------------------------------------------------------------------------------- /ios/Pods/Headers/Private/SocketRocket/SocketRocket.h: -------------------------------------------------------------------------------- 1 | ../../../SocketRocket/SocketRocket/SocketRocket.h -------------------------------------------------------------------------------- /ios/Pods/Headers/Public/MZFayeClient/MZFayeClient.h: -------------------------------------------------------------------------------- 1 | ../../../MZFayeClient/MZFayeClient/MZFayeClient.h -------------------------------------------------------------------------------- /ios/Pods/Headers/Public/MZFayeClient/MZFayeMessage.h: -------------------------------------------------------------------------------- 1 | ../../../MZFayeClient/MZFayeClient/MZFayeMessage.h -------------------------------------------------------------------------------- /ios/Pods/Headers/Public/SocketRocket/SocketRocket.h: -------------------------------------------------------------------------------- 1 | ../../../SocketRocket/SocketRocket/SocketRocket.h -------------------------------------------------------------------------------- /screenshots/drawer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/screenshots/drawer.png -------------------------------------------------------------------------------- /index.android.js: -------------------------------------------------------------------------------- 1 | import GitterMobile from './app/index.js' 2 | global.CURRENT_VERSION = 'v0.6.0-beta-2' 3 | -------------------------------------------------------------------------------- /screenshots/message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/screenshots/message.png -------------------------------------------------------------------------------- /screenshots/user_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/screenshots/user_screen.png -------------------------------------------------------------------------------- /screenshots/search_rooms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/screenshots/search_rooms.png -------------------------------------------------------------------------------- /app/images/gitter-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/app/images/gitter-background.jpg -------------------------------------------------------------------------------- /screenshots/room_info_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/screenshots/room_info_screen.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | GitterMobile 3 | 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /libs/react-native-gitter-faye/index.android.js: -------------------------------------------------------------------------------- 1 | import { NativeModules } from 'react-native' 2 | module.exports = NativeModules.FayeGitter; 3 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/Entypo.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/Zocial.ttf -------------------------------------------------------------------------------- /.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/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/Ionicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/Octicons.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/Foundation.ttf -------------------------------------------------------------------------------- /libs/react-native-android-bottom-sheet/index.android.js: -------------------------------------------------------------------------------- 1 | import { NativeModules } from 'react-native' 2 | export default NativeModules.AndroidBottomSheet 3 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/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/apiko-dev/GitterMobile/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/components/Link/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | 5 | }) 6 | 7 | export default styles 8 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/SimpleLineIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/SimpleLineIcons.ttf -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/res/mipmap-xxxhdpi/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 | -------------------------------------------------------------------------------- /app/utils/channelNameAndOwner.js: -------------------------------------------------------------------------------- 1 | export default function channelNameAndOwner(str) { 2 | const [owner, name] = str.split(/\/(.*)/) 3 | return {owner, name} 4 | } 5 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@1x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/MZFayeClient/MZFayeClient-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_MZFayeClient : NSObject 3 | @end 4 | @implementation PodsDummy_MZFayeClient 5 | @end 6 | -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/SocketRocket/SocketRocket-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SocketRocket : NSObject 3 | @end 4 | @implementation PodsDummy_SocketRocket 5 | @end 6 | -------------------------------------------------------------------------------- /ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apiko-dev/GitterMobile/HEAD/ios/gittermobile/Images.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /app/screens/RoomUsers/RoomUsersList/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1 6 | } 7 | }) 8 | 9 | export default styles 10 | -------------------------------------------------------------------------------- /app/screens/RoomSettings/Section/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | // padding: 16 6 | }, 7 | }) 8 | 9 | export default styles 10 | -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/Pods-GitterMobile/Pods-GitterMobile-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_GitterMobile : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_GitterMobile 5 | @end 6 | -------------------------------------------------------------------------------- /libs/react-native-gitter-faye/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/screens/Drawer/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | backgroundColor: 'white' 7 | } 8 | }) 9 | 10 | export default styles 11 | -------------------------------------------------------------------------------- /app/screens/ImageLightbox/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | backgroundColor: '#000' 7 | } 8 | }) 9 | 10 | export default styles 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /libs/react-native-android-bottom-sheet/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/styles/common/BackgroundImage.js: -------------------------------------------------------------------------------- 1 | import {Dimensions} from 'react-native' 2 | 3 | const {width, height} = Dimensions.get('window') 4 | 5 | const styles = { 6 | flex: 1, 7 | width, 8 | height 9 | } 10 | 11 | export default styles 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 6 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | import {Provider} from 'react-redux' 2 | import configureStore from './configureStore' 3 | 4 | import Application from './screens' 5 | 6 | const store = configureStore() 7 | export const rootNavigator = new Application(store, Provider) 8 | 9 | rootNavigator.run() 10 | -------------------------------------------------------------------------------- /app/utils/links.js: -------------------------------------------------------------------------------- 1 | export const createGhAvatarLink = (name, size = 40) => { 2 | return `https://avatars.githubusercontent.com/${name}?v=3&size=${size}` 3 | } 4 | 5 | export function quoteLink(time, url, id) { 6 | return `:point_up: [${time}](https://gitter.im${url}?at=${id})` 7 | } 8 | -------------------------------------------------------------------------------- /app/api/github.js: -------------------------------------------------------------------------------- 1 | const BASE_API_URL = 'https://api.github.com' 2 | 3 | export function checkNewReleases() { 4 | return request('repos/terrysahaidak/GitterMobile/releases') 5 | } 6 | 7 | function request(endpoint) { 8 | return fetch(`${BASE_API_URL}/${endpoint}`).then(raw => raw.json()) 9 | } 10 | -------------------------------------------------------------------------------- /app/screens/Drawer/SearchField/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | marginVertical: 12, 6 | marginHorizontal: 16 7 | }, 8 | text: { 9 | color: '#E0E0E0' 10 | } 11 | }) 12 | 13 | export default styles 14 | -------------------------------------------------------------------------------- /app/components/ScrollToTop/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | // flex: 1, 6 | position: 'absolute', 7 | alignItems: 'center', 8 | justifyContent: 'center' 9 | } 10 | }) 11 | 12 | export default styles 13 | -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/MZFayeClient/MZFayeClient-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/SocketRocket/SocketRocket-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /libs/react-native-gitter-faye/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-faye", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.android.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /app/screens/RoomInfo/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | backgroundColor: 'white' 7 | }, 8 | tabs: { 9 | 10 | }, 11 | tabsContainer: { 12 | flex: 1 13 | } 14 | }) 15 | 16 | export default styles 17 | -------------------------------------------------------------------------------- /app/screens/Search/SearchRoomsTab/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1 6 | }, 7 | tabText: { 8 | textAlign: 'center', 9 | fontSize: 24, 10 | marginTop: 50 11 | } 12 | }) 13 | 14 | export default styles 15 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '8.0' 3 | # Uncomment this line if you're using Swift 4 | # use_frameworks! 5 | 6 | target 'GitterMobile' do 7 | pod 'MZFayeClient', :git => 'https://github.com/m1entus/MZFayeClient.git', :commit => '6a88a1' 8 | end 9 | -------------------------------------------------------------------------------- /app/screens/Room/MessagesList/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | rootStyle: { 5 | flex: 1 6 | }, 7 | verticallyInverted: { 8 | flex: 1, 9 | transform: [ 10 | { scaleY: -1 } 11 | ] 12 | } 13 | }) 14 | 15 | export default styles 16 | -------------------------------------------------------------------------------- /ios/gittermobile.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/screens/Room/StatusMessage/renderEmoji.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Emoji from '../../../components/Emoji' 3 | 4 | const renderEmoji = (matchingString, matches) => { 5 | const name = matches[0].replace(/:/, '') 6 | return ( 7 | 8 | ) 9 | } 10 | 11 | export default renderEmoji 12 | -------------------------------------------------------------------------------- /libs/react-native-android-bottom-sheet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-android-bottom-sheet", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.android.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC" 11 | } 12 | -------------------------------------------------------------------------------- /app/components/Button/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | button: { 5 | height: 35, 6 | borderRadius: 2, 7 | flexDirection: 'row', 8 | justifyContent: 'center', 9 | alignItems: 'center', 10 | elevation: 4 11 | } 12 | }) 13 | 14 | export default styles 15 | -------------------------------------------------------------------------------- /app/utils/storage.js: -------------------------------------------------------------------------------- 1 | import {AsyncStorage} from 'react-native' 2 | 3 | export function getItem(key) { 4 | return AsyncStorage.getItem(key) 5 | } 6 | 7 | export function setItem(key, value) { 8 | return AsyncStorage.setItem(key, value) 9 | } 10 | 11 | export function removeItem(key) { 12 | return AsyncStorage.removeItem(key) 13 | } 14 | -------------------------------------------------------------------------------- /__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 | -------------------------------------------------------------------------------- /__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/screens/Settings/Group/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | // flex: 1, 6 | backgroundColor: 'white', 7 | elevation: 4, 8 | marginBottom: 4 9 | }, 10 | headingContainer: { 11 | paddingVertical: 8 12 | }, 13 | items: { 14 | 15 | } 16 | }) 17 | 18 | export default styles 19 | -------------------------------------------------------------------------------- /app/utils/normalize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns normalized data - ids and entities 3 | * @param response - json response 4 | */ 5 | export default function normalize(response) { 6 | const result = { 7 | ids: [], 8 | entities: {} 9 | } 10 | 11 | response.map(item => { 12 | result.ids.push(item.id) 13 | result.entities[[item.id]] = item 14 | }) 15 | 16 | return result 17 | } 18 | -------------------------------------------------------------------------------- /ios/GitterMobile/FayeManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // FayeManager.h 3 | // gittermobile 4 | // 5 | // Created by Roman Temchenko on 5/4/16. 6 | // Copyright © 2016 Facebook. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | @interface FayeManager : RCTEventEmitter 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /app/screens/RoomUserAdd/SearchResult/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1 6 | }, 7 | loading: { 8 | height: 150 9 | }, 10 | noResultContainer: { 11 | paddingTop: 50 12 | }, 13 | noResult: { 14 | textAlign: 'center', 15 | fontSize: 24 16 | } 17 | }) 18 | 19 | export default styles 20 | -------------------------------------------------------------------------------- /app/screens/RoomUsers/RoomUsersSearchResult/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1 6 | }, 7 | loading: { 8 | height: 150 9 | }, 10 | noResultContainer: { 11 | paddingTop: 50 12 | }, 13 | noResult: { 14 | textAlign: 'center', 15 | fontSize: 24 16 | } 17 | }) 18 | 19 | export default styles 20 | -------------------------------------------------------------------------------- /app/components/LoadingOverlay/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | loadingContainer: { 5 | flex: 1, 6 | position: 'absolute', 7 | bottom: 0, 8 | top: 0, 9 | left: 0, 10 | right: 0, 11 | backgroundColor: 'rgba(0,0,0,0.7)', 12 | justifyContent: 'center', 13 | alignItems: 'center' 14 | } 15 | }) 16 | 17 | export default styles 18 | -------------------------------------------------------------------------------- /app/screens/Room/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | flex: 1, 8 | backgroundColor: 'white' 9 | }, 10 | toolbar: { 11 | backgroundColor: colors.raspberry, 12 | height: 56, 13 | elevation: 4 14 | } 15 | }) 16 | 17 | export default styles 18 | -------------------------------------------------------------------------------- /libs/react-native-gitter-faye/index.ios.js: -------------------------------------------------------------------------------- 1 | import { NativeModules } from 'react-native' 2 | 3 | const noop = () => {} 4 | const trueNoop = Promise.resolve(true) 5 | 6 | const FayeGitter = { 7 | setAccessToken: noop, 8 | create: noop, 9 | logger: noop, 10 | connect: trueNoop, 11 | checkConnectionStatus: trueNoop, 12 | subscribe: noop, 13 | unsubscribe: noop 14 | } 15 | 16 | export default NativeModules.FayeManager 17 | -------------------------------------------------------------------------------- /app/screens/Settings/TextItem/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | padding: 16, 7 | justifyContent: 'center' 8 | }, 9 | text: { 10 | fontSize: 18, 11 | fontWeight: 'bold', 12 | // color: 'black' 13 | }, 14 | button: { 15 | elevation: 0, 16 | height: 56 17 | } 18 | }) 19 | 20 | export default styles 21 | -------------------------------------------------------------------------------- /app/styles/common/navigationStyles.js: -------------------------------------------------------------------------------- 1 | import {THEMES} from '../../constants' 2 | const {colors} = THEMES.gitterDefault 3 | 4 | const navigationStyles = { 5 | navBarBackgroundColor: colors.raspberry, 6 | navBarButtonColor: 'white', 7 | navBarTextColor: 'white', 8 | topBarElevationShadowEnabled: true, 9 | statusBarColor: colors.darkRed, 10 | statusBarTextColorScheme: 'dark' 11 | } 12 | 13 | export default navigationStyles 14 | -------------------------------------------------------------------------------- /app/screens/RoomInfo/RoomInfo/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1 6 | }, 7 | header: { 8 | flexDirection: 'row', 9 | paddingHorizontal: 16, 10 | paddingVertical: 24 11 | }, 12 | headerTextContainer: { 13 | marginLeft: 16, 14 | flexDirection: 'column' 15 | }, 16 | name: { 17 | } 18 | }) 19 | 20 | export default styles 21 | -------------------------------------------------------------------------------- /app/screens/Message/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | flex: 1, 8 | backgroundColor: 'white' 9 | }, 10 | toolbar: { 11 | height: 56, 12 | backgroundColor: colors.raspberry, 13 | elevation: 4, 14 | marginBottom: 8 15 | }, 16 | }) 17 | 18 | export default styles 19 | -------------------------------------------------------------------------------- /app/screens/RoomUserAdd/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Platform} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | backgroundColor: 'rgba(0,0,0,0.2)', 7 | paddingTop: Platform.OS === 'ios' ? 24 : 0, 8 | }, 9 | bottomContainer: { 10 | flex: 1, 11 | margin: 8, 12 | borderRadius: 2, 13 | backgroundColor: 'white', 14 | elevation: 2 15 | } 16 | }) 17 | 18 | export default styles 19 | -------------------------------------------------------------------------------- /app/screens/Launch/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import backgroundImage from '../../styles/common/BackgroundImage' 3 | 4 | const styles = StyleSheet.create({ 5 | container: { 6 | ...backgroundImage, 7 | justifyContent: 'space-around', 8 | alignItems: 'center' 9 | }, 10 | logo: { 11 | fontSize: 40, 12 | color: 'white', 13 | backgroundColor: 'transparent' 14 | } 15 | }) 16 | 17 | 18 | export default styles 19 | -------------------------------------------------------------------------------- /app/screens/RoomUsers/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Platform} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | backgroundColor: 'rgba(0,0,0,0.2)', 7 | paddingTop: Platform.OS === 'ios' ? 24 : 0, 8 | 9 | }, 10 | bottomContainer: { 11 | flex: 1, 12 | borderRadius: 2, 13 | elevation: 2, 14 | backgroundColor: 'white', 15 | margin: 4 16 | } 17 | }) 18 | 19 | export default styles 20 | -------------------------------------------------------------------------------- /app/screens/Message/ReadBy/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | // flex: 1 6 | }, 7 | usersContainer: { 8 | paddingHorizontal: 16, 9 | paddingVertical: 4, 10 | alignItems: 'center', 11 | flexWrap: 'wrap', 12 | flexDirection: 'row' 13 | }, 14 | itemContainer: { 15 | marginRight: 6, 16 | marginBottom: 4 17 | } 18 | }) 19 | 20 | export default styles 21 | -------------------------------------------------------------------------------- /app/screens/RoomInfo/Activity/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | // flex: 1 6 | }, 7 | header: { 8 | paddingHorizontal: 16, 9 | paddingVertical: 24 10 | }, 11 | listContainer: { 12 | paddingHorizontal: 16 13 | }, 14 | itemContainer: { 15 | paddingVertical: 4 16 | }, 17 | nothing: { 18 | margin: 16 19 | } 20 | }) 21 | 22 | export default styles 23 | -------------------------------------------------------------------------------- /app/components/FailedToLoad/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | justifyContent: 'center', 7 | alignItems: 'center' 8 | }, 9 | heading: { 10 | fontSize: 18, 11 | marginBottom: 10 12 | }, 13 | button: { 14 | width: 100, 15 | height: 30, 16 | alignItems: 'center', 17 | justifyContent: 'center' 18 | } 19 | }) 20 | 21 | export default styles 22 | -------------------------------------------------------------------------------- /app/screens/RoomSettings/Section/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View} from 'react-native' 4 | import Heading from '../../../components/Heading' 5 | 6 | import s from './styles' 7 | 8 | const Section = ({title, children}) => ( 9 | 10 | 11 | 12 | {children} 13 | 14 | ) 15 | 16 | Section.propTypes = { 17 | 18 | } 19 | 20 | export default Section 21 | -------------------------------------------------------------------------------- /app/components/LoadingOverlay/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {View, Text} from 'react-native' 3 | import Loading from '../Loading' 4 | import s from './styles' 5 | 6 | const LoadingOverlay = ({text}) => ( 7 | 8 | 9 | 10 | 11 | 12 | ) 13 | 14 | LoadingOverlay.propTypes = { 15 | 16 | } 17 | 18 | export default LoadingOverlay 19 | -------------------------------------------------------------------------------- /app/screens/Settings/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | flex: 1, 8 | backgroundColor: '#f0eef0' 9 | }, 10 | scrollContainer: { 11 | flex: 1 12 | }, 13 | toolbar: { 14 | height: 56, 15 | backgroundColor: colors.raspberry, 16 | elevation: 4 17 | } 18 | }) 19 | 20 | export default styles 21 | -------------------------------------------------------------------------------- /app/screens/RoomUsers/RoomUserItem/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | button: { 5 | elevation: 0, 6 | flexDirection: 'row', 7 | height: 70, 8 | justifyContent: 'flex-start', 9 | paddingLeft: 18, 10 | paddingVertical: 16 11 | }, 12 | userInfo: { 13 | paddingLeft: 18 14 | }, 15 | displayName: { 16 | fontSize: 18, 17 | color: 'black' 18 | } 19 | }) 20 | 21 | export default styles 22 | -------------------------------------------------------------------------------- /libs/react-native-gitter-faye/README.md: -------------------------------------------------------------------------------- 1 | ## react-native-gitter-faye 2 | 3 | #### example 4 | ``` 5 | FayeGitter.setAccessToken('token') 6 | FayeGitter.create() 7 | 8 | FayeGitter.connect().then(() => { 9 | FayeGitter.subscribe('/api/v1/user/555e610f15522ed4b3e0c169/rooms') 10 | FayeGitter.logger() 11 | }) 12 | 13 | // events 14 | FayeGitter:onDisconnected 15 | FayeGitter:onFailedToCreate 16 | FayeGitter:Message 17 | FayeGitter:SubscribtionFailed 18 | FayeGitter:Subscribed 19 | FayeGitter:Unsubscribed 20 | FayeGitter:log 21 | ``` 22 | -------------------------------------------------------------------------------- /ios/gittermobile/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 | -------------------------------------------------------------------------------- /app/utils/hexToRgb.js: -------------------------------------------------------------------------------- 1 | export default function hexToRgb(hex) { 2 | // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") 3 | const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i 4 | const newHex = hex.replace(shorthandRegex, (m, r, g, b) => { 5 | return r + r + g + g + b + b 6 | }) 7 | 8 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(newHex) 9 | return result ? [ 10 | parseInt(result[1], 16), 11 | parseInt(result[2], 16), 12 | parseInt(result[3], 16) 13 | ].join() : null 14 | } 15 | -------------------------------------------------------------------------------- /app/screens/Drawer/ChannelListSection/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | }, 6 | heading: { 7 | marginBottom: 16 8 | }, 9 | sectionHeader: { 10 | flexDirection: 'row', 11 | alignItems: 'center', 12 | justifyContent: 'space-between', 13 | paddingRight: 16 14 | }, 15 | icon: { 16 | width: 16, 17 | height: 16, 18 | opacity: 0.6 19 | }, 20 | collapsButton: { 21 | width: 16, 22 | height: 16 23 | } 24 | }) 25 | 26 | export default styles 27 | -------------------------------------------------------------------------------- /app/screens/Room/HistoryBegin/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import s from './styles' 5 | 6 | const HistoryBegin = () => { 7 | return ( 8 | 9 | 10 | Welcome! 11 | 12 | 13 | This is the very beginning of this channel history. 14 | 15 | 16 | ) 17 | } 18 | 19 | HistoryBegin.propTypes = { 20 | 21 | } 22 | 23 | export default HistoryBegin 24 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "env": { 5 | "browser": true, 6 | "node": true, 7 | "jasmine": true 8 | }, 9 | "rules": { 10 | "no-use-before-define": [2, "nofunc"], 11 | "object-curly-spacing": 0, 12 | "react/jsx-indent-props": 0, 13 | "react/jsx-closing-bracket-location": [2, "after-props"], 14 | "react/wrap-multilines": 0, 15 | "new-cap": 0, 16 | "indent": [2, 2], 17 | "semi": 0, 18 | "comma-dangle": [1, "never"], 19 | "no-else-return": 0, 20 | "no-unused-vars": 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libs/react-native-android-bottom-sheet/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | } 14 | 15 | repositories { 16 | mavenCentral() 17 | } 18 | 19 | dependencies { 20 | compile 'com.android.support:appcompat-v7:23.2.1' 21 | compile 'com.facebook.react:react-native:0.17.0' 22 | compile 'com.cocosw:bottomsheet:1.+@aar' 23 | } 24 | -------------------------------------------------------------------------------- /app/screens/Room/JoinRoomField/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {Text} from 'react-native'; 4 | import Button from '../../../components/Button' 5 | import s from './styles' 6 | 7 | const JoinRoomField = ({onPress}) => { 8 | return ( 9 | 16 | ) 17 | } 18 | 19 | JoinRoomField.propTypes = { 20 | onPress: PropTypes.func 21 | } 22 | 23 | export default JoinRoomField 24 | -------------------------------------------------------------------------------- /libs/react-native-android-bottom-sheet/index.ios.js: -------------------------------------------------------------------------------- 1 | import {ActionSheetIOS} from 'react-native' 2 | 3 | const BottomSheet = { 4 | showBotttomSheetWithOptions({title, items}, callback) { 5 | const options = { 6 | title: title || '', 7 | options: items.concat('Close'), 8 | cancelButtonIndex: items.length 9 | } 10 | 11 | ActionSheetIOS.showActionSheetWithOptions( 12 | options, 13 | index => index === items.length // Close 14 | ? () => {} 15 | : callback(index, items[index]) 16 | ) 17 | } 18 | } 19 | 20 | export default BottomSheet 21 | -------------------------------------------------------------------------------- /app/screens/Room/JoinRoomField/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | 6 | const styles = StyleSheet.create({ 7 | container: { 8 | height: 52, 9 | alignSelf: 'stretch', 10 | alignItems: 'center', 11 | justifyContent: 'center', 12 | elevation: 8, 13 | backgroundColor: 'white', 14 | borderTopWidth: 1, 15 | borderTopColor: '#f0eef0' 16 | }, 17 | text: { 18 | color: colors.raspberry, 19 | fontSize: 18 20 | } 21 | 22 | }) 23 | 24 | export default styles 25 | -------------------------------------------------------------------------------- /ios/gittermobile/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/screens/Room/HistoryBegin/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Dimensions} from 'react-native' 2 | const {height} = Dimensions.get('window') 3 | const TOOLBAR_HEIGHT = 56 + 24 4 | const BOTTOM_BAR_HEIGHT = 56 5 | 6 | const styles = StyleSheet.create({ 7 | container: { 8 | flex: 1, 9 | height: height - TOOLBAR_HEIGHT - BOTTOM_BAR_HEIGHT, 10 | alignSelf: 'stretch', 11 | justifyContent: 'flex-end', 12 | paddingBottom: 10, 13 | paddingHorizontal: 15 14 | }, 15 | heading: { 16 | fontSize: 24 17 | }, 18 | text: { 19 | fontSize: 14 20 | } 21 | }) 22 | 23 | export default styles 24 | -------------------------------------------------------------------------------- /app/components/Heading/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | 5 | const Heading = ({text, color, styles}) => ( 6 | 9 | 13 | {text} 14 | 15 | 16 | ) 17 | 18 | Heading.defaultProps = { 19 | color: '#E20354' 20 | } 21 | 22 | Heading.propTypes = { 23 | text: PropTypes.string.isRequired, 24 | color: PropTypes.string, 25 | styles: PropTypes.any 26 | } 27 | 28 | export default Heading 29 | -------------------------------------------------------------------------------- /app/modules/readBy.js: -------------------------------------------------------------------------------- 1 | export const READ_BY_SNAPSHOT = 'readBy/READ_BY_SNAPSHOT' 2 | 3 | export function receiveReadBySnapshot(messageId, snapshot) { 4 | return { 5 | type: READ_BY_SNAPSHOT, 6 | payload: snapshot, 7 | messageId 8 | } 9 | } 10 | 11 | const initialState = { 12 | byMessage: {} 13 | } 14 | 15 | export default function readBy(state = initialState, action) { 16 | switch (action.type) { 17 | case READ_BY_SNAPSHOT: 18 | return {...state, 19 | byMessage: {...state.byMessage, 20 | [action.messageId]: action.payload 21 | } 22 | } 23 | 24 | default: 25 | return state 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/screens/Drawer/ChannelListItem/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | flexDirection: 'row', 7 | alignItems: 'center', 8 | justifyContent: 'space-between', 9 | paddingHorizontal: 16, 10 | height: 50, 11 | backgroundColor: 'white' 12 | }, 13 | headingContainer: { 14 | marginLeft: 10, 15 | flex: 1 16 | }, 17 | heading: { 18 | fontSize: 12, 19 | color: 'black' 20 | }, 21 | leftContainer: { 22 | flexDirection: 'row', 23 | alignItems: 'center' 24 | } 25 | }) 26 | 27 | export default styles 28 | -------------------------------------------------------------------------------- /app/screens/Home/HomeRoomItem/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | height: 80, 7 | padding: 20, 8 | paddingLeft: 20, 9 | alignSelf: 'stretch', 10 | flexDirection: 'row', 11 | justifyContent: 'flex-start', 12 | alignItems: 'center' 13 | }, 14 | infoContainer: { 15 | flex: 1, 16 | flexDirection: 'column', 17 | marginLeft: 16 18 | }, 19 | name: { 20 | fontSize: 16, 21 | color: 'black' 22 | }, 23 | userCount: { 24 | fontSize: 14, 25 | color: 'gray' 26 | } 27 | }) 28 | 29 | export default styles 30 | -------------------------------------------------------------------------------- /app/screens/Settings/TextItem/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import s from './styles' 5 | 6 | import Button from '../../../components/Button' 7 | 8 | const TextITem = ({ 9 | onPress, 10 | text 11 | }) => ( 12 | 19 | ) 20 | 21 | TextITem.propTypes = { 22 | onPress: PropTypes.func, 23 | text: PropTypes.string, 24 | icon: PropTypes.string 25 | } 26 | 27 | export default TextITem 28 | -------------------------------------------------------------------------------- /app/components/Divider/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View} from 'react-native'; 4 | 5 | const Divider = ({inset, style, light}) => { 6 | return ( 7 | 14 | ) 15 | } 16 | 17 | Divider.defaultProps = { 18 | light: true 19 | } 20 | 21 | Divider.propTypes = { 22 | inset: PropTypes.bool, 23 | style: PropTypes.object, 24 | light: PropTypes.bool 25 | } 26 | 27 | export default Divider 28 | -------------------------------------------------------------------------------- /app/screens/LoginByWebView/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import backgroundImage from '../../styles/common/BackgroundImage' 3 | import {THEMES} from '../../constants' 4 | const {colors} = THEMES.gitterDefault 5 | 6 | const styles = StyleSheet.create({ 7 | container: { 8 | ...backgroundImage, 9 | flex: 1, 10 | justifyContent: 'center' 11 | }, 12 | logo: { 13 | fontSize: 40, 14 | color: 'white', 15 | backgroundColor: 'transparent', 16 | marginTop: 20 17 | }, 18 | loadingContainer: { 19 | justifyContent: 'center', 20 | alignItems: 'center' 21 | } 22 | }) 23 | 24 | 25 | export default styles 26 | -------------------------------------------------------------------------------- /app/screens/SearchMessages/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | flex: 1, 8 | backgroundColor: 'white' 9 | }, 10 | toolbar: { 11 | backgroundColor: colors.raspberry, 12 | height: 56, 13 | elevation: 4 14 | }, 15 | text: { 16 | textAlign: 'center', 17 | fontSize: 14, 18 | paddingTop: 16 19 | }, 20 | textInput: { 21 | color: 'white', 22 | height: 24, 23 | fontSize: 18, 24 | alignSelf: 'stretch' 25 | } 26 | }) 27 | 28 | export default styles 29 | -------------------------------------------------------------------------------- /ios/Pods/SocketRocket/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright 2012 Square Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | -------------------------------------------------------------------------------- /libs/react-native-gitter-faye/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 22 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | lintOptions { 14 | abortOnError false 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | compile 'com.facebook.react:react-native:0.20.0' 24 | } 25 | 26 | repositories { 27 | jcenter() 28 | } 29 | 30 | dependencies { 31 | compile 'com.github.amatkivskiy:gitter.sdk.async:1.5' 32 | } 33 | -------------------------------------------------------------------------------- /app/modules/activity.js: -------------------------------------------------------------------------------- 1 | export const RECEIVE_ROOM_EVENTS_SNAPSHOT = 'activity/RECEIVE_ROOM_EVENTS_SNAPSHOT' 2 | 3 | export function receiveRoomEventsSnapshot(roomId, snapshot) { 4 | return { 5 | type: RECEIVE_ROOM_EVENTS_SNAPSHOT, 6 | snapshot, 7 | roomId 8 | } 9 | } 10 | 11 | const initialState = { 12 | byRoom: { 13 | // [id]: [] 14 | } 15 | } 16 | 17 | export default function activity(state = initialState, action) { 18 | switch (action.type) { 19 | case RECEIVE_ROOM_EVENTS_SNAPSHOT: 20 | return { 21 | byRoom: {...state.byRoom, 22 | [action.roomId]: action.snapshot 23 | } 24 | } 25 | default: 26 | return state 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/screens/Drawer/SearchField/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import s from './styles' 5 | 6 | import {THEMES} from '../../../constants' 7 | const {colors} = THEMES.gitterDefault 8 | 9 | import Icon from 'react-native-vector-icons/MaterialIcons' 10 | 11 | const SearchField = ({onPress}) => ( 12 | 13 | onPress()}> 19 | Search 20 | 21 | 22 | ) 23 | 24 | export default SearchField 25 | -------------------------------------------------------------------------------- /app/components/FailedToLoad/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import Button from '../Button' 5 | import s from './styles' 6 | 7 | const FailedToLoad = ({onRetry, message}) => { 8 | return ( 9 | 10 | 11 | {message} 12 | 13 | 18 | 19 | ) 20 | } 21 | 22 | FailedToLoad.propTypes = { 23 | onRetry: PropTypes.func, 24 | message: PropTypes.string 25 | } 26 | 27 | export default FailedToLoad 28 | -------------------------------------------------------------------------------- /app/components/Avatar/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {Image} from 'react-native'; 4 | 5 | 6 | const Avatar = ({src, size}) => { 7 | return ( 8 | 17 | ) 18 | } 19 | 20 | Avatar.defaultProps = { 21 | src: 'https://avatars.githubusercontent.com/ammorium?v=3&s=100', 22 | size: 40 23 | } 24 | 25 | Avatar.propTypes = { 26 | src: PropTypes.string, 27 | size: PropTypes.number 28 | } 29 | 30 | export default Avatar 31 | -------------------------------------------------------------------------------- /app/components/ParsedText/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Platform} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const iOS = Platform.OS === 'ios' 6 | 7 | const styles = StyleSheet.create({ 8 | mention: { 9 | fontWeight: 'bold' 10 | }, 11 | groupMention: { 12 | color: '#e67e22' 13 | }, 14 | selfMention: { 15 | color: '#e67e22' 16 | }, 17 | url: { 18 | color: colors.link 19 | }, 20 | emoji: { 21 | fontSize: 14 22 | }, 23 | text: { 24 | fontSize: 14 25 | }, 26 | codespan: { 27 | fontFamily: iOS ? 'Courier New' : 'monospace', 28 | color: 'green' 29 | } 30 | }) 31 | 32 | export default styles 33 | -------------------------------------------------------------------------------- /app/screens/User/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | flex: 1, 8 | backgroundColor: 'white', 9 | height: '100%' 10 | }, 11 | loadingContainer: { 12 | height: '100%', 13 | flex: 1, 14 | justifyContent: 'center', 15 | alignItems: 'center', 16 | backgroundColor: 'white' 17 | }, 18 | toolbar: { 19 | height: 56, 20 | backgroundColor: colors.raspberry, 21 | elevation: 4 22 | }, 23 | tabsContainer: { 24 | // flex: 1 25 | }, 26 | tabs: { 27 | elevation: 4 28 | } 29 | }) 30 | 31 | export default styles 32 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - MZFayeClient (1.0.3): 3 | - SocketRocket 4 | - SocketRocket (0.5.1) 5 | 6 | DEPENDENCIES: 7 | - MZFayeClient (from `https://github.com/m1entus/MZFayeClient.git`, commit `6a88a1`) 8 | 9 | EXTERNAL SOURCES: 10 | MZFayeClient: 11 | :commit: 6a88a1 12 | :git: https://github.com/m1entus/MZFayeClient.git 13 | 14 | CHECKOUT OPTIONS: 15 | MZFayeClient: 16 | :commit: 6a88a1 17 | :git: https://github.com/m1entus/MZFayeClient.git 18 | 19 | SPEC CHECKSUMS: 20 | MZFayeClient: ac3defb0026d26f025444eeb021117be9cab4642 21 | SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531 22 | 23 | PODFILE CHECKSUM: 943ae513e18e7ab74182d57137d9874ad2a96422 24 | 25 | COCOAPODS: 1.2.0 26 | -------------------------------------------------------------------------------- /ios/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - MZFayeClient (1.0.3): 3 | - SocketRocket 4 | - SocketRocket (0.5.1) 5 | 6 | DEPENDENCIES: 7 | - MZFayeClient (from `https://github.com/m1entus/MZFayeClient.git`, commit `6a88a1`) 8 | 9 | EXTERNAL SOURCES: 10 | MZFayeClient: 11 | :commit: 6a88a1 12 | :git: https://github.com/m1entus/MZFayeClient.git 13 | 14 | CHECKOUT OPTIONS: 15 | MZFayeClient: 16 | :commit: 6a88a1 17 | :git: https://github.com/m1entus/MZFayeClient.git 18 | 19 | SPEC CHECKSUMS: 20 | MZFayeClient: ac3defb0026d26f025444eeb021117be9cab4642 21 | SocketRocket: d57c7159b83c3c6655745cd15302aa24b6bae531 22 | 23 | PODFILE CHECKSUM: 943ae513e18e7ab74182d57137d9874ad2a96422 24 | 25 | COCOAPODS: 1.2.0 26 | -------------------------------------------------------------------------------- /app/modules/settings.js: -------------------------------------------------------------------------------- 1 | export const READ_ALL_MESSAGES = 'settings/READ_ALL_MESSAGES' 2 | 3 | export function readAll(enabled, limit = 2) { 4 | return { 5 | type: READ_ALL_MESSAGES, 6 | enabled, 7 | limit 8 | } 9 | } 10 | 11 | const initialState = { 12 | limit: 30, 13 | usersLimit: 30, 14 | readAllMessages: { 15 | enabled: false, 16 | limit: 2 17 | } 18 | } 19 | 20 | export default function settings(state = initialState, action) { 21 | switch (action.type) { 22 | case READ_ALL_MESSAGES: 23 | return {...state, 24 | readAllMessages: { 25 | enabled: action.enabled, 26 | limit: action.limit 27 | } 28 | } 29 | 30 | default: 31 | return state 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/screens/Search/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | 4 | const {colors} = THEMES.gitterDefault 5 | 6 | const styles = StyleSheet.create({ 7 | container: { 8 | flex: 1, 9 | backgroundColor: 'white' 10 | }, 11 | tabsContainer: { 12 | flex: 1 13 | }, 14 | toolbar: { 15 | height: 56, 16 | backgroundColor: colors.raspberry 17 | }, 18 | toolbarContainer: { 19 | justifyContent: 'center', 20 | alignSelf: 'stretch' 21 | }, 22 | tabs: { 23 | elevation: 4 24 | }, 25 | textInput: { 26 | color: 'white', 27 | height: 24, 28 | fontSize: 18, 29 | alignSelf: 'stretch' 30 | } 31 | }) 32 | 33 | export default styles 34 | -------------------------------------------------------------------------------- /app/screens/NoInternet/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import backgroundImage from '../../styles/common/BackgroundImage' 3 | 4 | const styles = StyleSheet.create({ 5 | container: { 6 | ...backgroundImage, 7 | justifyContent: 'space-around', 8 | alignItems: 'center' 9 | }, 10 | logo: { 11 | fontSize: 40, 12 | textAlign: 'center', 13 | color: 'white' 14 | }, 15 | buttonStyle: { 16 | margin: 10, 17 | width: 150, 18 | height: 40, 19 | borderRadius: 2, 20 | justifyContent: 'center', 21 | alignItems: 'center', 22 | elevation: 2 23 | }, 24 | buttonText: { 25 | color: 'white', 26 | fontWeight: 'bold' 27 | } 28 | }) 29 | 30 | export default styles 31 | -------------------------------------------------------------------------------- /ios/Pods/Local Podspecs/MZFayeClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MZFayeClient", 3 | "version": "1.0.3", 4 | "summary": "Faye Client for iOS. Supports subscription blocks.", 5 | "homepage": "https://github.com/m1entus/MZFayeClient", 6 | "license": { 7 | "type": "MIT", 8 | "file": "LICENSE" 9 | }, 10 | "authors": { 11 | "Michał Zaborowski": "m1entus@gmail.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/m1entus/MZFayeClient.git", 15 | "tag": "1.0.3" 16 | }, 17 | "source_files": "MZFayeClient/*.{h,m}", 18 | "dependencies": { 19 | "SocketRocket": [ 20 | 21 | ] 22 | }, 23 | "platforms": { 24 | "ios": "7.0" 25 | }, 26 | "frameworks": "QuartzCore", 27 | "requires_arc": true 28 | } 29 | -------------------------------------------------------------------------------- /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.3' 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 | -------------------------------------------------------------------------------- /app/components/Link/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Component } from 'react' 3 | import {Text, Linking} from 'react-native'; 4 | import s from './styles' 5 | import {THEMES} from '../../constants' 6 | const {colors} = THEMES.gitterDefault 7 | 8 | 9 | export default class Link extends Component { 10 | render() { 11 | const {children, to, fontSize} = this.props 12 | return ( 13 | Linking.openURL(to)}> 16 | {children} 17 | 18 | ) 19 | } 20 | } 21 | 22 | Link.propTypes = { 23 | children: PropTypes.string.isRequired, 24 | to: PropTypes.string.isRequired, 25 | fontSize: PropTypes.number 26 | } 27 | -------------------------------------------------------------------------------- /app/utils/iconsMap.js: -------------------------------------------------------------------------------- 1 | import MaterialIcons from 'react-native-vector-icons/MaterialIcons' 2 | import {icons} from '../constants' 3 | 4 | export const iconsMap = {}; 5 | export const iconsLoaded = new Promise((resolve, reject) => { 6 | new Promise.all( 7 | Object.keys(icons).map(iconName => { 8 | const icon = icons[iconName] 9 | const Provider = MaterialIcons 10 | return Provider.getImageSource( 11 | icon.icon, 12 | icon.size, 13 | icon.color 14 | ) 15 | }) 16 | ).then(sources => { 17 | Object.keys(icons) 18 | .forEach((iconName, idx) => iconsMap[iconName] = sources[idx]) 19 | 20 | // Call resolve (and we are done) 21 | resolve(true); 22 | }) 23 | }) 24 | 25 | export default iconsMap 26 | -------------------------------------------------------------------------------- /ios/Pods/SocketRocket/SocketRocket/SocketRocket.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2012 Square Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | #import 18 | -------------------------------------------------------------------------------- /ios/Pods/Local Podspecs/RNVectorIcons.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RNVectorIcons", 3 | "version": "2.1.0", 4 | "summary": "Customizable Icons for React Native with support for NavBar/TabBar, image source and full styling.", 5 | "homepage": "https://github.com/oblador/react-native-vector-icons", 6 | "license": "MIT", 7 | "authors": { 8 | "Joel Arvidsson": "joel@oblador.se" 9 | }, 10 | "platforms": { 11 | "ios": "7.0" 12 | }, 13 | "source": { 14 | "git": "https://github.com/oblador/react-native-vector-icons.git", 15 | "tag": "v2.1.0" 16 | }, 17 | "source_files": "RNVectorIconsManager/**/*.{h,m}", 18 | "resources": "Fonts/*.ttf", 19 | "preserve_paths": "**/*.js", 20 | "dependencies": { 21 | "React": [ 22 | 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/components/CustomSearch/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | const height = 48 3 | 4 | const styles = StyleSheet.create({ 5 | container: { 6 | borderRadius: 2, 7 | height, 8 | flexDirection: 'row', 9 | alignItems: 'center', 10 | // justifyContent: 'center', 11 | margin: 4, 12 | backgroundColor: 'white', 13 | elevation: 2 14 | }, 15 | button: { 16 | elevation: 0, 17 | width: 56, 18 | height, 19 | justifyContent: 'center', 20 | alignItems: 'center' 21 | }, 22 | buttonIcon: { 23 | width: 25, 24 | height: 25, 25 | opacity: 0.6 26 | }, 27 | textInput: { 28 | flex: 1, 29 | height, 30 | backgroundColor: 'white', 31 | fontSize: 18 32 | } 33 | }) 34 | 35 | export default styles 36 | -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/SocketRocket/SocketRocket.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/SocketRocket 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SocketRocket" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/MZFayeClient" "${PODS_ROOT}/Headers/Public/SocketRocket" 4 | OTHER_LDFLAGS = -l"icucore" -framework "CFNetwork" -framework "Security" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/SocketRocket 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /app/screens/Launch/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import {Text, Image, StatusBar} from 'react-native'; 3 | import s from './styles' 4 | import {THEMES} from '../../constants' 5 | const {colors} = THEMES.gitterDefault 6 | 7 | 8 | export default class LaunchScreen extends Component { 9 | render() { 10 | return ( 11 | 13 | 16 | 17 | Loading... 18 | 19 | 20 | ) 21 | } 22 | } 23 | 24 | LaunchScreen.navigatorStyle = { 25 | navBarHidden: true, 26 | statusBarBlur: true, 27 | statusBarColor: colors.darkRed 28 | } 29 | -------------------------------------------------------------------------------- /app/components/LoadingMoreSnack/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Dimensions} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | 4 | const {colors} = THEMES.gitterDefault 5 | const {width} = Dimensions.get('window') 6 | 7 | 8 | const style = StyleSheet.create({ 9 | container: { 10 | flex: 1, 11 | alignItems: 'center', 12 | justifyContent: 'center', 13 | position: 'absolute', 14 | top: 56, 15 | right: 0, 16 | height: 25, 17 | width, 18 | elevation: 4 19 | }, 20 | text: { 21 | textAlign: 'center' 22 | }, 23 | info: { 24 | backgroundColor: colors.androidGray 25 | }, 26 | progressBar: { 27 | position: 'absolute', 28 | top: -6, 29 | right: 0, 30 | left: 0, 31 | elevation: 4 32 | } 33 | }) 34 | 35 | export default style 36 | -------------------------------------------------------------------------------- /app/components/LoadingMoreSnack/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {ProgressBarAndroid, View, Text} from 'react-native'; 4 | import s from './styles' 5 | import {THEMES} from '../../constants' 6 | const {colors} = THEMES.gitterDefault 7 | 8 | const LoadingMoreSnack = ({loading}) => { 9 | if (loading) { 10 | return ( 11 | 12 | 15 | 16 | ) 17 | } 18 | 19 | return ( 20 | 21 | Loading... 22 | 23 | ) 24 | } 25 | 26 | LoadingMoreSnack.propTypes = { 27 | loading: PropTypes.bool 28 | } 29 | 30 | export default LoadingMoreSnack 31 | -------------------------------------------------------------------------------- /app/screens/RoomInfo/RepoInfo/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | // flex: 1 6 | }, 7 | header: { 8 | flexDirection: 'row', 9 | paddingHorizontal: 16, 10 | paddingVertical: 24 11 | }, 12 | headerTextContainer: { 13 | marginLeft: 16, 14 | flexDirection: 'column' 15 | }, 16 | name: { 17 | }, 18 | itemContainer: { 19 | paddingHorizontal: 16, 20 | paddingVertical: 8 21 | }, 22 | description: { 23 | 24 | }, 25 | statContainer: { 26 | flexDirection: 'row', 27 | justifyContent: 'space-around' 28 | }, 29 | statItemContainer: { 30 | alignItems: 'center', 31 | width: 75 32 | }, 33 | button: { 34 | height: 48, 35 | elevation: 0 36 | } 37 | }) 38 | 39 | export default styles 40 | -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/MZFayeClient/MZFayeClient.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/MZFayeClient 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/MZFayeClient" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/MZFayeClient" "${PODS_ROOT}/Headers/Public/SocketRocket" 4 | LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/SocketRocket" 5 | OTHER_LDFLAGS = -framework "QuartzCore" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/MZFayeClient 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | -------------------------------------------------------------------------------- /app/modules/index.js: -------------------------------------------------------------------------------- 1 | import {combineReducers} from 'redux' 2 | 3 | import ui from './ui' 4 | import app from './app' 5 | import auth from './auth' 6 | import rooms from './rooms' 7 | import users from './users' 8 | import readBy from './readBy' 9 | import viewer from './viewer' 10 | import search from './search' 11 | import roomInfo from './roomInfo' 12 | import messages from './messages' 13 | import settings from './settings' 14 | import realtime from './realtime' 15 | import activity from './activity' 16 | import navigation from './navigation' 17 | 18 | const rootReducer = combineReducers({ 19 | ui, 20 | app, 21 | auth, 22 | rooms, 23 | users, 24 | readBy, 25 | viewer, 26 | search, 27 | roomInfo, 28 | messages, 29 | settings, 30 | realtime, 31 | activity, 32 | navigation 33 | }) 34 | 35 | export default rootReducer 36 | -------------------------------------------------------------------------------- /app/screens/Room/StatusMessage/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const style = StyleSheet.create({ 6 | container: { 7 | flex: 1, 8 | flexDirection: 'row', 9 | flexWrap: 'wrap', 10 | paddingLeft: 15, 11 | paddingRight: 15, 12 | paddingTop: 5, 13 | paddingBottom: 5 14 | }, 15 | content: { 16 | flex: 1, 17 | flexDirection: 'column', 18 | flexWrap: 'wrap', 19 | marginLeft: 15 20 | }, 21 | text: { 22 | fontSize: 14, 23 | color: 'purple' 24 | }, 25 | url: { 26 | color: colors.link 27 | }, 28 | readStatus: { 29 | width: 15, 30 | marginTop: 3 31 | }, 32 | readStatusIcon: { 33 | width: 15, 34 | height: 15 35 | } 36 | }) 37 | 38 | export default style 39 | -------------------------------------------------------------------------------- /app/components/UnreadBadge/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | width: 20, 8 | height: 20, 9 | borderRadius: 20, 10 | borderColor: 'rgba(0,0,0,0.1)', 11 | borderWidth: 0, 12 | alignItems: 'center', 13 | justifyContent: 'center' 14 | }, 15 | mention: { 16 | backgroundColor: colors.mention 17 | }, 18 | unread: { 19 | backgroundColor: colors.green 20 | }, 21 | text: { 22 | color: colors.white, 23 | fontSize: 10 24 | }, 25 | lurk: { 26 | width: 8, 27 | height: 8, 28 | borderRadius: 8, 29 | borderColor: colors.green, 30 | borderWidth: 1, 31 | backgroundColor: 'transparent' 32 | } 33 | }) 34 | 35 | export default styles 36 | -------------------------------------------------------------------------------- /app/screens/Settings/Group/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Children } from 'react' 3 | import {View} from 'react-native'; 4 | import s from './styles' 5 | 6 | import Heading from '../../../components/Heading' 7 | import Divider from '../../../components/Divider' 8 | 9 | const Group = ({ 10 | heading, 11 | children 12 | }) => ( 13 | 14 | 15 | 16 | 17 | 18 | 19 | {Children.map(children, Item => ( 20 | 21 | {Item} 22 | 23 | 24 | ))} 25 | 26 | 27 | ) 28 | 29 | Group.propTypes = { 30 | heading: PropTypes.string, 31 | children: PropTypes.array 32 | } 33 | 34 | export default Group 35 | -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/Pods-GitterMobile/Pods-GitterMobile.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/MZFayeClient" "${PODS_ROOT}/Headers/Public/SocketRocket" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/MZFayeClient" "$PODS_CONFIGURATION_BUILD_DIR/SocketRocket" 4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/MZFayeClient" -isystem "${PODS_ROOT}/Headers/Public/SocketRocket" 5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"MZFayeClient" -l"SocketRocket" -l"icucore" -framework "CFNetwork" -framework "QuartzCore" -framework "Security" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /app/screens/SearchMessages/MessagesList/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {ScrollView} from 'react-native' 4 | import Message from '../../Room/Message' 5 | 6 | const MessagesList = ({ 7 | items, 8 | onLongPress, 9 | onPress, 10 | onUserAvatarPress 11 | }) => ( 12 | 14 | {items.map(item => 15 | {}} 21 | key={item.id} /> 22 | )} 23 | 24 | ) 25 | 26 | MessagesList.propTypes = { 27 | items: PropTypes.array, 28 | onPress: PropTypes.func, 29 | onLongPress: PropTypes.func, 30 | onUserAvatarPress: PropTypes.func 31 | } 32 | 33 | export default MessagesList 34 | -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/Pods-GitterMobile/Pods-GitterMobile.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/MZFayeClient" "${PODS_ROOT}/Headers/Public/SocketRocket" 3 | LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/MZFayeClient" "$PODS_CONFIGURATION_BUILD_DIR/SocketRocket" 4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/MZFayeClient" -isystem "${PODS_ROOT}/Headers/Public/SocketRocket" 5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"MZFayeClient" -l"SocketRocket" -l"icucore" -framework "CFNetwork" -framework "QuartzCore" -framework "Security" 6 | PODS_BUILD_DIR = $BUILD_DIR 7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /ios/gittermobileTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/gittermobile-tvOSTests/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/screens/Drawer/DrawerUserInfo/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet, StatusBar, Platform} from 'react-native' 2 | const STATUS_BAR_HEIGHT = StatusBar.currentHeight 3 | 4 | const styles = StyleSheet.create({ 5 | container: { 6 | elevation: 4 7 | }, 8 | topContainer: { 9 | paddingLeft: 16, 10 | paddingRight: 8, 11 | paddingTop: Platform.OS === 'ios' ? 24 + 8 : 8, 12 | alignSelf: 'stretch', 13 | flexDirection: 'row', 14 | justifyContent: 'center', 15 | alignItems: 'center' 16 | }, 17 | info: { 18 | flex: 1, 19 | flexDirection: 'column', 20 | marginLeft: 16 21 | }, 22 | displayName: { 23 | fontSize: 16 24 | }, 25 | buttonStyle: { 26 | width: 35, 27 | height: 35, 28 | justifyContent: 'center', 29 | alignItems: 'center' 30 | }, 31 | icon: { 32 | width: 20, 33 | height: 20 34 | } 35 | }) 36 | 37 | export default styles 38 | -------------------------------------------------------------------------------- /app/components/UnreadBadge/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import s from './styles' 5 | 6 | const UnreadBadge = ({mentions, unreadItems, lurk}) => { 7 | if (!!mentions) { 8 | return ( 9 | 10 | @ 11 | 12 | ) 13 | } else if (lurk) { 14 | return ( 15 | 16 | 17 | 18 | ) 19 | } else { 20 | return ( 21 | 22 | {unreadItems} 23 | 24 | ) 25 | } 26 | } 27 | 28 | UnreadBadge.propTypes = { 29 | mentions: PropTypes.number, 30 | unreadItems: PropTypes.number, 31 | lurk: PropTypes.bool 32 | } 33 | 34 | export default UnreadBadge 35 | -------------------------------------------------------------------------------- /app/screens/RoomUserAdd/RoomUserItem/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | button: { 5 | flex: 1, 6 | elevation: 0, 7 | flexDirection: 'row', 8 | height: 70, 9 | flexWrap: 'wrap', 10 | paddingHorizontal: 18, 11 | paddingVertical: 16 12 | }, 13 | container: { 14 | flex: 1, 15 | alignItems: 'center', 16 | flexDirection: 'row', 17 | height: 70, 18 | flexWrap: 'wrap' 19 | }, 20 | userInfo: { 21 | flex: 1, 22 | paddingLeft: 18, 23 | flexDirection: 'column' 24 | }, 25 | displayName: { 26 | fontSize: 18, 27 | color: 'black' 28 | }, 29 | icon: { 30 | width: 30, 31 | height: 30, 32 | opacity: 0.6 33 | }, 34 | addIcon: { 35 | width: 40, 36 | height: 40, 37 | justifyContent: 'center', 38 | alignItems: 'center', 39 | elevation: 0 40 | } 41 | }) 42 | 43 | export default styles 44 | -------------------------------------------------------------------------------- /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/screens/RoomInfo/RoomUsers/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | // flex: 1 8 | }, 9 | usersContainer: { 10 | // flex: 1, 11 | padding: 16, 12 | alignItems: 'center', 13 | flexWrap: 'wrap', 14 | flexDirection: 'row' 15 | }, 16 | itemContainer: { 17 | margin: 2 18 | }, 19 | buttonsGroup: { 20 | // flex: 1, 21 | flexDirection: 'row', 22 | justifyContent: 'space-between', 23 | marginLeft: 16, 24 | marginRight: 16, 25 | marginBottom: 16 26 | }, 27 | button: { 28 | width: 128, 29 | height: 32, 30 | elevation: 2, 31 | justifyContent: 'center', 32 | alignItems: 'center', 33 | backgroundColor: colors.blue 34 | }, 35 | primaryButton: { 36 | backgroundColor: colors.primaryButton 37 | } 38 | }) 39 | 40 | export default styles 41 | -------------------------------------------------------------------------------- /app/screens/User/UserInfo/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | flex: 1, 8 | backgroundColor: 'white', 9 | paddingBottom: 16 10 | }, 11 | item: { 12 | paddingHorizontal: 20, 13 | paddingVertical: 8, 14 | flexDirection: 'row' 15 | }, 16 | icon: { 17 | marginRight: 8 18 | }, 19 | button: { 20 | marginHorizontal: 20, 21 | marginVertical: 10, 22 | backgroundColor: colors.secondaryButton, 23 | elevation: 2, 24 | height: 35, 25 | borderRadius: 2, 26 | flexDirection: 'row', 27 | justifyContent: 'center', 28 | alignItems: 'center' 29 | }, 30 | chatPrivately: { 31 | backgroundColor: colors.primaryButton 32 | }, 33 | textWrapper: { 34 | // flex: 1 35 | }, 36 | text: { 37 | fontSize: 18 38 | } 39 | }) 40 | 41 | export default styles 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 50 | 51 | fastlane/report.xml 52 | fastlane/Preview.html 53 | fastlane/screenshots 54 | 55 | app/local.js 56 | -------------------------------------------------------------------------------- /app/screens/RoomSettings/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Platform} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | const iOS = Platform.OS === 'ios' 5 | 6 | const styles = StyleSheet.create({ 7 | container: { 8 | flex: 1, 9 | backgroundColor: 'white' 10 | }, 11 | toolbar: { 12 | backgroundColor: colors.raspberry, 13 | height: 56, 14 | elevation: 4 15 | }, 16 | itemStyle: { 17 | fontSize: 12 18 | }, 19 | picker: { 20 | height: iOS ? 110 : 50, 21 | overflow: 'hidden', 22 | justifyContent: 'space-around', 23 | marginHorizontal: 8 24 | }, 25 | buttonStyle: { 26 | margin: 10, 27 | backgroundColor: colors.primaryButton, 28 | width: 150, 29 | height: 40, 30 | borderRadius: 2, 31 | alignSelf: 'center', 32 | justifyContent: 'center', 33 | alignItems: 'center', 34 | elevation: 2 35 | }, 36 | buttonText: { 37 | color: 'white', 38 | fontWeight: 'bold' 39 | } 40 | }) 41 | 42 | export default styles 43 | -------------------------------------------------------------------------------- /app/components/Loading/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {ActivityIndicator, View, Text} from 'react-native'; 4 | import {THEMES} from '../../constants' 5 | const {colors} = THEMES.gitterDefault 6 | 7 | const Loading = ({size, height, color, text}) => ( 8 | 14 | 18 | {text && ( 19 | 25 | {text} 26 | 27 | )} 28 | 29 | ) 30 | 31 | Loading.propTypes = { 32 | size: PropTypes.string, 33 | height: PropTypes.number, 34 | color: PropTypes.string 35 | } 36 | 37 | Loading.defaultProps = { 38 | size: 'large' 39 | } 40 | 41 | export default Loading 42 | -------------------------------------------------------------------------------- /app/screens/Message/Message/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const style = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | flexDirection: 'row', 7 | flexWrap: 'wrap', 8 | paddingLeft: 15, 9 | paddingRight: 15, 10 | paddingTop: 16, 11 | paddingBottom: 4 12 | }, 13 | content: { 14 | flex: 1, 15 | flexDirection: 'column', 16 | flexWrap: 'wrap', 17 | marginLeft: 15 18 | }, 19 | top: { 20 | flex: 1, 21 | flexDirection: 'row', 22 | // justifyContent: 'space-between' 23 | }, 24 | username: { 25 | fontWeight: 'bold' 26 | }, 27 | bottom: { 28 | 29 | }, 30 | text: { 31 | fontSize: 14 32 | }, 33 | deleted: { 34 | fontStyle: 'italic', 35 | opacity: 0.8 36 | }, 37 | date: { 38 | marginLeft: 4, 39 | fontSize: 14 40 | }, 41 | url: { 42 | color: 'blue' 43 | }, 44 | readStatus: { 45 | width: 15, 46 | marginTop: 3 47 | }, 48 | readStatusIcon: { 49 | width: 15, 50 | height: 15 51 | } 52 | }) 53 | 54 | export default style 55 | -------------------------------------------------------------------------------- /app/screens/Room/Message/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const style = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | flexDirection: 'row', 7 | flexWrap: 'wrap', 8 | paddingLeft: 15, 9 | paddingRight: 15, 10 | paddingTop: 5, 11 | paddingBottom: 5 12 | }, 13 | content: { 14 | flex: 1, 15 | flexDirection: 'column', 16 | flexWrap: 'wrap', 17 | marginLeft: 15 18 | }, 19 | top: { 20 | flex: 1, 21 | flexDirection: 'row', 22 | // justifyContent: 'space-between' 23 | }, 24 | username: { 25 | fontWeight: 'bold' 26 | }, 27 | bottom: { 28 | 29 | }, 30 | text: { 31 | fontSize: 14 32 | }, 33 | deleted: { 34 | fontStyle: 'italic', 35 | opacity: 0.8 36 | }, 37 | date: { 38 | marginLeft: 4, 39 | fontSize: 14 40 | }, 41 | url: { 42 | color: 'blue' 43 | }, 44 | readStatus: { 45 | width: 15, 46 | marginTop: 3 47 | }, 48 | readStatusIcon: { 49 | width: 15, 50 | height: 15 51 | } 52 | }) 53 | 54 | export default style 55 | -------------------------------------------------------------------------------- /app/components/Button/index.ios.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Children } from 'react' 3 | import {TouchableOpacity, View} from 'react-native'; 4 | import s from './styles' 5 | 6 | const noop = () => {} 7 | 8 | const Button = ({ 9 | onPress = noop, 10 | onLongPress = noop, 11 | onLayout = noop, 12 | children, 13 | rippleColor, 14 | style, 15 | background 16 | }) => ( 17 | 21 | 22 | {Children.map(children, child => child)} 23 | 24 | 25 | ) 26 | 27 | Button.defaultProps = { 28 | onPress: noop, 29 | onLongPress: noop, 30 | onLayout: noop, 31 | rippleColor: '#f0eef0', 32 | // style: s.button 33 | } 34 | 35 | Button.propTypes = { 36 | onPress: PropTypes.func, 37 | children: PropTypes.any, 38 | style: PropTypes.any, 39 | onLongPress: PropTypes.func, 40 | onLayout: PropTypes.func, 41 | rippleColor: PropTypes.string 42 | } 43 | 44 | export default Button 45 | -------------------------------------------------------------------------------- /app/screens/RoomUsers/RoomUserItem/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import s from './styles' 5 | 6 | import Avatar from '../../../components/Avatar' 7 | import Button from '../../../components/Button' 8 | 9 | const RoomUserItem = ({onUserItemPress, id, username, displayName, avatarUrlSmall}) => { 10 | return ( 11 | 22 | ) 23 | } 24 | 25 | RoomUserItem.propTypes = { 26 | onUserItemPress: PropTypes.func, 27 | id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 28 | username: PropTypes.string, 29 | displayName: PropTypes.string, 30 | avatarUrlSmall: PropTypes.string 31 | } 32 | 33 | export default RoomUserItem 34 | -------------------------------------------------------------------------------- /app/screens/Search/SearchUserItem/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import Button from '../../../components/Button' 5 | import s from '../../Home/HomeRoomItem/styles' 6 | import Avatar from '../../../components/Avatar' 7 | 8 | const SearchUserItem = ({id, username, displayName, avatarUrlMedium, onPress}) => { 9 | return ( 10 | 22 | 23 | ) 24 | } 25 | 26 | SearchUserItem.propTypes = { 27 | displayName: PropTypes.string, 28 | username: PropTypes.string, 29 | id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 30 | avatarUrlMedium: PropTypes.string, 31 | onPress: PropTypes.func 32 | } 33 | 34 | export default SearchUserItem 35 | -------------------------------------------------------------------------------- /app/configureStore.js: -------------------------------------------------------------------------------- 1 | import {createStore, applyMiddleware, compose} from 'redux' 2 | import thunkMiddleware from 'redux-thunk' 3 | 4 | import rootReducer from './modules' 5 | 6 | 7 | export default function configureStore(initialState) { 8 | const devTools = require('remote-redux-devtools') 9 | /** 10 | * Create store with remote-devtools and logger middleware. Do it only 11 | * in development to reduce performance issues. 12 | */ 13 | if (__DEV__) { 14 | // const createLogger = require('redux-logger') 15 | // const logger = createLogger() 16 | 17 | const finalCreateStore = compose( 18 | applyMiddleware(thunkMiddleware), 19 | devTools() 20 | )(createStore) 21 | 22 | const store = finalCreateStore(rootReducer, initialState) 23 | 24 | return store 25 | } else { 26 | // const finalCreateStore = compose(applyMiddleware(thunkMiddleware), devTools())(createStore) 27 | const finalCreateStore = applyMiddleware(thunkMiddleware)(createStore) 28 | const store = finalCreateStore(rootReducer, initialState) 29 | 30 | return store 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/components/Emoji/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {Image, Text, PixelRatio, Platform} from 'react-native'; 4 | import {emoji} from '../../images/emoji' 5 | const iOS = Platform.OS === 'ios' 6 | 7 | const Emoji = ({name, styles}) => { 8 | const source = emoji[name] 9 | 10 | if (!source) { 11 | return ( 12 | 13 | ) 14 | } 15 | 16 | return ( 17 | 18 | 21 | 22 | ) 23 | } 24 | 25 | Emoji.defaultProps = { 26 | styles: { 27 | wrapper: { 28 | fontSize: 14 29 | }, 30 | image: iOS 31 | ? { height: 20, width: 20 } 32 | : { 33 | height: PixelRatio.getPixelSizeForLayoutSize(20), 34 | width: PixelRatio.getPixelSizeForLayoutSize(20) 35 | } 36 | } 37 | } 38 | 39 | Emoji.propTypes = { 40 | name: PropTypes.string, 41 | styles: PropTypes.object 42 | } 43 | 44 | export default Emoji 45 | -------------------------------------------------------------------------------- /app/screens/RoomInfo/UserInfo/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text, TouchableOpacity} from 'react-native'; 4 | import s from '../RoomInfo/styles' 5 | 6 | import Avatar from '../../../components/Avatar' 7 | import Divider from '../../../components/Divider' 8 | 9 | const RoomInfo = ({name, user, onAvatarPress}) => { 10 | return ( 11 | 12 | 13 | onAvatarPress(user.avatarUrlSmall, name)}> 15 | 18 | 19 | 20 | {name} 21 | @{user.username} 22 | 23 | 24 | 25 | 26 | ) 27 | } 28 | 29 | RoomInfo.propTypes = { 30 | name: PropTypes.string, 31 | user: PropTypes.object, 32 | onAvatarPress: PropTypes.func 33 | } 34 | 35 | export default RoomInfo 36 | -------------------------------------------------------------------------------- /app/screens/Message/ReadBy/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, TouchableOpacity} from 'react-native'; 4 | import s from './styles' 5 | 6 | import Avatar from '../../../components/Avatar' 7 | import Heading from '../../../components/Heading' 8 | 9 | const ReadBy = ({items, onAvatarPress}) => { 10 | return ( 11 | 12 | 14 | 15 | {items.map(item => ( 16 | onAvatarPress(item.id, item.username)} 18 | key={item.id}> 19 | 22 | 25 | 26 | 27 | ))} 28 | 29 | 30 | ) 31 | } 32 | 33 | ReadBy.propTypes = { 34 | items: PropTypes.array, 35 | onAvatarPress: PropTypes.func 36 | } 37 | 38 | export default ReadBy 39 | -------------------------------------------------------------------------------- /app/screens/Login/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Dimensions} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | flex: 1, 8 | backgroundColor: colors.raspberry, 9 | justifyContent: 'center', 10 | alignItems: 'center' 11 | }, 12 | logo: { 13 | fontSize: 40, 14 | color: 'white', 15 | backgroundColor: 'transparent' 16 | }, 17 | hero: { 18 | marginTop: 20, 19 | marginHorizontal: 20, 20 | fontSize: 24, 21 | color: 'white', 22 | lineHeight: 40, 23 | backgroundColor: 'transparent' 24 | }, 25 | buttonGroup: { 26 | position: 'absolute', 27 | bottom: 20 28 | }, 29 | buttonStyle: { 30 | backgroundColor: 'white', 31 | marginBottom: 16, 32 | height: 35, 33 | borderRadius: 2, 34 | justifyContent: 'center', 35 | alignItems: 'center', 36 | elevation: 4 37 | }, 38 | buttonText: { 39 | fontWeight: 'bold', 40 | paddingHorizontal: 40, 41 | color: colors.raspberry 42 | } 43 | }) 44 | 45 | 46 | export default styles 47 | -------------------------------------------------------------------------------- /app/screens/User/UserTop/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | backgroundColor: 'white', 6 | alignItems: 'center' 7 | }, 8 | avatarWrapper: { 9 | marginVertical: 30, 10 | justifyContent: 'center', 11 | alignItems: 'center' 12 | }, 13 | displayNameWapper: { 14 | // flex: 1, 15 | paddingHorizontal: 30, 16 | alignItems: 'center', 17 | justifyContent: 'center', 18 | marginBottom: 15, 19 | }, 20 | displayName: { 21 | textAlign: 'center', 22 | color: 'black', 23 | fontSize: 24, 24 | fontWeight: 'bold' 25 | }, 26 | username: { 27 | fontSize: 18 28 | }, 29 | github: { 30 | // height: 50, 31 | paddingHorizontal: 15, 32 | flexDirection: 'row', 33 | alignItems: 'center' 34 | }, 35 | githubItem: { 36 | flexDirection: 'column', 37 | justifyContent: 'center', 38 | alignItems: 'center', 39 | margin: 15 40 | }, 41 | githubItemText: { 42 | fontSize: 18 43 | }, 44 | bold: { 45 | fontSize: 18, 46 | fontWeight: 'bold' 47 | } 48 | }) 49 | 50 | export default styles 51 | -------------------------------------------------------------------------------- /ios/Pods/MZFayeClient/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Michał Zaborowski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /app/screens/LoginByToken/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | container: { 7 | flex: 1, 8 | backgroundColor: 'white', 9 | paddingHorizontal: 16 10 | }, 11 | buttonContainer: { 12 | alignSelf: 'center' 13 | }, 14 | buttonStyle: { 15 | margin: 16, 16 | backgroundColor: colors.raspberry, 17 | paddingHorizontal: 40, 18 | marginBottom: 40, 19 | height: 35, 20 | borderRadius: 2, 21 | justifyContent: 'center', 22 | alignItems: 'center', 23 | elevation: 2 24 | }, 25 | buttonText: { 26 | color: 'white', 27 | fontWeight: 'bold' 28 | }, 29 | textfield: { 30 | height: 40, 31 | backgroundColor: 'white', 32 | paddingLeft: 0, 33 | color: colors.raspberry 34 | }, 35 | textfieldContainer: { 36 | marginVertical: 16, 37 | borderBottomWidth: 1, 38 | borderBottomColor: colors.raspberry 39 | }, 40 | hint: { 41 | color: colors.secondaryFont 42 | }, 43 | error: { 44 | color: colors.red, 45 | marginBottom: 16, 46 | fontSize: 18 47 | } 48 | }) 49 | 50 | 51 | export default styles 52 | -------------------------------------------------------------------------------- /app/screens/Home/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | 6 | const styles = StyleSheet.create({ 7 | container: { 8 | backgroundColor: 'white', 9 | 10 | flex: 1, 11 | }, 12 | scrollContainer: { 13 | // justifyContent: 'center', 14 | // alignItems: 'center' 15 | }, 16 | toolbar: { 17 | height: 56, 18 | backgroundColor: colors.raspberry, 19 | elevation: 4 20 | }, 21 | welcome: { 22 | 23 | fontSize: 20, 24 | textAlign: 'center', 25 | color: 'white', 26 | paddingBottom: 20 27 | }, 28 | loadingWrap: { 29 | height: 200 30 | }, 31 | instructions: { 32 | textAlign: 'center', 33 | color: '#333333', 34 | marginBottom: 5 35 | }, 36 | heading: { 37 | flex: 1 38 | }, 39 | foreground: { 40 | alignItems: 'center', 41 | justifyContent: 'center' 42 | }, 43 | bottom: { 44 | flex: 1, 45 | backgroundColor: 'white', 46 | alignSelf: 'stretch', 47 | paddingTop: 20 48 | }, 49 | bottomSectionHeading: { 50 | fontSize: 24, 51 | color: 'black', 52 | marginBottom: 10, 53 | marginLeft: 20 54 | } 55 | }) 56 | 57 | export default styles 58 | -------------------------------------------------------------------------------- /app/screens/Home/HomeRoomItemMy/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | height: 80, 7 | padding: 20, 8 | paddingLeft: 20, 9 | alignSelf: 'stretch', 10 | flexDirection: 'row', 11 | justifyContent: 'flex-start', 12 | alignItems: 'center' 13 | }, 14 | headingContainer: { 15 | flex: 1, 16 | flexDirection: 'column', 17 | marginLeft: 10 18 | }, 19 | heading: { 20 | fontSize: 16, 21 | color: 'black' 22 | }, 23 | userCount: { 24 | fontSize: 14, 25 | color: 'gray' 26 | }, 27 | unread: { 28 | alignSelf: 'flex-end' 29 | } 30 | }) 31 | 32 | export default styles 33 | // 34 | // container: { 35 | // height: 80, 36 | // padding: 20, 37 | // paddingLeft: 20, 38 | // alignSelf: 'stretch', 39 | // flexDirection: 'row', 40 | // justifyContent: 'flex-start', 41 | // alignItems: 'center' 42 | // }, 43 | // infoContainer: { 44 | // flexDirection: 'column', 45 | // marginLeft: 16 46 | // }, 47 | // name: { 48 | // fontSize: 16, 49 | // color: 'black' 50 | // }, 51 | // userCount: { 52 | // fontSize: 14, 53 | // color: 'gray' 54 | // } 55 | // }) 56 | -------------------------------------------------------------------------------- /app/screens/Room/SendMessageField/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | 3 | const padding = 12 4 | const button = 35 5 | const buttonMargin = 8 6 | 7 | const style = StyleSheet.create({ 8 | container: { 9 | flexDirection: 'row', 10 | alignItems: 'center', 11 | justifyContent: 'center', 12 | paddingHorizontal: padding, 13 | backgroundColor: 'white', 14 | elevation: 8, 15 | borderTopWidth: 1, 16 | borderTopColor: '#f0eef0' 17 | }, 18 | innerContainer: { 19 | flex: 1, 20 | // alignItems: 'center', 21 | justifyContent: 'center' 22 | }, 23 | textInput: { 24 | backgroundColor: 'white', 25 | fontSize: 16, 26 | paddingTop: 0, 27 | paddingBottom: 0, 28 | textAlignVertical: 'center' 29 | }, 30 | button: { 31 | height: button, 32 | margin: buttonMargin, 33 | alignItems: 'center', 34 | justifyContent: 'center' 35 | }, 36 | sendIcon: { 37 | width: 30, 38 | height: 30 39 | }, 40 | hidden: { 41 | position: 'absolute', 42 | top: 10000, // way off screen 43 | left: 10000, // way off screen 44 | backgroundColor: 'transparent', 45 | borderColor: 'transparent', 46 | color: 'transparent' 47 | } 48 | }) 49 | 50 | export default style 51 | -------------------------------------------------------------------------------- /libs/react-native-android-bottom-sheet/src/main/java/com/terrysahaidak/bottomsheet/AndroidBottomSheetPackage.java: -------------------------------------------------------------------------------- 1 | package com.terrysahaidak.bottomsheet; 2 | 3 | import android.app.Activity; 4 | 5 | import com.facebook.react.ReactPackage; 6 | import com.facebook.react.bridge.JavaScriptModule; 7 | import com.facebook.react.bridge.NativeModule; 8 | import com.facebook.react.bridge.ReactApplicationContext; 9 | import com.facebook.react.uimanager.ViewManager; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Collections; 13 | import java.util.List; 14 | 15 | public class AndroidBottomSheetPackage implements ReactPackage { 16 | 17 | public AndroidBottomSheetPackage() { 18 | super(); 19 | } 20 | 21 | @Override 22 | public List createNativeModules(ReactApplicationContext reactContext) { 23 | List modules = new ArrayList<>(); 24 | 25 | modules.add(new AndroidBottomSheet(reactContext)); 26 | 27 | return modules; 28 | } 29 | 30 | @Override 31 | public List> createJSModules() { 32 | return Collections.emptyList(); 33 | } 34 | 35 | @Override 36 | public List createViewManagers(ReactApplicationContext reactContext) { 37 | return Collections.emptyList(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/screens/Home/HomeRoomItem/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import Button from '../../../components/Button' 5 | import s from './styles' 6 | 7 | import Avatar from '../../../components/Avatar' 8 | import {createGhAvatarLink} from '../../../utils/links' 9 | 10 | const HomeRoomItem = ({id, name, userCount, oneToOne, onPress, ...props}) => { 11 | const src = oneToOne 12 | ? createGhAvatarLink(props.user.username, 200) 13 | : createGhAvatarLink(name.split('/')[0], 200) 14 | return ( 15 | 32 | 33 | ) 34 | } 35 | 36 | HomeRoomItem.propTypes = { 37 | name: PropTypes.string.isRequired, 38 | userCount: PropTypes.number.isRequired, 39 | id: PropTypes.string.isRequired, 40 | user: PropTypes.object, 41 | onPress: PropTypes.func 42 | } 43 | 44 | export default HomeRoomItem 45 | -------------------------------------------------------------------------------- /app/screens/RoomUsers/RoomUsersSearchResult/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text, ScrollView} from 'react-native'; 4 | import s from './styles' 5 | 6 | import RoomUserItem from '../RoomUserItem' 7 | import Loading from '../../../components/Loading' 8 | 9 | const RoomUsersSearchResult = ({resultItems, onUserItemPress, isLoading}) => { 10 | if (isLoading) { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | ) 18 | } 19 | 20 | if (resultItems.length === 0) { 21 | return ( 22 | 23 | 24 | No result 25 | 26 | 27 | ) 28 | } 29 | 30 | return ( 31 | 32 | 33 | {resultItems.map(item => ( 34 | 37 | ))} 38 | 39 | 40 | ) 41 | } 42 | 43 | RoomUsersSearchResult.propTypes = { 44 | resultItems: PropTypes.array, 45 | onUserItemPress: PropTypes.func, 46 | isLoading: PropTypes.bool 47 | } 48 | 49 | export default RoomUsersSearchResult 50 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/gittermobile/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.gittermobile; 2 | 3 | // import com.facebook.react.ReactActivity; 4 | import android.widget.LinearLayout; 5 | import android.graphics.Color; 6 | import android.widget.TextView; 7 | import android.view.Gravity; 8 | import android.util.TypedValue; 9 | import com.reactnativenavigation.controllers.SplashActivity; 10 | 11 | public class MainActivity extends SplashActivity { 12 | 13 | @Override 14 | public LinearLayout createSplashLayout() { 15 | LinearLayout view = new LinearLayout(this); 16 | TextView textView = new TextView(this); 17 | 18 | view.setBackgroundColor(Color.parseColor("#E20354")); 19 | view.setGravity(Gravity.CENTER); 20 | 21 | textView.setTextColor(Color.parseColor("#FFFFFF")); 22 | textView.setText("GitterMobile"); 23 | textView.setGravity(Gravity.CENTER); 24 | textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40); 25 | 26 | view.addView(textView); 27 | return view; 28 | } 29 | 30 | // /** 31 | // * Returns the name of the main component registered from JavaScript. 32 | // * This is used to schedule rendering of the component. 33 | // */ 34 | // @Override 35 | // protected String getMainComponentName() { 36 | // return "GitterMobile"; 37 | // } 38 | } 39 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'gittermobile' 2 | include ':react-native-fetch-blob' 3 | project(':react-native-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fetch-blob/android') 4 | 5 | include ':app', ':react-native-android-bottom-sheet', ':react-native-gitter-faye', ':react-native-dialogs' 6 | project(':react-native-android-bottom-sheet').projectDir = new File(rootProject.projectDir, '../libs/react-native-android-bottom-sheet') 7 | project(':react-native-gitter-faye').projectDir = new File(rootProject.projectDir, '../libs/react-native-gitter-faye') 8 | project(':react-native-dialogs').projectDir = file('../node_modules/react-native-dialogs/android') 9 | include ':react-native-vector-icons' 10 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') 11 | include ':react-native-device-info' 12 | project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android') 13 | include ':react-native-share' 14 | project(':react-native-share').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-share/android') 15 | include ':react-native-navigation' 16 | project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/android/app/') 17 | -------------------------------------------------------------------------------- /libs/react-native-gitter-faye/src/main/java/com/terrysahaidak/faye/FayeGitterPackage.java: -------------------------------------------------------------------------------- 1 | package com.terrysahaidak.faye; 2 | 3 | import android.app.Activity; 4 | 5 | import com.facebook.react.ReactPackage; 6 | import com.facebook.react.bridge.JavaScriptModule; 7 | import com.facebook.react.bridge.NativeModule; 8 | import com.facebook.react.bridge.ReactApplicationContext; 9 | import com.facebook.react.uimanager.ViewManager; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | /** 17 | * Created by Nishanth Shankar on 9/23/15. 18 | */ 19 | public class FayeGitterPackage implements ReactPackage { 20 | private Activity mActivity = null; 21 | 22 | public FayeGitterPackage(){ 23 | 24 | } 25 | 26 | @Override 27 | public List createNativeModules(ReactApplicationContext reactApplicationContext) { 28 | List modules = new ArrayList(); 29 | modules.add(new FayeGitterModule(reactApplicationContext)); 30 | return modules; 31 | } 32 | 33 | @Override 34 | public List> createJSModules() { 35 | return Collections.emptyList(); 36 | } 37 | 38 | @Override 39 | public List createViewManagers(ReactApplicationContext reactContext) { 40 | return Arrays.asList(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/utils/createMessage.js: -------------------------------------------------------------------------------- 1 | export function createMessage(user, text) { 2 | const temporaryId = randomId() 3 | return { 4 | sending: true, 5 | failed: false, 6 | id: `send-${temporaryId}`, 7 | text, 8 | sent: 'sending...', 9 | fromUser: user 10 | } 11 | } 12 | 13 | export function createStatusMessage(user, text) { 14 | const temporaryId = randomId() 15 | return { 16 | sending: true, 17 | failed: false, 18 | id: `send-${temporaryId}`, 19 | text, 20 | status: true, 21 | sent: 'sending...', 22 | fromUser: user 23 | } 24 | } 25 | 26 | // https://gist.github.com/jed/982883 27 | function randomId( 28 | a // placeholder 29 | ) { 30 | return a // if the placeholder was passed, return 31 | ? ( // a random number from 0 to 15 32 | (// unless b is 8, 33 | (a ^ Math.random() // in which case 34 | * 16 // a random number from 35 | >> a / 4)) // 8 to 11 36 | ).toString(16) // in hexadecimal 37 | : ( // or otherwise a concatenated string: 38 | (// -80000000 + 39 | ([1e7] + // 10000000 + 40 | -1e3 + // -1000 + 41 | -4e3 + // -4000 + 42 | -8e3 + -1e11)) // -100000000000, 43 | ).replace( // replacing 44 | /[018]/g, // zeroes, ones, and eights with 45 | randomId // random hex digits 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /app/screens/NoInternet/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Component } from 'react' 3 | import {Text, Image} from 'react-native'; 4 | import Button from '../../components/Button' 5 | import {connect} from 'react-redux' 6 | import s from './styles' 7 | import {THEMES} from '../../constants' 8 | import {init} from '../../modules/app' 9 | const {colors} = THEMES.gitterDefault 10 | import {rootNavigator} from '../index' 11 | 12 | class NoInternetScreen extends Component { 13 | constructor(props) { 14 | super(props) 15 | 16 | this.handleRetry = this.handleRetry.bind(this) 17 | } 18 | 19 | handleRetry() { 20 | const {dispatch} = this.props 21 | rootNavigator.startAppWithScreen({screen: 'gm.Launch'}) 22 | dispatch(init()) 23 | } 24 | 25 | render() { 26 | return ( 27 | 29 | 30 | 31 | No internet connection. 32 | 33 | 34 | 42 | 43 | ) 44 | } 45 | } 46 | 47 | NoInternetScreen.propTypes = { 48 | dispatch: PropTypes.func 49 | } 50 | 51 | export default connect()(NoInternetScreen) 52 | -------------------------------------------------------------------------------- /app/screens/Search/SearchRoomsTab/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text, ScrollView} from 'react-native'; 4 | import s from './styles' 5 | import {THEMES} from '../../../constants' 6 | import Loading from '../../../components/Loading' 7 | import SearchRoomItem from '../SearchRoomItem' 8 | const {colors} = THEMES.gitterDefault 9 | 10 | const SearchRoomsTab = ({isLoadingRooms, roomsResult, value, onPress}) => { 11 | if (isLoadingRooms) { 12 | return ( 13 | 15 | ) 16 | } 17 | 18 | if (!value.trim()) { 19 | return ( 20 | 21 | ) 22 | } 23 | 24 | if (roomsResult.length === 0) { 25 | return ( 26 | 27 | 28 | No result to display. 29 | 30 | 31 | ) 32 | } 33 | 34 | const content = roomsResult.map(item => ( 35 | 39 | )) 40 | 41 | return ( 42 | 43 | 45 | {content} 46 | 47 | 48 | ) 49 | } 50 | 51 | SearchRoomsTab.propTypes = { 52 | isLoadingRooms: PropTypes.bool, 53 | roomsResult: PropTypes.array, 54 | value: PropTypes.string, 55 | onPress: PropTypes.func 56 | } 57 | 58 | export default SearchRoomsTab 59 | -------------------------------------------------------------------------------- /app/screens/RoomUserAdd/SearchResult/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text, ScrollView} from 'react-native'; 4 | import s from './styles' 5 | 6 | import RoomUserItem from '../RoomUserItem' 7 | import Loading from '../../../components/Loading' 8 | 9 | const SearchResult = ({resultItems, onUserItemPress, isLoading, onAddPress}) => { 10 | if (isLoading) { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | ) 18 | } 19 | 20 | if (resultItems.length === 0) { 21 | return ( 22 | 23 | 24 | No result 25 | 26 | 27 | ) 28 | } 29 | 30 | return ( 31 | 32 | 34 | {resultItems.map(item => ( 35 | 40 | ))} 41 | 42 | 43 | ) 44 | } 45 | 46 | SearchResult.propTypes = { 47 | resultItems: PropTypes.array, 48 | onUserItemPress: PropTypes.func, 49 | isLoading: PropTypes.bool, 50 | onAddPress: PropTypes.func 51 | } 52 | 53 | export default SearchResult 54 | -------------------------------------------------------------------------------- /app/screens/RoomUserAdd/RoomUserItem/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import s from './styles' 5 | import Icon from 'react-native-vector-icons/MaterialIcons' 6 | 7 | import Avatar from '../../../components/Avatar' 8 | import Button from '../../../components/Button' 9 | 10 | const RoomUserItem = ({onUserItemPress, id, username, displayName, avatarUrlSmall, onAddPress, noButton}) => { 11 | return ( 12 | 33 | )} 34 | 35 | ) 36 | } 37 | 38 | RoomUserItem.propTypes = { 39 | onUserItemPress: PropTypes.func, 40 | id: PropTypes.string, 41 | username: PropTypes.string, 42 | displayName: PropTypes.string, 43 | avatarUrlSmall: PropTypes.string, 44 | onAddPress: PropTypes.func, 45 | noButton: PropTypes.bool 46 | } 47 | 48 | export default RoomUserItem 49 | -------------------------------------------------------------------------------- /app/screens/Search/SearchUsersTab/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text, ScrollView} from 'react-native'; 4 | import s from '../SearchRoomsTab/styles' 5 | import {THEMES} from '../../../constants' 6 | import Loading from '../../../components/Loading' 7 | import SearchUserItem from '../SearchUserItem' 8 | const {colors} = THEMES.gitterDefault 9 | 10 | const SearchUsersTab = ({isLoadingUsers, usersResult, value, onPress}) => { 11 | if (isLoadingUsers) { 12 | return ( 13 | 15 | ) 16 | } 17 | 18 | if (!value.trim()) { 19 | return ( 20 | 21 | ) 22 | } 23 | 24 | if (usersResult.length === 0) { 25 | return ( 26 | 27 | 28 | No result to display. 29 | 30 | 31 | ) 32 | } 33 | 34 | const content = usersResult.map(item => ( 35 | 39 | )) 40 | 41 | return ( 42 | 43 | 45 | {content} 46 | 47 | 48 | ) 49 | } 50 | 51 | SearchUsersTab.propTypes = { 52 | isLoadingUsers: PropTypes.bool, 53 | usersResult: PropTypes.array, 54 | value: PropTypes.string, 55 | onPress: PropTypes.func 56 | } 57 | 58 | export default SearchUsersTab 59 | -------------------------------------------------------------------------------- /app/screens/RoomInfo/RoomInfo/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text, TouchableOpacity} from 'react-native'; 4 | import s from './styles' 5 | 6 | import {createGhAvatarLink} from '../../../utils/links' 7 | import channelNameAndOwner from '../../../utils/channelNameAndOwner' 8 | 9 | import Avatar from '../../../components/Avatar' 10 | import Divider from '../../../components/Divider' 11 | 12 | const RoomInfo = ({name, onAvatarPress}) => { 13 | const avatarSrc = createGhAvatarLink(name.split('/')[0], 200) 14 | const channel = channelNameAndOwner(name) 15 | 16 | return ( 17 | 18 | 19 | onAvatarPress(avatarSrc, !channel.name ? channel.owner : channel.name)}> 21 | 24 | 25 | {!channel.name 26 | ? ( 27 | 28 | {channel.owner} 29 | 30 | ) : ( 31 | 32 | {channel.name} 33 | by {channel.owner} 34 | 35 | )} 36 | 37 | 38 | 39 | ) 40 | } 41 | 42 | RoomInfo.propTypes = { 43 | name: PropTypes.string, 44 | onAvatarPress: PropTypes.func 45 | } 46 | 47 | export default RoomInfo 48 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | .*/Libraries/react-native/ReactNative.js 16 | 17 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | emoji=true 26 | 27 | module.system=haste 28 | 29 | experimental.strict_type_args=true 30 | 31 | munge_underscores=true 32 | 33 | 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' 34 | 35 | suppress_type=$FlowIssue 36 | suppress_type=$FlowFixMe 37 | suppress_type=$FixMe 38 | 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-5]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-5]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 41 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 42 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 43 | 44 | unsafe.enable_getters_and_setters=true 45 | 46 | [version] 47 | ^0.45.0 48 | -------------------------------------------------------------------------------- /app/components/CustomSearch/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {TextInput, View, Platform} from 'react-native'; 4 | import s from './styles' 5 | import Button from '../Button' 6 | import Icon from 'react-native-vector-icons/MaterialIcons' 7 | 8 | const CustomSearch = (props) => { 9 | const {value, onChange, onBackPress, onClearPress} = props 10 | 11 | return ( 12 | 13 | 22 | 30 | {!!value && value.length !== 0 ? ( 31 | 40 | ) : ()} 41 | 42 | ) 43 | } 44 | 45 | CustomSearch.propTypes = { 46 | value: PropTypes.string, 47 | onChange: PropTypes.func, 48 | onBackPress: PropTypes.func, 49 | onClearPress: PropTypes.func 50 | } 51 | 52 | export default CustomSearch 53 | -------------------------------------------------------------------------------- /app/screens/Search/SearchRoomItem/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import Button from '../../../components/Button' 5 | import s from '../../Home/HomeRoomItem/styles' 6 | // import {THEMES} from '../constants' 7 | // const {colors} = THEMES.gitterDefault 8 | import Avatar from '../../../components/Avatar' 9 | import {createGhAvatarLink} from '../../../utils/links' 10 | 11 | 12 | const SearchRoomItem = ({id, name, userCount, oneToOne, onPress, exists, room, ...props}) => { 13 | const src = oneToOne 14 | ? createGhAvatarLink(props.user.username, 200) 15 | : createGhAvatarLink(name.split('/')[0], 200) 16 | 17 | const roomId = !!exists && exists === true && !!room ? room.id : id 18 | return ( 19 | 32 | 33 | ) 34 | } 35 | 36 | SearchRoomItem.defaultProps = { 37 | exists: true 38 | } 39 | 40 | SearchRoomItem.propTypes = { 41 | name: PropTypes.string.isRequired, 42 | userCount: PropTypes.number.isRequired, 43 | id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, 44 | user: PropTypes.object, 45 | onPress: PropTypes.func, 46 | exists: PropTypes.bool, 47 | room: PropTypes.object 48 | } 49 | 50 | export default SearchRoomItem 51 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/modules/viewer.js: -------------------------------------------------------------------------------- 1 | import * as Api from '../api/gitter' 2 | import {LOGOUT} from './auth' 3 | 4 | /** 5 | * Constants 6 | */ 7 | 8 | export const CURRENT_USER = 'viewer/CURRENT_USER' 9 | export const CURRENT_USER_RECEIVED = 'viewer/CURRENT_USER_RECEIVED' 10 | export const CURRENT_USER_FAILED = 'viewer/CURRENT_USER_FAILED' 11 | 12 | /** 13 | * Action creators 14 | */ 15 | 16 | /** 17 | * Returns current user info by token 18 | */ 19 | export function getCurrentUser() { 20 | return async (dispatch, getState) => { 21 | const {token} = getState().auth 22 | try { 23 | dispatch({type: CURRENT_USER}) 24 | const payload = await Api.currentUser(token) 25 | dispatch({type: CURRENT_USER_RECEIVED, payload: payload[0]}) 26 | } catch (error) { 27 | dispatch({CURRENT_USER_FAILED, error}) 28 | } 29 | } 30 | } 31 | 32 | /** 33 | * Reducer 34 | */ 35 | 36 | const initialState = { 37 | isLoading: false, 38 | error: false, 39 | errors: [], 40 | user: {} 41 | } 42 | 43 | export default function viewer(state = initialState, action) { 44 | switch (action.type) { 45 | case CURRENT_USER: { 46 | return {...state, 47 | isLoading: true 48 | } 49 | } 50 | 51 | case CURRENT_USER_RECEIVED: { 52 | return {...state, 53 | isLoading: false, 54 | user: action.payload 55 | } 56 | } 57 | 58 | case LOGOUT: { 59 | return Object.assign({}, initialState) 60 | } 61 | 62 | case CURRENT_USER_FAILED: { 63 | return {...state, 64 | isLoading: false, 65 | error: true, 66 | errors: action.error 67 | } 68 | } 69 | 70 | default: 71 | return state 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/screens/Login/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Component } from 'react' 3 | import {Text, View} from 'react-native'; 4 | import Button from '../../components/Button' 5 | import s from './styles' 6 | import {connect} from 'react-redux' 7 | import {THEMES} from '../../constants' 8 | const {colors} = THEMES.gitterDefault 9 | 10 | 11 | class LoginScreen extends Component { 12 | render() { 13 | const {navigator} = this.props 14 | return ( 15 | 16 | 17 | GitterMobile 18 | 19 | 20 | 28 | 36 | 37 | 38 | ) 39 | } 40 | } 41 | 42 | LoginScreen.propTypes = { 43 | dispatch: PropTypes.func, 44 | navigator: PropTypes.object 45 | } 46 | 47 | LoginScreen.navigatorStyle = { 48 | navBarHidden: true, 49 | statusBarBlur: true, 50 | statusBarColor: colors.darkRed 51 | } 52 | 53 | export default connect()(LoginScreen) 54 | -------------------------------------------------------------------------------- /app/screens/RoomUsers/RoomUsersList/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Component } from 'react' 3 | import {ListView, View} from 'react-native'; 4 | import s from './styles' 5 | 6 | import RoomUserItem from '../RoomUserItem' 7 | 8 | export default class RoomUsersList extends Component { 9 | constructor(props) { 10 | super(props) 11 | 12 | this.renderRow = this.renderRow.bind(this) 13 | } 14 | 15 | renderRow(rowData, rowId) { 16 | const {onItemPress, onUserItemPress} = this.props 17 | 18 | return ( 19 | 24 | ) 25 | } 26 | 27 | render() { 28 | const {listViewData} = this.props 29 | 30 | if (!listViewData) { 31 | return 32 | } 33 | 34 | return ( 35 | 36 | this.renderRow(rowData, rowId)} /> 47 | 48 | ) 49 | } 50 | } 51 | 52 | RoomUsersList.propTypes = { 53 | listViewData: PropTypes.object, 54 | onItemPress: PropTypes.func, 55 | onEndReached: PropTypes.func, 56 | onUserItemPress: PropTypes.func 57 | } 58 | -------------------------------------------------------------------------------- /app/components/Toolbar/styles.js: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native' 2 | import {THEMES} from '../../constants' 3 | const {colors} = THEMES.gitterDefault 4 | 5 | const styles = StyleSheet.create({ 6 | globalContainer: { 7 | flex: 1, 8 | backgroundColor: '#FFF' 9 | }, 10 | container: { 11 | height: 64, 12 | paddingTop: 20, 13 | flexDirection: 'row', 14 | alignItems: 'center', 15 | // alignSelf: 'stretch' 16 | justifyContent: 'space-between' 17 | }, 18 | titleContainer: { 19 | // flex: 1, 20 | // backgroundColor: 'gray', 21 | // justifyContent: 'center', 22 | // alignItems: 'center' 23 | }, 24 | title: { 25 | fontSize: 16, 26 | fontWeight: 'bold', 27 | color: 'white' 28 | }, 29 | iconButton: { 30 | backgroundColor: colors.raspberry, 31 | // marginHorizontal: 4, 32 | height: 35, 33 | flexDirection: 'row', 34 | alignItems: 'center', 35 | width: 44, 36 | justifyContent: 'center' 37 | }, 38 | showIcon: { 39 | // marginRight: 4 40 | }, 41 | icon: { 42 | width: 25, 43 | height: 25 44 | }, 45 | addContainer: { 46 | // paddingHorizontal: 8, 47 | height: 44, 48 | flexDirection: 'row', 49 | alignItems: 'center', 50 | width: 44, 51 | justifyContent: 'flex-end', 52 | // alignSelf: 'flex-end' 53 | }, 54 | addContainerInner: { 55 | flex: 1, 56 | flexDirection: 'row', 57 | justifyContent: 'center', 58 | alignItems: 'center' 59 | }, 60 | iconTitle: { 61 | color: '#FFF', 62 | paddingRight: 20, 63 | fontSize: 20 64 | }, 65 | childrenContainer: { 66 | flex: 1 67 | } 68 | }) 69 | 70 | export default styles 71 | -------------------------------------------------------------------------------- /app/screens/Home/HomeRoomItemMy/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import Button from '../../../components/Button' 5 | import UnreadBadge from '../../../components/UnreadBadge' 6 | import s from './styles' 7 | import Avatar from '../../../components/Avatar' 8 | 9 | import {createGhAvatarLink} from '../../../utils/links' 10 | 11 | const HomeRoomItemMy = ({ 12 | id, name, oneToOne, user, onPress, 13 | unreadItems, mentions, lurk, userCount 14 | }) => { 15 | const src = oneToOne 16 | ? createGhAvatarLink(user.username, 200) 17 | : createGhAvatarLink(name.split('/')[0], 200) 18 | 19 | return ( 20 | 46 | ) 47 | } 48 | 49 | 50 | HomeRoomItemMy.propTypes = { 51 | name: PropTypes.string.isRequired, 52 | userCount: PropTypes.number.isRequired, 53 | id: PropTypes.string.isRequired, 54 | user: PropTypes.object, 55 | onPress: PropTypes.func 56 | } 57 | 58 | 59 | export default HomeRoomItemMy 60 | -------------------------------------------------------------------------------- /app/screens/Drawer/ChannelListSection/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View} from 'react-native' 4 | import s from './styles' 5 | import ChannelListItem from '../ChannelListItem' 6 | import Heading from '../../../components/Heading' 7 | import Button from '../../../components/Button' 8 | import Icon from 'react-native-vector-icons/MaterialIcons' 9 | 10 | const ChannelListSection = ({ 11 | name, 12 | items, 13 | onRoomPress, 14 | activeRoom, 15 | onLongRoomPress, 16 | onToggleCollapsed, 17 | sectionsState 18 | }) => { 19 | const icon = sectionsState[name] ? 'expand-more' : 'expand-less' 20 | 21 | return ( 22 | 23 | 32 | 33 | {!sectionsState[name] && items && items.map(item => ( 34 | 40 | ))} 41 | 42 | 43 | ) 44 | } 45 | 46 | 47 | ChannelListSection.propTypes = { 48 | name: PropTypes.string, 49 | items: PropTypes.array, 50 | onRoomPress: PropTypes.func, 51 | activeRoom: PropTypes.string, 52 | onLongRoomPress: PropTypes.func, 53 | collapsed: PropTypes.bool, 54 | sectionsState: PropTypes.object 55 | } 56 | 57 | export default ChannelListSection 58 | -------------------------------------------------------------------------------- /app/screens/Drawer/DrawerUserInfo/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {Image, View, Text} from 'react-native'; 4 | import Button from '../../../components/Button' 5 | import s from './styles' 6 | import Avatar from '../../../components/Avatar' 7 | import SearchField from '../SearchField' 8 | 9 | import {THEMES} from '../../../constants' 10 | const {colors} = THEMES.gitterDefault 11 | 12 | import Icon from 'react-native-vector-icons/MaterialIcons' 13 | 14 | const DrawerUserInfo = ({username, displayName, avatarUrlMedium, onSettingsPress, onSearchPress}) => { 15 | return ( 16 | 20 | 21 | 22 | 23 | 24 | {displayName} 25 | @{username} 26 | 27 | 28 | 34 | 35 | 36 | 37 | onSearchPress()} /> 39 | 40 | ) 41 | } 42 | 43 | DrawerUserInfo.propTypes = { 44 | username: PropTypes.string, 45 | displayName: PropTypes.string, 46 | avatarUrlMedium: PropTypes.string, 47 | onSettingsPress: PropTypes.func, 48 | onSearchPress: PropTypes.func 49 | } 50 | 51 | export default DrawerUserInfo 52 | -------------------------------------------------------------------------------- /ios/gittermobile.xcworkspace/xcshareddata/gittermobile.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "5F21F0E3235FB84632695194147A453A6E6793CF", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "5F21F0E3235FB84632695194147A453A6E6793CF" : 9223372036854775807, 8 | "2D744A5E2DBE6045F4BDE5587E93CD9E116BC6F4" : 9223372036854775807 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "ED1D968B-5A19-4871-A08D-A2ADAC173F62", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "5F21F0E3235FB84632695194147A453A6E6793CF" : "GitterMobile\/", 13 | "2D744A5E2DBE6045F4BDE5587E93CD9E116BC6F4" : "..\/khmarka\/megabank" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "gittermobile", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "ios\/gittermobile.xcworkspace", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:khmarka\/mgb.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "2D744A5E2DBE6045F4BDE5587E93CD9E116BC6F4" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:terrysahaidak\/GitterMobile.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "5F21F0E3235FB84632695194147A453A6E6793CF" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Terry Sahaidak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | 24 | 25 | Copyright 2016 Terry Sahaidak 26 | 27 | Licensed under the Apache License, Version 2.0 (the "License"); 28 | you may not use this file except in compliance with the License. 29 | You may obtain a copy of the License at 30 | 31 | http://www.apache.org/licenses/LICENSE-2.0 32 | 33 | Unless required by applicable law or agreed to in writing, software 34 | distributed under the License is distributed on an "AS IS" BASIS, 35 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 36 | See the License for the specific language governing permissions and 37 | limitations under the License. 38 | -------------------------------------------------------------------------------- /app/screens/User/UserTop/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text, TouchableOpacity} from 'react-native' 4 | import Avatar from '../../../components/Avatar' 5 | import s from './styles' 6 | import {createGhAvatarLink} from '../../../utils/links' 7 | 8 | const UserTop = ({displayName, username, github, gravatarImageUrl, onAvatarPress}) => { 9 | const avatar = github ? createGhAvatarLink(username, 200) : gravatarImageUrl 10 | 11 | return ( 12 | 13 | onAvatarPress(avatar)}> 15 | 16 | 19 | 20 | 21 | 22 | 23 | {displayName} 24 | 25 | 26 | @{username} 27 | 28 | 29 | {github && 30 | 31 | {github.followers} 32 | followers 33 | 34 | 35 | {github.public_repos} 36 | repos 37 | 38 | 39 | {github.following} 40 | following 41 | 42 | } 43 | 44 | ) 45 | } 46 | 47 | UserTop.propTypes = { 48 | displayName: PropTypes.string, 49 | username: PropTypes.string, 50 | github: PropTypes.object 51 | } 52 | 53 | export default UserTop 54 | -------------------------------------------------------------------------------- /ios/gittermobile-tvOS/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.gittermobile", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.gittermobile", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /app/components/Button/index.android.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Children } from 'react' 3 | import {TouchableNativeFeedback, TouchableOpacity, View} from 'react-native'; 4 | import s from './styles' 5 | import DeviceInfo from 'react-native-device-info' 6 | import {OLD_ANDROID_VERSIONS} from '../../constants' 7 | 8 | const noop = () => {} 9 | 10 | const Button = ({ 11 | onPress = noop, 12 | onLongPress = noop, 13 | onLayout = noop, 14 | children, 15 | rippleColor, 16 | style, 17 | background 18 | }) => { 19 | const version = DeviceInfo.getSystemVersion() 20 | 21 | if (!!OLD_ANDROID_VERSIONS.find(oldVersion => oldVersion === version)) { 22 | return ( 23 | 27 | 28 | {Children.map(children, child => child)} 29 | 30 | 31 | ) 32 | } else { 33 | return ( 34 | 39 | 40 | {Children.map(children, child => child)} 41 | 42 | 43 | ) 44 | } 45 | } 46 | 47 | Button.defaultProps = { 48 | onPress: noop, 49 | onLongPress: noop, 50 | onLayout: noop, 51 | rippleColor: '#f0eef0', 52 | // style: s.button 53 | } 54 | 55 | Button.propTypes = { 56 | onPress: PropTypes.func, 57 | children: PropTypes.any, 58 | style: PropTypes.any, 59 | onLongPress: PropTypes.func, 60 | onLayout: PropTypes.func, 61 | rippleColor: PropTypes.string 62 | } 63 | 64 | export default Button 65 | -------------------------------------------------------------------------------- /app/screens/Room/StatusMessage/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View} from 'react-native'; 4 | import Parser from 'react-native-parsed-text' 5 | import Icon from 'react-native-vector-icons/MaterialIcons' 6 | 7 | import s from './styles' 8 | import Button from '../../../components/Button' 9 | import renderEmoji from './renderEmoji' 10 | 11 | const EMOJI_REGEX = /:([a-z0-9A-Z_-]+):/ 12 | const THUMBSUP = /:\+1:/ 13 | const THUMBSDOWN = /:\-1:/ 14 | 15 | const StatusMessage = ({onPress, onLongPress, text, handleUrlPress, backgroundColor, opacity, onLayout}) => { 16 | const patterns = [ 17 | {type: 'url', style: s.url, onPress: handleUrlPress}, 18 | {pattern: EMOJI_REGEX, style: s.emoji, renderText: renderEmoji}, 19 | {pattern: THUMBSUP, style: s.emoji, renderText: renderEmoji}, 20 | {pattern: THUMBSDOWN, style: s.emoji, renderText: renderEmoji} 21 | ] 22 | 23 | return ( 24 | 49 | ) 50 | } 51 | 52 | StatusMessage.propTypes = { 53 | onPress: PropTypes.func, 54 | onLongPress: PropTypes.func, 55 | text: PropTypes.string, 56 | handleUrlPress: PropTypes.func, 57 | backgroundColor: PropTypes.string, 58 | opacity: PropTypes.number 59 | } 60 | 61 | export default StatusMessage 62 | -------------------------------------------------------------------------------- /app/components/ParsedText/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {Text} from 'react-native'; 4 | import Parser from 'react-native-parsed-text' 5 | import Emoji from '../Emoji' 6 | import s from './styles' 7 | 8 | const MENTION_REGEX = /(([^`]|^)@([a-zA-Z0-9_\-]+))/ 9 | const GROUP_MENTION_REGEX = /^(@\/([a-zA-Z0-9_\-]+))/ 10 | const EMOJI_REGEX = /:([a-z0-9A-Z_-]+):/ 11 | const THUMBSUP = /:\+1:/ 12 | const THUMBSDOWN = /:\-1:/ 13 | const CODE_REGEX = /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/m 14 | 15 | const renderEmoji = (matchingString, matches) => { 16 | const name = matches[0].replace(/:/g, '') 17 | return ( 18 | 19 | ) 20 | } 21 | 22 | const renderCodespan = (matchingString, matches) => { 23 | let component 24 | matchingString.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, 25 | (wholeMatch, m1, m2, m3) => { 26 | let c = m3; 27 | c = c.replace(/^([ \t]*)/g, ''); // leading whitespace 28 | c = c.replace(/[ \t]*$/g, ''); // trailing whitespace 29 | component = ( 30 | {c} 31 | ) 32 | }) 33 | return component 34 | } 35 | 36 | const ParsedText = ({text, username, handleUrlPress}) => { 37 | const patterns = [ 38 | {type: 'url', style: s.url, onPress: handleUrlPress}, 39 | {pattern: new RegExp(`@${username}`), style: s.selfMention}, 40 | {pattern: MENTION_REGEX, style: s.mention}, 41 | {pattern: GROUP_MENTION_REGEX, style: s.groupMention}, 42 | {pattern: EMOJI_REGEX, style: s.emoji, renderText: renderEmoji}, 43 | {pattern: THUMBSUP, style: s.emoji, renderText: renderEmoji}, 44 | {pattern: THUMBSDOWN, style: s.emoji, renderText: renderEmoji}, 45 | {pattern: CODE_REGEX, renderText: renderCodespan} 46 | ] 47 | 48 | return ( 49 | 52 | {text} 53 | 54 | ) 55 | } 56 | 57 | ParsedText.propTypes = { 58 | text: PropTypes.string, 59 | handleUrlPress: PropTypes.func 60 | } 61 | 62 | export default ParsedText 63 | -------------------------------------------------------------------------------- /ios/Pods/Target Support Files/Pods-GitterMobile/Pods-GitterMobile-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## MZFayeClient 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2013 Michał Zaborowski 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of 11 | this software and associated documentation files (the "Software"), to deal in 12 | the Software without restriction, including without limitation the rights to 13 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 14 | the Software, and to permit persons to whom the Software is furnished to do so, 15 | subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 22 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 23 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 24 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 25 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | 28 | ## SocketRocket 29 | 30 | 31 | Copyright 2012 Square Inc. 32 | 33 | Licensed under the Apache License, Version 2.0 (the "License"); 34 | you may not use this file except in compliance with the License. 35 | You may obtain a copy of the License at 36 | 37 | http://www.apache.org/licenses/LICENSE-2.0 38 | 39 | Unless required by applicable law or agreed to in writing, software 40 | distributed under the License is distributed on an "AS IS" BASIS, 41 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 42 | See the License for the specific language governing permissions and 43 | limitations under the License. 44 | 45 | 46 | Generated by CocoaPods - https://cocoapods.org 47 | -------------------------------------------------------------------------------- /app/constants.js: -------------------------------------------------------------------------------- 1 | import {Platform} from 'react-native' 2 | const iOS = Platform.OS === 'ios' 3 | 4 | export const THEMES = { 5 | gitterDefault: { 6 | name: 'Gitter default theme', 7 | colors: { 8 | brand: '#E20354', 9 | 10 | sidebarBackground: '#383435', 11 | 12 | primaryButton: '#46bc99', 13 | secondaryButton: '#d6d6d6', 14 | 15 | green: '#1dce73', 16 | orange: '#ea9448', 17 | yellow: '#f1c40f', 18 | blue: '#3498db', 19 | red: '#e74c3c', 20 | purple: '#935991', 21 | 22 | mention: '#e67e22', 23 | unReadBackground: 'rgba(213,245,226,.8)', 24 | 25 | mainFont: '#333', 26 | secondaryFont: '#777', 27 | whiteFont: 'white', 28 | link: '#3498db', 29 | blockquoteBorder: '#eee', 30 | 31 | codeInlineBorder: 'rgba(192,201,200,.4)', 32 | codeInlineBackground: 'rgba(192,201,200,.2', 33 | 34 | darkRed: '#b70345', 35 | raspberry: '#E20354', 36 | white: '#ffffff', 37 | gray: '#E0E0E0', 38 | dark: '#424242', 39 | 40 | androidGray: '#f0eef0' 41 | } 42 | } 43 | } 44 | 45 | export const OLD_ANDROID_VERSIONS = ['4.4.4', '4.4.3', '4.4.2', '4.4.1', '4.4', '4.3.1', '4.3', '4.2.2', '4.2.1', '4.2', '4.1.2'] 46 | 47 | export const icons = { 48 | 'menu': {icon: 'menu', color: 'black', size: 24}, 49 | 'menu-white': {icon: 'menu', color: 'white', size: 24}, 50 | 'search': {icon: 'search', color: 'black', size: 24}, 51 | 'search-white': {icon: 'search', color: 'white', size: 24}, 52 | 'more-vert': {icon: 'more-vert', color: 'white', size: 24}, 53 | 'info-outline': {icon: 'info-outline', color: 'white', size: 24}, 54 | 'back': {icon: iOS ? 'chevron-left' : 'arrow-back', color: 'white', size: 24}, 55 | 'forward': iOS ? {icon: 'chevron-right', color: 'white', size: 40} : {icon: 'arrow-forward', color: 'white', size: 24}, 56 | 'expand-more': {icon: 'expand-more', color: 'white', size: 24}, 57 | 'checkmark': {icon: 'check', color: 'white', size: 24}, 58 | 'browser': {icon: 'open-in-browser', color: 'white', size: 24}, 59 | 'closeIcon': {icon: 'close', color: 'white', size: 24} 60 | } 61 | -------------------------------------------------------------------------------- /ios/gittermobile/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | #import 3 | 4 | // ********************************************** 5 | // *** DON'T MISS: THE NEXT LINE IS IMPORTANT *** 6 | // ********************************************** 7 | #import "RCCManager.h" 8 | 9 | // IMPORTANT: if you're getting an Xcode error that RCCManager.h isn't found, you've probably ran "npm install" 10 | // with npm ver 2. You'll need to "npm install" with npm 3 (see https://github.com/wix/react-native-navigation/issues/1) 11 | 12 | #import 13 | 14 | @implementation AppDelegate 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 17 | { 18 | NSURL *jsCodeLocation; 19 | #ifdef DEBUG 20 | // jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"]; 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | #else 23 | jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 24 | #endif 25 | 26 | 27 | // ********************************************** 28 | // *** DON'T MISS: THIS IS HOW WE BOOTSTRAP ***** 29 | // ********************************************** 30 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 31 | self.window.backgroundColor = [UIColor whiteColor]; 32 | [[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation]; 33 | 34 | /* 35 | // original RN bootstrap - remove this part 36 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 37 | moduleName:@"example" 38 | initialProperties:nil 39 | launchOptions:launchOptions]; 40 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 41 | UIViewController *rootViewController = [UIViewController new]; 42 | rootViewController.view = rootView; 43 | self.window.rootViewController = rootViewController; 44 | [self.window makeKeyAndVisible]; 45 | */ 46 | 47 | 48 | return YES; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /app/screens/Drawer/ChannelListItem/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text} from 'react-native'; 4 | import s from './styles' 5 | 6 | import Avatar from '../../../components/Avatar' 7 | import UnreadBadge from '../../../components/UnreadBadge' 8 | import Button from '../../../components/Button' 9 | 10 | import {createGhAvatarLink} from '../../../utils/links' 11 | import {THEMES} from '../../../constants' 12 | const {colors} = THEMES.gitterDefault 13 | 14 | const ChannelListItem = ({ 15 | id, name, oneToOne, user, activeRoom, onRoomPress, 16 | unreadItems, mentions, lurk, onLongRoomPress 17 | }) => { 18 | const src = oneToOne 19 | ? createGhAvatarLink(user.username, 200) 20 | : createGhAvatarLink(name.split('/')[0], 200) 21 | 22 | const itemStyles = activeRoom === id 23 | ? {backgroundColor: colors.androidGray, color: colors.raspberry} 24 | : {backgroundColor: colors.white} 25 | 26 | return ( 27 | 55 | ) 56 | } 57 | 58 | ChannelListItem.propTypes = { 59 | // id: PropTypes.stings, 60 | onLongRoomPress: PropTypes.func, 61 | name: PropTypes.string, 62 | oneToOne: PropTypes.bool, 63 | user: PropTypes.object, 64 | activeRoom: PropTypes.string, 65 | onRoomPress: PropTypes.func, 66 | unreadItems: PropTypes.number, 67 | mentions: PropTypes.number, 68 | lurk: PropTypes.bool 69 | } 70 | 71 | export default ChannelListItem 72 | -------------------------------------------------------------------------------- /ios/gittermobile/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIViewControllerBasedStatusBarAppearance 6 | 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleDisplayName 10 | GitterMobile 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1 27 | LSRequiresIPhoneOS 28 | 29 | NSAppTransportSecurity 30 | 31 | NSExceptionDomains 32 | 33 | localhost 34 | 35 | NSExceptionAllowsInsecureHTTPLoads 36 | 37 | 38 | 39 | 40 | NSLocationWhenInUseUsageDescription 41 | 42 | UIAppFonts 43 | 44 | Entypo.ttf 45 | Evillicons.ttf 46 | FontAwesome.ttf 47 | Foundation.ttf 48 | Ionicons.ttf 49 | MaterialIcons.ttf 50 | Octicons.ttf 51 | Zocia.ttf 52 | EvilIcons.ttf 53 | MaterialCommunityIcons.ttf 54 | SimpleLineIcons.ttf 55 | Zocial.ttf 56 | 57 | UILaunchStoryboardName 58 | LaunchScreen 59 | UIRequiredDeviceCapabilities 60 | 61 | armv7 62 | 63 | UISupportedInterfaceOrientations 64 | 65 | UIInterfaceOrientationPortrait 66 | UIInterfaceOrientationLandscapeLeft 67 | UIInterfaceOrientationLandscapeRight 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /ios/Pods/MZFayeClient/MZFayeClient/MZFayeMessage.h: -------------------------------------------------------------------------------- 1 | // 2 | // MZFayeMessage.h 3 | // MZFayeClient 4 | // 5 | // Created by Michał Zaborowski on 12.12.2013. 6 | // Copyright (c) 2013 Michał Zaborowski. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | @interface MZFayeMessage : NSObject 29 | 30 | @property (nonatomic, strong) NSString *Id; 31 | @property (nonatomic, strong) NSString *channel; 32 | @property (nonatomic, strong) NSString *clientId; 33 | @property (nonatomic, strong) NSNumber *successful; 34 | @property (nonatomic, strong) NSNumber *authSuccessful; 35 | @property (nonatomic, strong) NSString *version; 36 | @property (nonatomic, strong) NSString *minimumVersion; 37 | @property (nonatomic, strong) NSArray *supportedConnectionTypes; 38 | @property (nonatomic, strong) NSDictionary *advice; 39 | @property (nonatomic, strong) NSString *error; 40 | @property (nonatomic, strong) NSString *subscription; 41 | @property (nonatomic, strong) NSDate *timestamp; 42 | @property (nonatomic, strong) NSDictionary *data; 43 | @property (nonatomic, strong) NSDictionary *ext; 44 | 45 | + (instancetype)messageFromDictionary:(NSDictionary *)dictionary; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /app/screens/RoomInfo/Activity/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Component } from 'react' 3 | import {View, Text} from 'react-native'; 4 | import s from './styles' 5 | import ParsedText from '../../../components/ParsedText' 6 | import Heading from '../../../components/Heading' 7 | import Divider from '../../../components/Divider' 8 | 9 | import moment from 'moment' 10 | 11 | class Activity extends Component { 12 | constructor(props) { 13 | super(props) 14 | 15 | this.renderItem = this.renderItem.bind(this) 16 | this.renderList = this.renderList.bind(this) 17 | } 18 | 19 | renderList() { 20 | const {data} = this.props 21 | const lastIndex = data.length - 1 22 | return ( 23 | 24 | {data.map((item, index) => { 25 | const bottom = lastIndex !== index 26 | return this.renderItem(item, bottom) 27 | })} 28 | 29 | ) 30 | } 31 | 32 | renderItem(item, bottom) { 33 | const {onUrlPress} = this.props 34 | return ( 35 | 36 | 37 | onUrlPress(url)} /> 41 | {this.renderDate(item.sent)} 42 | 43 | {bottom && } 44 | 45 | ) 46 | } 47 | 48 | renderDate(sent) { 49 | const now = moment() 50 | const date = moment(sent) 51 | if (now.year() > date.year()) { 52 | return date.format('YYYY MMM D HH:mm') 53 | } 54 | 55 | if (now.diff(date, 'hours') > 24) { 56 | return date.format('MMM D HH:mm') 57 | } 58 | 59 | return date.format('HH:mm') 60 | } 61 | 62 | render() { 63 | const {data} = this.props 64 | if (!data) { 65 | return null 66 | } 67 | 68 | return ( 69 | 70 | 72 | {data.length === 0 73 | ? Nothing to display 74 | : this.renderList() 75 | } 76 | 77 | ) 78 | } 79 | } 80 | 81 | Activity.propTypes = { 82 | data: PropTypes.array, 83 | onUrlPress: PropTypes.func 84 | } 85 | 86 | export default Activity 87 | -------------------------------------------------------------------------------- /libs/react-native-android-bottom-sheet/src/main/java/com/terrysahaidak/bottomsheet/AndroidBottomSheet.java: -------------------------------------------------------------------------------- 1 | package com.terrysahaidak.bottomsheet; 2 | 3 | import android.app.Activity; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | 7 | import com.cocosw.bottomsheet.BottomSheet; 8 | import com.facebook.react.bridge.Callback; 9 | import com.facebook.react.bridge.ReactApplicationContext; 10 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 11 | import com.facebook.react.bridge.ReactMethod; 12 | import com.facebook.react.bridge.ReadableArray; 13 | import com.facebook.react.bridge.ReadableMap; 14 | 15 | class AndroidBottomSheet extends ReactContextBaseJavaModule { 16 | 17 | public AndroidBottomSheet(ReactApplicationContext reactContext) { 18 | super(reactContext); 19 | } 20 | 21 | @Override 22 | public String getName() { 23 | return "AndroidBottomSheet"; 24 | } 25 | 26 | @ReactMethod 27 | public void showBotttomSheetWithOptions(ReadableMap options, final Callback onSelect) { 28 | final ReadableArray itemsArray = options.getArray("items"); 29 | final String title = options.getString("title"); 30 | 31 | BottomSheet.Builder builder = new BottomSheet.Builder(getCurrentActivity()).title(title); 32 | 33 | // create options 34 | Integer size = itemsArray.size(); 35 | for (int i = 0; i < size; i++) { 36 | builder.sheet(i, itemsArray.getString(i)); 37 | } 38 | 39 | builder.listener(new DialogInterface.OnClickListener() { 40 | @Override 41 | public void onClick(DialogInterface dialog, int which) { 42 | onSelect.invoke(which, itemsArray.getString(which)); 43 | } 44 | }); 45 | 46 | builder.build().show(); 47 | } 48 | 49 | @ReactMethod 50 | public void showShareActionSheetWithOptions(ReadableMap options, Callback failureCallback, Callback successCallback) { 51 | String url = options.getString("url"); 52 | String message = options.getString("message"); 53 | 54 | BottomSheet.Builder builder = new BottomSheet.Builder(getCurrentActivity()); 55 | final Intent shareIntent = new Intent(Intent.ACTION_SEND); 56 | 57 | failureCallback.invoke("not support this method"); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/screens/LoginByWebView/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Component } from 'react' 3 | import { 4 | WebView, 5 | View 6 | } from 'react-native' 7 | import {connect} from 'react-redux' 8 | 9 | import LoadingOverlay from '../../components/LoadingOverlay' 10 | 11 | import {THEMES} from '../../constants' 12 | const {colors} = THEMES.gitterDefault 13 | 14 | import s from './styles' 15 | import {loginByToken} from '../../modules/auth' 16 | import {gitterLoginUrl} from '../../api/gitter' 17 | 18 | class LoginByWebView extends Component { 19 | constructor(props) { 20 | super(props) 21 | 22 | this.handleNavigationStateChange = this.handleNavigationStateChange.bind(this) 23 | 24 | this.state = { 25 | url: '', 26 | loading: false 27 | } 28 | } 29 | 30 | 31 | handleNavigationStateChange(state) { 32 | if (state.url !== this.state.url) { 33 | if (state.url.indexOf('gittermobile://code') !== -1 && 34 | state.url.indexOf('https://gitter.im') === -1) { 35 | const {dispatch} = this.props 36 | const code = state.url.split('gittermobile://code?code=')[1] 37 | this.setState({url: state.url, loading: true}) 38 | dispatch(loginByToken({code})) 39 | } else { 40 | this.setState({url: state.url}) 41 | } 42 | } 43 | } 44 | 45 | renderLoading() { 46 | return ( 47 | 48 | ) 49 | } 50 | 51 | render() { 52 | const {loading} = this.state 53 | return ( 54 | 55 | 62 | {loading && this.renderLoading()} 63 | 64 | ) 65 | } 66 | } 67 | 68 | LoginByWebView.propTypes = { 69 | dispatch: PropTypes.func 70 | } 71 | 72 | LoginByWebView.navigatorStyle = { 73 | navBarBackgroundColor: colors.raspberry, 74 | navBarButtonColor: 'white', 75 | navBarTextColor: 'white', 76 | topBarElevationShadowEnabled: true, 77 | statusBarColor: colors.darkRed, 78 | statusBarTextColorScheme: 'dark' 79 | } 80 | 81 | export default connect()(LoginByWebView) 82 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GitterMobile", 3 | "version": "0.6.0-beta-2", 4 | "description": "Gitter client for mobile devices.", 5 | "author": "Terry Sahaidak (http://sahaidak.com)", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/terrysahaidak/GitterMobile.git" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/terrysahaidak/GitterMobile/issues" 12 | }, 13 | "homepage": "https://github.com/terrysahaidak/GitterMobile#readme", 14 | "private": true, 15 | "scripts": { 16 | "start": "node node_modules/react-native/local-cli/cli.js start", 17 | "test": "jest", 18 | "android:check": "adb devices && adb reverse tcp:8081 tcp:8081", 19 | "android": "node node_modules/react-native/local-cli/cli.js run-android", 20 | "lint": "node node_modules/eslint/bin/eslint -c .eslintrc ./", 21 | "release": "cd android && ./gradlew assembleRelease", 22 | "android-release": "node node_modules/react-native/local-cli/cli.js run-android --variant=release" 23 | }, 24 | "dependencies": { 25 | "lodash": "^4.2.1", 26 | "moment": "^2.11.2", 27 | "prop-types": "^15.5.10", 28 | "react": "16.0.0-alpha.6", 29 | "react-native": "^0.44.3", 30 | "react-native-device-info": "^0.10.2", 31 | "react-native-dialogs": "0.0.19", 32 | "react-native-drawer-layout": "^1.3.0", 33 | "react-native-fetch-blob": "^0.10.6", 34 | "react-native-invertible-scroll-view": "^1.0.0", 35 | "react-native-navigation": "^1.1.125", 36 | "react-native-parsed-text": "0.0.16", 37 | "react-native-scrollable-tab-view": "^0.6.7", 38 | "react-native-share": "^1.0.16", 39 | "react-native-transformable-image": "github:terrysahaidak/react-native-transformable-image", 40 | "react-native-vector-icons": "^4.0.1", 41 | "react-redux": "^5.0.3", 42 | "redux": "^3.2.1", 43 | "redux-logger": "^3.0.1", 44 | "redux-thunk": "^1.0.3", 45 | "remote-redux-devtools": "^0.1.1" 46 | }, 47 | "devDependencies": { 48 | "babel-jest": "19.0.0", 49 | "babel-preset-react-native": "1.9.1", 50 | "jest": "19.0.2", 51 | "react-test-renderer": "16.0.0-alpha.6", 52 | "eslint": "~1.10.3", 53 | "eslint-config-airbnb": "~2.1.1", 54 | "eslint-plugin-react": "~3.13.1", 55 | "babel-eslint": "~4.1.6" 56 | }, 57 | "jest": { 58 | "preset": "react-native" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ios/gittermobileTests/gittermobileTests.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 14 | #import 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface GitterMobileTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation GitterMobileTests 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 = [[[RCTSharedApplication() 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/components/ScrollToTop/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Component } from 'react' 3 | import { 4 | TouchableOpacity, 5 | Animated 6 | } from 'react-native' 7 | import s from './styles' 8 | import Icon from 'react-native-vector-icons/MaterialIcons' 9 | 10 | class ScrollToTop extends Component { 11 | constructor(props) { 12 | super(props) 13 | 14 | this.state = { 15 | bottom: new Animated.Value(-54) 16 | } 17 | } 18 | 19 | componentWillReceiveProps(nextProps) { 20 | if (this.props.visible !== nextProps.visible) { 21 | Animated.timing( 22 | this.state.bottom, 23 | { 24 | toValue: nextProps.visible ? 0 : -54, 25 | duration: 200 26 | }, 27 | ).start() 28 | } 29 | } 30 | 31 | _onPress() { 32 | this.props.root.refs.listview.scrollTo({x: 0, y: 0, animated: true}); 33 | } 34 | 35 | render() { 36 | const { 37 | isRadius, 38 | borderRadius, 39 | backgroundColor, 40 | width, 41 | height, 42 | right, 43 | bottom, 44 | icon, 45 | iconSize 46 | } = this.props 47 | 48 | return ( 49 | 51 | 61 | 65 | 66 | 67 | ); 68 | } 69 | } 70 | 71 | ScrollToTop.defaultProps = { 72 | isRadius: true, 73 | width: 60, 74 | height: 60, 75 | borderRadius: 30, 76 | backgroundColor: 'white' 77 | } 78 | 79 | ScrollToTop.propTypes = { 80 | isRadius: PropTypes.bool, 81 | borderRadius: PropTypes.number, 82 | backgroundColor: PropTypes.string, 83 | width: PropTypes.number, 84 | height: PropTypes.number, 85 | right: PropTypes.number, 86 | children: PropTypes.element, 87 | root: PropTypes.object, 88 | bottom: PropTypes.number, 89 | icon: PropTypes.string, 90 | iconSize: PropTypes.number, 91 | visible: PropTypes.bool 92 | } 93 | 94 | export default ScrollToTop 95 | -------------------------------------------------------------------------------- /app/screens/Message/Message/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React, { Component } from 'react' 3 | import {TouchableOpacity, Linking, View, Text} from 'react-native'; 4 | import s from './styles' 5 | import moment from 'moment' 6 | import ParsedText from '../../../components/ParsedText' 7 | 8 | import Avatar from '../../../components/Avatar' 9 | 10 | class Message extends Component { 11 | constructor(props) { 12 | super(props) 13 | 14 | this.renderMessageText = this.renderMessageText.bind(this) 15 | this.renderDate = this.renderDate.bind(this) 16 | } 17 | 18 | handleUrlPress(url) { 19 | Linking.openURL(url) 20 | } 21 | 22 | renderDate() { 23 | const {sent} = this.props 24 | return moment(sent).format('YYYY MMM D HH:mm') 25 | } 26 | 27 | renderMessageText() { 28 | const {text, username} = this.props 29 | 30 | if (this.props.hasOwnProperty('editedAt') && !text) { 31 | return ( 32 | 33 | This message was deleted 34 | 35 | ) 36 | } 37 | return ( 38 | 42 | ) 43 | } 44 | 45 | render() { 46 | const {fromUser, onAvatarPress} = this.props 47 | 48 | return ( 49 | 50 | onAvatarPress(fromUser.id, fromUser.username)}> 52 | 53 | 54 | 55 | 56 | 58 | {fromUser.username} 59 | 60 | 61 | {this.renderDate()} 62 | 63 | 64 | 65 | {this.renderMessageText()} 66 | 67 | 68 | 69 | ) 70 | } 71 | } 72 | 73 | Message.propTypes = { 74 | id: PropTypes.string, 75 | text: PropTypes.string, 76 | sent: PropTypes.string, 77 | fromUser: PropTypes.object, 78 | dispatch: PropTypes.func, 79 | onAvatarPress: PropTypes.func, 80 | username: PropTypes.string, 81 | status: PropTypes.bool 82 | } 83 | 84 | export default Message 85 | -------------------------------------------------------------------------------- /app/screens/RoomInfo/RoomUsers/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import React from 'react' 3 | import {View, Text, TouchableOpacity} from 'react-native'; 4 | import s from './styles' 5 | 6 | import Avatar from '../../../components/Avatar' 7 | import Heading from '../../../components/Heading' 8 | import Button from '../../../components/Button' 9 | 10 | const RoomUsers = ({ids, entities, onPress, userCount, onAllUsersPress, onAddPress, oneToOne}) => { 11 | const displayUserHeader = oneToOne === true ? 'People' : `People (${userCount})` 12 | let content = [] 13 | 14 | if (ids.length >= 30) { 15 | for (let i = 0; i < 30; i++) { 16 | const id = ids[i] 17 | content.push( 18 | onPress(id, entities[id].username)} 20 | key={id}> 21 | 24 | 27 | 28 | 29 | ) 30 | } 31 | } else { 32 | content = ids.map(id => ( 33 | onPress(id, entities[id].username)} 35 | key={id}> 36 | 39 | 42 | 43 | 44 | )) 45 | } 46 | return ( 47 | 48 | 50 | 51 | {content} 52 | 53 | {!oneToOne && ( 54 | 55 | 60 | 65 | 66 | )} 67 | 68 | ) 69 | } 70 | 71 | RoomUsers.propTypes = { 72 | ids: PropTypes.array, 73 | entities: PropTypes.object, 74 | onPress: PropTypes.func, 75 | userCount: PropTypes.number, 76 | onAllUsersPress: PropTypes.func, 77 | oneToOne: PropTypes.bool, 78 | onAddPress: PropTypes.func 79 | } 80 | 81 | export default RoomUsers 82 | -------------------------------------------------------------------------------- /app/modules/ui.js: -------------------------------------------------------------------------------- 1 | import {getItem, setItem, removeItem} from '../utils/storage' 2 | 3 | export const INITIALIZE_UI = 'ui/INITIALIZE_UI' 4 | export const CHANGE_ROOM_INFO_DRAWER_STATE = 'ui/RoomInfo/CHANGE_ROOM_INFO_DRAWER_STATE' 5 | export const TOGGLE_DRAWER_SECTION_STATE = 'ui/TOGGLE_DRAWER_SECTION_STATE' 6 | export const SET_ROOM_INPUT_STATE = 'ui/SET_ROOM_INPUT_STATE' 7 | 8 | export function initializeUi() { 9 | return async dispatch => { 10 | const payload = await getItem('uiReducer') 11 | 12 | dispatch({ 13 | type: INITIALIZE_UI, 14 | payload: typeof payload === 'string' 15 | ? JSON.parse(payload) 16 | : payload 17 | }) 18 | } 19 | } 20 | 21 | export function toggleDrawerSectionState(sectionName, oldState) { 22 | return async dispatch => { 23 | dispatch({type: TOGGLE_DRAWER_SECTION_STATE, sectionName, newState: !oldState}) 24 | 25 | await dispatch(saveReducerToStorage()) 26 | } 27 | } 28 | 29 | export function setRoomTextInputState(roomId, text) { 30 | return async dispatch => { 31 | dispatch({type: SET_ROOM_INPUT_STATE, roomId, text}) 32 | 33 | await dispatch(saveReducerToStorage()) 34 | } 35 | } 36 | 37 | export function changeRoomInfoDrawerState(state) { 38 | return { 39 | type: CHANGE_ROOM_INFO_DRAWER_STATE, 40 | state 41 | } 42 | } 43 | 44 | function saveReducerToStorage() { 45 | return async (dispatch, getState) => { 46 | await setItem('uiReducer', JSON.stringify(getState().ui)) 47 | } 48 | } 49 | 50 | const initialState = { 51 | roomInfoDrawerState: 'close', 52 | sectionsState: { 53 | Favorites: false, 54 | Unread: false, 55 | Channels: false, 56 | Organizations: false 57 | }, 58 | roomInputStateById: {} 59 | } 60 | 61 | export default function ui(state = initialState, action) { 62 | switch (action.type) { 63 | 64 | case INITIALIZE_UI: 65 | return Object.assign({}, state, action.payload || initialState) 66 | 67 | case CHANGE_ROOM_INFO_DRAWER_STATE: 68 | return {...state, 69 | roomInfoDrawerState: action.state 70 | } 71 | 72 | case TOGGLE_DRAWER_SECTION_STATE: 73 | return {...state, 74 | sectionsState: {...state.sectionsState, 75 | [action.sectionName]: action.newState 76 | } 77 | } 78 | 79 | case SET_ROOM_INPUT_STATE: 80 | return {...state, 81 | roomInputStateById: {...state.roomInputStateById, 82 | [action.roomId]: action.text 83 | } 84 | } 85 | 86 | default: 87 | return state 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/gittermobile/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.gittermobile; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import com.RNFetchBlob.RNFetchBlobPackage; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.shell.MainReactPackage; 10 | import com.facebook.soloader.SoLoader; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | import com.oblador.vectoricons.VectorIconsPackage; 16 | import com.terrysahaidak.faye.FayeGitterPackage; 17 | import com.aakashns.reactnativedialogs.ReactNativeDialogsPackage; 18 | import com.terrysahaidak.bottomsheet.AndroidBottomSheetPackage; 19 | import com.learnium.RNDeviceInfo.RNDeviceInfo; 20 | import cl.json.RNSharePackage; 21 | import com.reactnativenavigation.NavigationApplication; 22 | 23 | // public class MainApplication extends Application implements ReactApplication { 24 | // 25 | // private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 26 | // @Override 27 | // public boolean getUseDeveloperSupport() { 28 | // return BuildConfig.DEBUG; 29 | // } 30 | // 31 | // @Override 32 | // protected List getPackages() { 33 | // return Arrays.asList( 34 | // new MainReactPackage(), 35 | // new RNSharePackage(), 36 | // new VectorIconsPackage(), 37 | // new ReactNativeDialogsPackage(), 38 | // new FayeGitterPackage(), 39 | // new RNDeviceInfo(), 40 | // new AndroidBottomSheetPackage() 41 | // ); 42 | // } 43 | // }; 44 | // 45 | // @Override 46 | // public ReactNativeHost getReactNativeHost() { 47 | // return mReactNativeHost; 48 | // } 49 | public class MainApplication extends NavigationApplication { 50 | @Override 51 | public boolean isDebug() { 52 | // Make sure you are using BuildConfig from your own application 53 | return BuildConfig.DEBUG; 54 | } 55 | 56 | @Override 57 | public List createAdditionalReactPackages() { 58 | return Arrays.asList( 59 | new RNSharePackage(), 60 | new VectorIconsPackage(), 61 | new ReactNativeDialogsPackage(), 62 | new FayeGitterPackage(), 63 | new RNDeviceInfo(), 64 | new RNFetchBlobPackage(), 65 | new AndroidBottomSheetPackage() 66 | ); 67 | } 68 | 69 | @Override 70 | public void onCreate() { 71 | super.onCreate(); 72 | SoLoader.init(this, /* native exopackage */ false); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/modules/roomInfo.js: -------------------------------------------------------------------------------- 1 | import * as Api from '../api/gitter' 2 | import {subscribeToRoomEvents} from './realtime' 3 | 4 | export const REPO_INFO = 'roomInfo/REPO_INFO' 5 | export const REPO_INFO_OK = 'roomInfo/REPO_INFO_OK' 6 | export const REPO_INFO_ERROR = 'roomInfo/REPO_INFO_ERROR' 7 | export const ROOM_INFO = 'roomInfo/ROOM_INFO' 8 | export const CLEAR_ERROR = 'roomInfo/CLEAR_ERROR' 9 | 10 | export function getRoomInfo(repoName, roomId) { 11 | return async (dispatch, getState) => { 12 | const {token} = getState().auth 13 | const room = getState().rooms.rooms[roomId] 14 | 15 | if (room.githubType !== 'ONETOONE') { 16 | dispatch(subscribeToRoomEvents(roomId)) 17 | } 18 | 19 | if (room.githubType !== 'REPO') { 20 | dispatch({type: ROOM_INFO, payload: room}) 21 | } else { 22 | dispatch({type: REPO_INFO, repoName}) 23 | 24 | try { 25 | const res = await Api.getRepoInfo(token, repoName) 26 | const resText = await res.text() 27 | 28 | if (resText.length > 0) { 29 | const payload = JSON.parse(resText) 30 | dispatch({type: REPO_INFO_OK, payload, repoName}) 31 | } 32 | } catch (error) { 33 | dispatch({type: REPO_INFO_ERROR, error}) 34 | } 35 | } 36 | } 37 | } 38 | 39 | export function clearRoomInfoError() { 40 | return { 41 | type: CLEAR_ERROR 42 | } 43 | } 44 | 45 | const initialState = { 46 | isFetching: false, 47 | ids: [], 48 | entities: {}, 49 | isError: false, 50 | error: {} 51 | } 52 | 53 | export default function roomInfo(state = initialState, action) { 54 | switch (action.type) { 55 | case REPO_INFO: 56 | return {...state, 57 | isFetching: true 58 | } 59 | 60 | case REPO_INFO_OK: { 61 | const {payload, repoName} = action 62 | return {...state, 63 | isFetching: false, 64 | ids: state.ids.concat(repoName), 65 | entities: {...state.entities, 66 | [repoName]: payload 67 | } 68 | } 69 | } 70 | 71 | case ROOM_INFO: 72 | return {...state, 73 | isFetching: false, 74 | ids: state.ids.concat(action.payload.name), 75 | entities: {...state.entities, 76 | [action.payload.name]: action.payload 77 | } 78 | } 79 | 80 | case CLEAR_ERROR: 81 | return {...state, 82 | isFetching: false, 83 | isError: false, 84 | error: {} 85 | } 86 | 87 | case REPO_INFO_ERROR: 88 | return {...state, 89 | isFetching: false, 90 | isError: true, 91 | error: action.error 92 | } 93 | 94 | default: 95 | return state 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ios/Pods/MZFayeClient/MZFayeClient/MZFayeMessage.m: -------------------------------------------------------------------------------- 1 | // 2 | // MZFayeMessage.m 3 | // MZFayeClient 4 | // 5 | // Created by Michał Zaborowski on 12.12.2013. 6 | // Copyright (c) 2013 Michał Zaborowski. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "MZFayeMessage.h" 27 | 28 | @implementation MZFayeMessage 29 | 30 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 31 | { 32 | self = [super init]; 33 | if (self) { 34 | [self importFromDictionary:dictionary]; 35 | } 36 | return self; 37 | } 38 | 39 | + (instancetype)messageFromDictionary:(NSDictionary *)dictionary 40 | { 41 | return [[[self class] alloc] initWithDictionary:dictionary]; 42 | } 43 | 44 | - (void)importFromDictionary:(NSDictionary *)dictionary 45 | { 46 | if (dictionary[@"id"] != nil) { 47 | self.Id = dictionary[@"id"]; 48 | } 49 | 50 | if (dictionary[@"timestamp"] != nil) { 51 | self.timestamp = [NSDate dateWithTimeIntervalSince1970:[dictionary[@"timestamp"] timeInterval]]; 52 | } 53 | 54 | NSArray *objectAttributes = @[@"channel", @"clientId", @"successful", @"authSuccessful", @"version", @"minimumVersion", @"supportedConnectionTypes", @"advice", @"error", @"subscription", @"data", @"ext"]; 55 | for (NSString *attribute in objectAttributes) { 56 | if (dictionary[attribute] != nil) { 57 | [self setValue:dictionary[attribute] forKey:attribute]; 58 | } 59 | } 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /app/screens/ImageLightbox/index.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | import PropTypes from 'prop-types' 3 | import {Linking, Image} from 'react-native' 4 | import TransformableImage from 'react-native-transformable-image' 5 | import s from './styles' 6 | import navigationStyles from '../../styles/common/navigationStyles' 7 | import {iconsMap} from '../../utils/iconsMap' 8 | 9 | class ImageLightbox extends Component { 10 | constructor(props) { 11 | super(props) 12 | 13 | this.handleToggleNavbar = this.handleToggleNavbar.bind(this) 14 | 15 | props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this)) 16 | props.navigator.setButtons({ 17 | leftButtons: [{ 18 | title: 'Close', 19 | id: 'close', 20 | icon: iconsMap.closeIcon, 21 | iconColor: 'white', 22 | showAsAction: 'always' 23 | }], 24 | rightButtons: [{ 25 | title: 'Open in Browser', 26 | icon: iconsMap.browser, 27 | id: 'open-in-browser', 28 | iconColor: 'white', 29 | showAsAction: 'always' 30 | }] 31 | }) 32 | 33 | this.state = { 34 | pixels: {}, 35 | showNavBar: true 36 | } 37 | } 38 | 39 | componentWillMount() { 40 | Image.getSize(this.props.url, (width, height) => 41 | this.setState({pixels: {width, height}}) 42 | ) 43 | } 44 | 45 | onNavigatorEvent(event) { 46 | if (event.type === 'NavBarButtonPress') { 47 | if (event.id === 'close') { 48 | this.props.navigator.dismissModal({ 49 | animationType: 'slide-down' 50 | }) 51 | } 52 | if (event.id === 'open-in-browser') { 53 | Linking.openURL(this.props.url) 54 | } 55 | } 56 | } 57 | 58 | handleToggleNavbar() { 59 | const {showNavBar} = this.state 60 | this.props.navigator.toggleNavBar({ 61 | to: showNavBar ? 'hidden' : 'shown', 62 | animated: false 63 | }) 64 | this.setState({showNavBar: !showNavBar}) 65 | } 66 | 67 | render() { 68 | const {url} = this.props 69 | const {pixels} = this.state 70 | 71 | return ( 72 | 80 | ) 81 | } 82 | } 83 | 84 | ImageLightbox.navigatorStyle = { 85 | ...navigationStyles, 86 | drawUnderNavBar: true 87 | } 88 | 89 | ImageLightbox.propTypes = { 90 | navigator: PropTypes.object, 91 | url: PropTypes.string 92 | } 93 | 94 | export default ImageLightbox 95 | -------------------------------------------------------------------------------- /app/screens/index.js: -------------------------------------------------------------------------------- 1 | import {Navigation} from 'react-native-navigation' 2 | import {iconsLoaded} from '../utils/iconsMap' 3 | 4 | import {init} from '../modules/app' 5 | 6 | import Launch from './Launch' 7 | import Login from './Login' 8 | import LoginByToken from './LoginByToken' 9 | import NoInternet from './NoInternet' 10 | import Home from './Home' 11 | import Room from './Room' 12 | import Search from './Search' 13 | import User from './User' 14 | import Drawer from './Drawer' 15 | import RoomUsers from './RoomUsers' 16 | import RoomUserAdd from './RoomUserAdd' 17 | import Message from './Message' 18 | import Settings from './Settings' 19 | import SearchMessages from './SearchMessages' 20 | import RoomInfo from './RoomInfo' 21 | import RoomSettings from './RoomSettings' 22 | import LoginByWebView from './LoginByWebView' 23 | import ImageLightbox from './ImageLightbox' 24 | 25 | export default class Application { 26 | constructor(store, Provider) { 27 | this._store = store 28 | this._provider = Provider 29 | this._iconsLoaded = false 30 | 31 | this._configureScreens(store, Provider) 32 | } 33 | 34 | _configureScreens(store, Provider) { 35 | const screens = { 36 | Launch, 37 | Login, 38 | LoginByToken, 39 | NoInternet, 40 | Home, 41 | Room, 42 | Search, 43 | User, 44 | Drawer, 45 | RoomUsers, 46 | RoomUserAdd, 47 | RoomInfo, 48 | Message, 49 | Settings, 50 | SearchMessages, 51 | RoomSettings, 52 | LoginByWebView, 53 | ImageLightbox 54 | } 55 | 56 | Object.keys(screens).map(key => { 57 | Navigation.registerComponent(`gm.${key}`, () => screens[key], store, Provider) 58 | }) 59 | } 60 | 61 | run() { 62 | this._store.dispatch(init()) 63 | } 64 | 65 | startAppWithScreen(opts) { 66 | if (this._iconsLoaded) { 67 | this.startApp(opts) 68 | } else { 69 | iconsLoaded 70 | .then(() => { 71 | this._iconsLoaded = true 72 | this.startApp(opts) 73 | }).catch(error => { 74 | console.error(error) // eslint-disable-line 75 | }) 76 | } 77 | } 78 | 79 | startApp({screen, passProps, showDrawer = false}) { 80 | const app = { 81 | screen: { 82 | screen, 83 | passProps, 84 | navigatorStyle: { 85 | tabBarHidden: true, 86 | drawUnderTabBar: true, 87 | disabledBackGesture: true 88 | } 89 | } 90 | } 91 | 92 | Navigation.startSingleScreenApp(Object.assign( 93 | app, 94 | showDrawer ? {drawer: {left: {screen: 'gm.Drawer'}}} : {} 95 | )) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/modules/navigation.js: -------------------------------------------------------------------------------- 1 | import {nav} from '../screens' 2 | 3 | const NAVIGATE_TO = 'navigation/NAVIGATE_TO' 4 | const NAVIGATE_BACK = 'navigation/NAVIGATE_BACK' 5 | const NAVIGATE_REPLACE = 'navigation/NAVIGATE_REPLACE' 6 | const NAVIGATE_RESET = 'navigation/NAVIGATE_RESET' 7 | const NAVIGATE_RESET_WITH_STACK = 'navigation/NAVIGATE_RESET_WITH_STACK' 8 | 9 | export function goTo(route) { 10 | return dispatch => { 11 | dispatch({type: NAVIGATE_TO, route}) 12 | nav.push(route) 13 | } 14 | } 15 | 16 | export function goBack() { 17 | return dispatch => { 18 | dispatch({type: NAVIGATE_BACK}) 19 | nav.pop() 20 | } 21 | } 22 | 23 | export function goAndReplace(route) { 24 | return dispatch => { 25 | dispatch({type: NAVIGATE_REPLACE, route}) 26 | nav.replace(route) 27 | } 28 | } 29 | 30 | export function resetTo(route) { 31 | return dispatch => { 32 | dispatch({type: NAVIGATE_RESET, route}) 33 | nav.resetTo(route) 34 | } 35 | } 36 | 37 | export function resetWithStack(stack) { 38 | return dispatch => { 39 | dispatch({type: NAVIGATE_RESET_WITH_STACK, stack}) 40 | nav.immediatelyResetRouteStack(stack) 41 | } 42 | } 43 | 44 | const initialState = { 45 | init: {name: 'launch'}, 46 | current: {}, 47 | prevision: {}, 48 | history: [] 49 | } 50 | 51 | export default function navigation(state = initialState, action) { 52 | switch (action.type) { 53 | case NAVIGATE_TO: 54 | return {...state, 55 | current: action.route, 56 | prevision: state.current, 57 | history: state.history.concat(action.route) 58 | } 59 | 60 | case NAVIGATE_BACK: { 61 | const {history} = state 62 | const newHistory = [].concat(history) 63 | newHistory.pop() 64 | return {...state, 65 | current: state.prevision, 66 | prevision: newHistory.length >= 2 ? newHistory[newHistory.length - 2] : {}, 67 | history: newHistory 68 | } 69 | } 70 | 71 | case NAVIGATE_RESET: 72 | return {...state, 73 | current: action.route, 74 | prevision: {}, 75 | history: [].concat(action.route) 76 | } 77 | 78 | case NAVIGATE_REPLACE: { 79 | const newHistory = [].concat(state.history) 80 | newHistory[state.history.length - 1] = action.route 81 | return {...state, 82 | current: action.route, 83 | history: newHistory 84 | } 85 | } 86 | 87 | case NAVIGATE_RESET_WITH_STACK: 88 | return {...state, 89 | current: action.stack[action.stack.length - 1], 90 | prevision: action.stack.length === 1 ? {} : action.stack[action.stack.length - 2], 91 | history: action.stack 92 | } 93 | 94 | default: 95 | return state 96 | } 97 | } 98 | --------------------------------------------------------------------------------